aboutsummaryrefslogtreecommitdiffstats
path: root/hierarchyviewer2
diff options
context:
space:
mode:
authorKonstantin Lopyrev <klopyrev@google.com>2010-08-18 22:08:09 -0700
committerKonstantin Lopyrev <klopyrev@google.com>2010-08-27 09:09:02 -0700
commit97b0639645d9c387cdd9884272e053c467a240da (patch)
tree7c952e2b4b5287d866832f9ce95a9e3aaf2bea89 /hierarchyviewer2
parent70a830d8ab396328ab984c75f923400af6a52e55 (diff)
downloadsdk-97b0639645d9c387cdd9884272e053c467a240da.zip
sdk-97b0639645d9c387cdd9884272e053c467a240da.tar.gz
sdk-97b0639645d9c387cdd9884272e053c467a240da.tar.bz2
Creating the application
Change-Id: I8f2fce7328cc1d93caed1cf003f04e41204f864c
Diffstat (limited to 'hierarchyviewer2')
-rw-r--r--hierarchyviewer2/app/src/Android.mk2
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/AboutDialog.java72
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java1192
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplicationDirector.java13
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/UIThread.java66
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/AboutAction.java63
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/CapturePSDAction.java62
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/DisplayViewAction.java62
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ImageAction.java27
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InspectScreenshotAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InvalidateAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadAllViewsAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadOverlayAction.java62
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadViewHierarchyAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/PixelPerfectAutoRefreshAction.java59
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/QuitAction.java44
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectTreeAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshViewAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshWindowsAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RequestLayoutAction.java58
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SavePixelPerfectAction.java62
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SaveTreeViewAction.java62
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ShowOverlayAction.java59
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/util/ActionButton.java75
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java69
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java407
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java125
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceConnection.java10
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java128
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/DeviceSelectionModel.java45
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java77
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java19
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/CaptureDisplay.java17
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DeviceSelector.java34
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/LayoutViewer.java85
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfect.java61
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectLoupe.java62
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectPixelPanel.java190
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectTree.java7
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/ProfileViewer.java188
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java62
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeView.java201
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeViewOverview.java53
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/DrawableViewNode.java10
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/PsdFile.java508
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/TreeColumnResizer.java3
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about-small.jpgbin0 -> 467 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpgbin0 -> 27144 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.pngbin0 -> 541 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.pngbin0 -> 339 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.pngbin0 -> 254 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.pngbin0 -> 228 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.pngbin0 -> 946 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.pngbin0 -> 9242 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.pngbin219 -> 302 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.pngbin0 -> 412 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.pngbin0 -> 391 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.pngbin0 -> 728 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.pngbin0 -> 549 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.pngbin0 -> 288 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.pngbin0 -> 12468 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.pngbin0 -> 157 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.pngbin0 -> 158 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.pngbin0 -> 734 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.pngbin0 -> 733 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.pngbin220 -> 383 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.pngbin0 -> 872 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.pngbin0 -> 223 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.pngbin0 -> 360 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.pngbin0 -> 5182 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.pngbin0 -> 9015 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.pngbin0 -> 12611 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.pngbin0 -> 12159 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.pngbin0 -> 958 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.pngbin0 -> 276 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.pngbin0 -> 281 bytes
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.pngbin221 -> 255 bytes
78 files changed, 4263 insertions, 602 deletions
diff --git a/hierarchyviewer2/app/src/Android.mk b/hierarchyviewer2/app/src/Android.mk
index 0a25ae7..1f15bee 100644
--- a/hierarchyviewer2/app/src/Android.mk
+++ b/hierarchyviewer2/app/src/Android.mk
@@ -23,6 +23,8 @@ LOCAL_JAVA_LIBRARIES := \
ddmuilib \
hierarchyviewerlib \
swt \
+ org.eclipse.jface_3.4.2.M20090107-0800 \
+ org.eclipse.core.commands_3.4.0.I20080509-2000 \
sdklib
LOCAL_MODULE := hierarchyviewer2
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/AboutDialog.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/AboutDialog.java
new file mode 100644
index 0000000..54edbc8
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/AboutDialog.java
@@ -0,0 +1,72 @@
+/*
+ * 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.hierarchyviewer;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+public class AboutDialog extends Dialog {
+ private Image aboutImage;
+
+ private Image smallImage;
+
+ public AboutDialog(Shell shell) {
+ super(shell);
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ smallImage = imageLoader.loadImage("load-view-hierarchy.png", Display.getDefault());
+ aboutImage = imageLoader.loadImage("about.jpg", Display.getDefault());
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite control = new Composite(parent, SWT.NONE);
+ control.setLayout(new GridLayout(2, true));
+ Composite imageControl = new Composite(control, SWT.BORDER);
+ imageControl.setLayout(new FillLayout());
+ imageControl.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+ Label imageLabel = new Label(imageControl, SWT.CENTER);
+ imageLabel.setImage(aboutImage);
+
+ CLabel textLabel = new CLabel(control, SWT.NONE);
+ textLabel
+ .setText("Hierarchy Viewer\nCopyright 2010, The Android Open Source Project\nAll Rights Reserved.");
+ textLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, true));
+ getShell().setText("About...");
+ getShell().setImage(smallImage);
+ return control;
+
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java
index c3538dc..c967d6b 100644
--- a/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java
@@ -16,27 +16,1201 @@
package com.android.hierarchyviewer;
-import com.android.hierarchyviewerlib.ComponentRegistry;
+import com.android.ddmlib.IDevice;
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewer.actions.AboutAction;
+import com.android.hierarchyviewer.actions.CapturePSDAction;
+import com.android.hierarchyviewer.actions.DisplayViewAction;
+import com.android.hierarchyviewer.actions.InspectScreenshotAction;
+import com.android.hierarchyviewer.actions.InvalidateAction;
+import com.android.hierarchyviewer.actions.LoadAllViewsAction;
+import com.android.hierarchyviewer.actions.LoadOverlayAction;
+import com.android.hierarchyviewer.actions.LoadViewHierarchyAction;
+import com.android.hierarchyviewer.actions.PixelPerfectAutoRefreshAction;
+import com.android.hierarchyviewer.actions.QuitAction;
+import com.android.hierarchyviewer.actions.RefreshPixelPerfectAction;
+import com.android.hierarchyviewer.actions.RefreshPixelPerfectTreeAction;
+import com.android.hierarchyviewer.actions.RefreshViewAction;
+import com.android.hierarchyviewer.actions.RefreshWindowsAction;
+import com.android.hierarchyviewer.actions.RequestLayoutAction;
+import com.android.hierarchyviewer.actions.SavePixelPerfectAction;
+import com.android.hierarchyviewer.actions.SaveTreeViewAction;
+import com.android.hierarchyviewer.actions.ShowOverlayAction;
+import com.android.hierarchyviewer.util.ActionButton;
import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+import com.android.hierarchyviewerlib.device.Window;
import com.android.hierarchyviewerlib.models.DeviceSelectionModel;
import com.android.hierarchyviewerlib.models.PixelPerfectModel;
import com.android.hierarchyviewerlib.models.TreeViewModel;
+import com.android.hierarchyviewerlib.models.DeviceSelectionModel.WindowChangeListener;
+import com.android.hierarchyviewerlib.models.PixelPerfectModel.ImageChangeListener;
+import com.android.hierarchyviewerlib.models.TreeViewModel.TreeChangeListener;
+import com.android.hierarchyviewerlib.ui.DeviceSelector;
+import com.android.hierarchyviewerlib.ui.LayoutViewer;
+import com.android.hierarchyviewerlib.ui.PixelPerfect;
+import com.android.hierarchyviewerlib.ui.PixelPerfectLoupe;
+import com.android.hierarchyviewerlib.ui.PixelPerfectPixelPanel;
+import com.android.hierarchyviewerlib.ui.PixelPerfectTree;
+import com.android.hierarchyviewerlib.ui.PropertyViewer;
+import com.android.hierarchyviewerlib.ui.TreeView;
+import com.android.hierarchyviewerlib.ui.TreeViewOverview;
-public class HierarchyViewerApplication {
- public static void main(String[] args) {
- HierarchyViewerDirector director = new HierarchyViewerApplicationDirector();
- ComponentRegistry.setDirector(director);
- ComponentRegistry.setDeviceSelectionModel(new DeviceSelectionModel());
- ComponentRegistry.setPixelPerfectModel(new PixelPerfectModel());
- ComponentRegistry.setTreeViewModel(new TreeViewModel());
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.window.ApplicationWindow;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Slider;
+import org.eclipse.swt.widgets.Text;
+
+public class HierarchyViewerApplication extends ApplicationWindow {
+
+ private static final int INITIAL_WIDTH = 1024;
+
+ private static final int INITIAL_HEIGHT = 768;
+
+ private static HierarchyViewerApplication APP;
+
+ private Image deviceViewImage;
+
+ private Image pixelPerfectImage;
+
+ private Image treeViewImage;
+
+ private Image deviceViewSelectedImage;
+
+ private Image pixelPerfectSelectedImage;
+
+ private Image treeViewSelectedImage;
+
+ private Button treeViewButton;
+
+ private Button pixelPerfectButton;
+
+ private Button deviceViewButton;
+
+ private Label progressLabel;
+
+ private ProgressBar progressBar;
+
+ private String progressString;
+
+ private Composite deviceSelectorPanel;
+
+ private Composite treeViewPanel;
+
+ private Composite pixelPerfectPanel;
+
+ private StackLayout mainWindowStackLayout;
+
+ private DeviceSelector deviceSelector;
+
+ private Composite statusBar;
+
+ private TreeView treeView;
+
+ private Composite mainWindow;
+
+ private Image onBlackImage;
+
+ private Image onWhiteImage;
+
+ private Button onBlackWhiteButton;
+
+ private Button showExtras;
+
+ private LayoutViewer layoutViewer;
+
+ private StackLayout statusBarStackLayout;
+
+ private Composite treeViewControls;
+
+ private Slider zoomSlider;
+
+ private Text filterText;
+
+ private Composite statusBarControlPanel;
+
+ private PixelPerfectLoupe pixelPerfectLoupe;
+
+ private boolean autoRefresh = false;
+
+ private int refreshInterval = 5;
+
+ private int refreshTimeLeft = 5;
+
+ private Slider overlaySlider;
+
+ private Slider ppZoomSlider;
+
+ private Slider refreshSlider;
+
+ public static final HierarchyViewerApplication getApp() {
+ return APP;
+ }
+
+ public HierarchyViewerApplication() {
+ super(null);
+
+ APP = this;
+
+ addMenuBar();
+ }
+
+ @Override
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText("Hierarchy Viewer");
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ Image image = imageLoader.loadImage("load-view-hierarchy.png", Display.getDefault());
+ shell.setImage(image);
+ }
+
+ @Override
+ public MenuManager createMenuManager() {
+ return new MenuManager();
+ }
+
+ public void run() {
+ HierarchyViewerDirector director = HierarchyViewerApplicationDirector.createDirector();
director.initDebugBridge();
director.startListenForDevices();
director.populateDeviceSelectionModel();
+ DeviceSelectionModel.getModel().addWindowChangeListener(windowChangeListener);
+ TreeViewModel.getModel().addTreeChangeListener(treeChangeListener);
+ PixelPerfectModel.getModel().addImageChangeListener(imageChangeListener);
+
+ setBlockOnOpen(true);
+
+ Thread pixelPerfectRefreshingThread = new Thread(autoRefresher);
+ pixelPerfectRefreshingThread.start();
- UIThread.runUI();
+ open();
+
+ pixelPerfectRefreshingThread.interrupt();
+
+ DeviceSelectionModel.getModel().removeWindowChangeListener(windowChangeListener);
+ TreeViewModel.getModel().removeTreeChangeListener(treeChangeListener);
+ PixelPerfectModel.getModel().removeImageChangeListener(imageChangeListener);
+
+ Display.getCurrent().dispose();
+ ImageLoader.dispose();
director.stopListenForDevices();
director.stopDebugBridge();
director.terminate();
+ }
+
+ @Override
+ protected void initializeBounds() {
+ Rectangle monitorArea = Display.getDefault().getPrimaryMonitor().getBounds();
+ getShell().setSize(Math.min(monitorArea.width, INITIAL_WIDTH),
+ Math.min(monitorArea.height, INITIAL_HEIGHT));
+ getShell().setLocation(monitorArea.x + (monitorArea.width - INITIAL_WIDTH) / 2,
+ monitorArea.y + (monitorArea.height - INITIAL_HEIGHT) / 2);
+ }
+
+ private void loadResources() {
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ treeViewImage = imageLoader.loadImage("tree-view.png", Display.getDefault());
+ treeViewSelectedImage =
+ imageLoader.loadImage("tree-view-selected.png", Display.getDefault());
+ pixelPerfectImage = imageLoader.loadImage("pixel-perfect-view.png", Display.getDefault());
+ pixelPerfectSelectedImage =
+ imageLoader.loadImage("pixel-perfect-view-selected.png", Display.getDefault());
+ deviceViewImage = imageLoader.loadImage("device-view.png", Display.getDefault());
+ deviceViewSelectedImage =
+ imageLoader.loadImage("device-view-selected.png", Display.getDefault());
+ onBlackImage = imageLoader.loadImage("on-black.png", Display.getDefault());
+ onWhiteImage = imageLoader.loadImage("on-white.png", Display.getDefault());
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ loadResources();
+
+ Composite control = new Composite(parent, SWT.NONE);
+ GridLayout mainLayout = new GridLayout();
+ mainLayout.marginHeight = mainLayout.marginWidth = 0;
+ mainLayout.verticalSpacing = mainLayout.horizontalSpacing = 0;
+ control.setLayout(mainLayout);
+ mainWindow = new Composite(control, SWT.NONE);
+ mainWindow.setLayoutData(new GridData(GridData.FILL_BOTH));
+ mainWindowStackLayout = new StackLayout();
+ mainWindow.setLayout(mainWindowStackLayout);
+
+ buildDeviceSelectorPanel(mainWindow);
+ buildTreeViewPanel(mainWindow);
+ buildPixelPerfectPanel(mainWindow);
+
+ buildStatusBar(control);
+
+ showDeviceSelector();
+
+ return control;
+ }
+
+ private void buildStatusBar(Composite parent) {
+ statusBar = new Composite(parent, SWT.NONE);
+ statusBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ FormLayout statusBarLayout = new FormLayout();
+ statusBarLayout.marginHeight = statusBarLayout.marginWidth = 2;
+
+ statusBar.setLayout(statusBarLayout);
+
+ deviceViewButton = new Button(statusBar, SWT.TOGGLE);
+ deviceViewButton.setImage(deviceViewImage);
+ deviceViewButton.setToolTipText("Switch to the window selection view");
+ deviceViewButton.addSelectionListener(deviceViewButtonSelectionListener);
+ FormData deviceViewButtonFormData = new FormData();
+ deviceViewButtonFormData.left = new FormAttachment();
+ deviceViewButton.setLayoutData(deviceViewButtonFormData);
+
+ treeViewButton = new Button(statusBar, SWT.TOGGLE);
+ treeViewButton.setImage(treeViewImage);
+ treeViewButton.setEnabled(false);
+ treeViewButton.setToolTipText("Switch to the tree view");
+ treeViewButton.addSelectionListener(treeViewButtonSelectionListener);
+ FormData treeViewButtonFormData = new FormData();
+ treeViewButtonFormData.left = new FormAttachment(deviceViewButton, 2);
+ treeViewButton.setLayoutData(treeViewButtonFormData);
+
+ pixelPerfectButton = new Button(statusBar, SWT.TOGGLE);
+ pixelPerfectButton.setImage(pixelPerfectImage);
+ pixelPerfectButton.setEnabled(false);
+ pixelPerfectButton.setToolTipText("Switch to the pixel perfect view");
+ pixelPerfectButton.addSelectionListener(pixelPerfectButtonSelectionListener);
+ FormData pixelPerfectButtonFormData = new FormData();
+ pixelPerfectButtonFormData.left = new FormAttachment(treeViewButton, 2);
+ pixelPerfectButton.setLayoutData(pixelPerfectButtonFormData);
+
+ // Control panel should go here.
+ statusBarControlPanel = new Composite(statusBar, SWT.NONE);
+ FormData statusBarControlPanelFormData = new FormData();
+ statusBarControlPanelFormData.left = new FormAttachment(pixelPerfectButton, 2);
+ statusBarControlPanelFormData.top = new FormAttachment(treeViewButton, 0, SWT.CENTER);
+ statusBarControlPanel.setLayoutData(statusBarControlPanelFormData);
+
+ // Label should go on top
+ progressLabel = new Label(statusBar, SWT.RIGHT);
+
+ progressBar = new ProgressBar(statusBar, SWT.HORIZONTAL | SWT.INDETERMINATE | SWT.SMOOTH);
+ FormData progressBarFormData = new FormData();
+ progressBarFormData.right = new FormAttachment(100, 0);
+ progressBarFormData.top = new FormAttachment(treeViewButton, 0, SWT.CENTER);
+ progressBar.setLayoutData(progressBarFormData);
+
+ FormData progressLabelFormData = new FormData();
+ progressLabelFormData.right = new FormAttachment(progressBar, -2);
+ progressLabelFormData.top = new FormAttachment(treeViewButton, 0, SWT.CENTER);
+ progressLabel.setLayoutData(progressLabelFormData);
+
+ if (progressString == null) {
+ progressLabel.setVisible(false);
+ progressBar.setVisible(false);
+ } else {
+ progressLabel.setText(progressString);
+ }
+
+ statusBarStackLayout = new StackLayout();
+ statusBarControlPanel.setLayout(statusBarStackLayout);
+
+ treeViewControls = new Composite(statusBarControlPanel, SWT.NONE);
+ GridLayout treeViewControlLayout = new GridLayout(5, false);
+ treeViewControlLayout.marginWidth = treeViewControlLayout.marginHeight = 2;
+ treeViewControlLayout.verticalSpacing = treeViewControlLayout.horizontalSpacing = 4;
+ treeViewControls.setLayout(treeViewControlLayout);
+
+ Label filterLabel = new Label(treeViewControls, SWT.NONE);
+ filterLabel.setText("Filter by class or id:");
+ filterLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, true));
+
+ filterText = new Text(treeViewControls, SWT.LEFT | SWT.SINGLE);
+ GridData filterTextGridData = new GridData(GridData.FILL_HORIZONTAL);
+ filterTextGridData.widthHint = 148;
+ filterText.setLayoutData(filterTextGridData);
+ filterText.addModifyListener(filterTextModifyListener);
+
+ Label smallZoomLabel = new Label(treeViewControls, SWT.NONE);
+ smallZoomLabel.setText(" 20%");
+ smallZoomLabel
+ .setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, true));
+
+ zoomSlider = new Slider(treeViewControls, SWT.HORIZONTAL);
+ GridData zoomSliderGridData = new GridData(GridData.CENTER, GridData.CENTER, false, false);
+ zoomSliderGridData.widthHint = 190;
+ zoomSlider.setLayoutData(zoomSliderGridData);
+ zoomSlider.setMinimum((int) (TreeViewModel.MIN_ZOOM * 10));
+ zoomSlider.setMaximum((int) (TreeViewModel.MAX_ZOOM * 10 + 1));
+ zoomSlider.setThumb(1);
+ zoomSlider.setSelection(10);
+
+ zoomSlider.addSelectionListener(zoomSliderSelectionListener);
+
+ Label largeZoomLabel = new Label(treeViewControls, SWT.NONE);
+ largeZoomLabel
+ .setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, true));
+ largeZoomLabel.setText("200%");
+ }
+
+ private void buildDeviceSelectorPanel(Composite parent) {
+ deviceSelectorPanel = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ deviceSelectorPanel.setLayout(gridLayout);
+
+ Composite buttonPanel = new Composite(deviceSelectorPanel, SWT.NONE);
+ buttonPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ GridLayout buttonLayout = new GridLayout();
+ buttonLayout.marginWidth = buttonLayout.marginHeight = 0;
+ buttonLayout.horizontalSpacing = buttonLayout.verticalSpacing = 0;
+ buttonPanel.setLayout(buttonLayout);
+
+ Composite innerButtonPanel = new Composite(buttonPanel, SWT.NONE);
+ innerButtonPanel.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+ GridLayout innerButtonPanelLayout = new GridLayout(3, true);
+ innerButtonPanelLayout.marginWidth = innerButtonPanelLayout.marginHeight = 2;
+ innerButtonPanelLayout.horizontalSpacing = innerButtonPanelLayout.verticalSpacing = 2;
+ innerButtonPanel.setLayout(innerButtonPanelLayout);
+
+ ActionButton refreshWindows =
+ new ActionButton(innerButtonPanel, RefreshWindowsAction.getAction());
+ refreshWindows.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton loadViewHierarchyButton =
+ new ActionButton(innerButtonPanel, LoadViewHierarchyAction.getAction());
+ loadViewHierarchyButton.setLayoutData(new GridData(GridData.FILL_BOTH));
+ LoadViewHierarchyAction.getAction().setEnabled(false);
+
+ ActionButton inspectScreenshotButton =
+ new ActionButton(innerButtonPanel, InspectScreenshotAction.getAction());
+ inspectScreenshotButton.setLayoutData(new GridData(GridData.FILL_BOTH));
+ InspectScreenshotAction.getAction().setEnabled(false);
+
+ Composite deviceSelectorContainer = new Composite(deviceSelectorPanel, SWT.BORDER);
+ deviceSelectorContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
+ deviceSelectorContainer.setLayout(new FillLayout());
+ deviceSelector = new DeviceSelector(deviceSelectorContainer);
+ }
+
+ public void buildTreeViewPanel(Composite parent) {
+ treeViewPanel = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ treeViewPanel.setLayout(gridLayout);
+
+ Composite buttonPanel = new Composite(treeViewPanel, SWT.NONE);
+ buttonPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ GridLayout buttonLayout = new GridLayout();
+ buttonLayout.marginWidth = buttonLayout.marginHeight = 0;
+ buttonLayout.horizontalSpacing = buttonLayout.verticalSpacing = 0;
+ buttonPanel.setLayout(buttonLayout);
+
+ Composite innerButtonPanel = new Composite(buttonPanel, SWT.NONE);
+ innerButtonPanel.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+ GridLayout innerButtonPanelLayout = new GridLayout(6, true);
+ innerButtonPanelLayout.marginWidth = innerButtonPanelLayout.marginHeight = 2;
+ innerButtonPanelLayout.horizontalSpacing = innerButtonPanelLayout.verticalSpacing = 2;
+ innerButtonPanel.setLayout(innerButtonPanelLayout);
+
+ ActionButton saveTreeView =
+ new ActionButton(innerButtonPanel, SaveTreeViewAction.getAction(getShell()));
+ saveTreeView.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton capturePSD =
+ new ActionButton(innerButtonPanel, CapturePSDAction.getAction(getShell()));
+ capturePSD.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton refreshViewAction =
+ new ActionButton(innerButtonPanel, RefreshViewAction.getAction());
+ refreshViewAction.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton displayView =
+ new ActionButton(innerButtonPanel, DisplayViewAction.getAction(getShell()));
+ displayView.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton invalidate = new ActionButton(innerButtonPanel, InvalidateAction.getAction());
+ invalidate.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton requestLayout =
+ new ActionButton(innerButtonPanel, RequestLayoutAction.getAction());
+ requestLayout.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ SashForm mainSash = new SashForm(treeViewPanel, SWT.HORIZONTAL | SWT.SMOOTH);
+ mainSash.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Composite treeViewContainer = new Composite(mainSash, SWT.BORDER);
+ treeViewContainer.setLayout(new FillLayout());
+ treeView = new TreeView(treeViewContainer);
+
+ SashForm sideSash = new SashForm(mainSash, SWT.VERTICAL | SWT.SMOOTH);
+
+ mainSash.SASH_WIDTH = 4;
+ mainSash.setWeights(new int[] {
+ 7, 3
+ });
+
+ Composite treeViewOverviewContainer = new Composite(sideSash, SWT.BORDER);
+ treeViewOverviewContainer.setLayout(new FillLayout());
+ TreeViewOverview treeViewOverview = new TreeViewOverview(treeViewOverviewContainer);
+
+ Composite propertyViewerContainer = new Composite(sideSash, SWT.BORDER);
+ propertyViewerContainer.setLayout(new FillLayout());
+ PropertyViewer propertyViewer = new PropertyViewer(propertyViewerContainer);
+
+ Composite layoutViewerContainer = new Composite(sideSash, SWT.NONE);
+ GridLayout layoutViewerLayout = new GridLayout();
+ layoutViewerLayout.marginWidth = layoutViewerLayout.marginHeight = 0;
+ layoutViewerLayout.horizontalSpacing = layoutViewerLayout.verticalSpacing = 1;
+ layoutViewerContainer.setLayout(layoutViewerLayout);
+
+ Composite fullButtonBar = new Composite(layoutViewerContainer, SWT.NONE);
+ fullButtonBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ GridLayout fullButtonBarLayout = new GridLayout(2, false);
+ fullButtonBarLayout.marginWidth = fullButtonBarLayout.marginHeight = 0;
+ fullButtonBarLayout.marginRight = 2;
+ fullButtonBarLayout.horizontalSpacing = fullButtonBarLayout.verticalSpacing = 0;
+ fullButtonBar.setLayout(fullButtonBarLayout);
+
+ Composite buttonBar = new Composite(fullButtonBar, SWT.NONE);
+ buttonBar.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+ RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL);
+ rowLayout.marginLeft =
+ rowLayout.marginRight = rowLayout.marginTop = rowLayout.marginBottom = 0;
+ rowLayout.pack = true;
+ rowLayout.center = true;
+ buttonBar.setLayout(rowLayout);
+
+ onBlackWhiteButton = new Button(buttonBar, SWT.PUSH);
+ onBlackWhiteButton.setImage(onWhiteImage);
+ onBlackWhiteButton.addSelectionListener(onBlackWhiteSelectionListener);
+
+ showExtras = new Button(buttonBar, SWT.CHECK);
+ showExtras.setText("Show Extras");
+ showExtras.addSelectionListener(showExtrasSelectionListener);
+
+ ActionButton loadAllViewsButton =
+ new ActionButton(fullButtonBar, LoadAllViewsAction.getAction());
+ loadAllViewsButton.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, true));
+ loadAllViewsButton.addSelectionListener(loadAllViewsSelectionListener);
+
+ Composite layoutViewerMainContainer = new Composite(layoutViewerContainer, SWT.BORDER);
+ layoutViewerMainContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
+ layoutViewerMainContainer.setLayout(new FillLayout());
+ layoutViewer = new LayoutViewer(layoutViewerMainContainer);
+
+ sideSash.SASH_WIDTH = 4;
+ sideSash.setWeights(new int[] {
+ 238, 332, 416
+ });
+
+ }
+
+ private void buildPixelPerfectPanel(Composite parent) {
+ pixelPerfectPanel = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ pixelPerfectPanel.setLayout(gridLayout);
+
+ Composite buttonPanel = new Composite(pixelPerfectPanel, SWT.NONE);
+ buttonPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ GridLayout buttonLayout = new GridLayout();
+ buttonLayout.marginWidth = buttonLayout.marginHeight = 0;
+ buttonLayout.horizontalSpacing = buttonLayout.verticalSpacing = 0;
+ buttonPanel.setLayout(buttonLayout);
+
+ Composite innerButtonPanel = new Composite(buttonPanel, SWT.NONE);
+ innerButtonPanel.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+ GridLayout innerButtonPanelLayout = new GridLayout(6, true);
+ innerButtonPanelLayout.marginWidth = innerButtonPanelLayout.marginHeight = 2;
+ innerButtonPanelLayout.horizontalSpacing = innerButtonPanelLayout.verticalSpacing = 2;
+ innerButtonPanel.setLayout(innerButtonPanelLayout);
+
+ ActionButton saveTreeView =
+ new ActionButton(innerButtonPanel, SavePixelPerfectAction.getAction(getShell()));
+ saveTreeView.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton refreshPixelPerfect =
+ new ActionButton(innerButtonPanel, RefreshPixelPerfectAction.getAction());
+ refreshPixelPerfect.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton refreshPixelPerfectTree =
+ new ActionButton(innerButtonPanel, RefreshPixelPerfectTreeAction.getAction());
+ refreshPixelPerfectTree.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton loadOverlay =
+ new ActionButton(innerButtonPanel, LoadOverlayAction.getAction(getShell()));
+ loadOverlay.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ActionButton showInLoupe =
+ new ActionButton(innerButtonPanel, ShowOverlayAction.getAction());
+ showInLoupe.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ ShowOverlayAction.getAction().setEnabled(false);
+
+ ActionButton autoRefresh =
+ new ActionButton(innerButtonPanel, PixelPerfectAutoRefreshAction.getAction());
+ autoRefresh.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ SashForm mainSash = new SashForm(pixelPerfectPanel, SWT.HORIZONTAL | SWT.SMOOTH);
+ mainSash.setLayoutData(new GridData(GridData.FILL_BOTH));
+ mainSash.SASH_WIDTH = 4;
+
+ Composite pixelPerfectTreeContainer = new Composite(mainSash, SWT.BORDER);
+ pixelPerfectTreeContainer.setLayout(new FillLayout());
+ PixelPerfectTree pixelPerfectTree = new PixelPerfectTree(pixelPerfectTreeContainer);
+
+ Composite pixelPerfectLoupeContainer = new Composite(mainSash, SWT.NONE);
+ GridLayout loupeLayout = new GridLayout();
+ loupeLayout.marginWidth = loupeLayout.marginHeight = 0;
+ loupeLayout.horizontalSpacing = loupeLayout.verticalSpacing = 0;
+ pixelPerfectLoupeContainer.setLayout(loupeLayout);
+
+ Composite pixelPerfectLoupeBorder = new Composite(pixelPerfectLoupeContainer, SWT.BORDER);
+ pixelPerfectLoupeBorder.setLayoutData(new GridData(GridData.FILL_BOTH));
+ GridLayout pixelPerfectLoupeBorderGridLayout = new GridLayout();
+ pixelPerfectLoupeBorderGridLayout.marginWidth =
+ pixelPerfectLoupeBorderGridLayout.marginHeight = 0;
+ pixelPerfectLoupeBorderGridLayout.horizontalSpacing =
+ pixelPerfectLoupeBorderGridLayout.verticalSpacing = 0;
+ pixelPerfectLoupeBorder.setLayout(pixelPerfectLoupeBorderGridLayout);
+
+ pixelPerfectLoupe = new PixelPerfectLoupe(pixelPerfectLoupeBorder);
+ pixelPerfectLoupe.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ PixelPerfectPixelPanel pixelPerfectPixelPanel =
+ new PixelPerfectPixelPanel(pixelPerfectLoupeBorder);
+ pixelPerfectPixelPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ Composite pixelPerfectControls = new Composite(pixelPerfectLoupeContainer, SWT.NONE);
+ pixelPerfectControls.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ pixelPerfectControls.setLayout(new FormLayout());
+
+ Label overlayTransparencyRight = new Label(pixelPerfectControls, SWT.NONE);
+ overlayTransparencyRight.setText("100%");
+ FormData overlayTransparencyRightData = new FormData();
+ overlayTransparencyRightData.right = new FormAttachment(100, -2);
+ overlayTransparencyRightData.top = new FormAttachment(0, 2);
+ overlayTransparencyRight.setLayoutData(overlayTransparencyRightData);
+
+ Label refreshRight = new Label(pixelPerfectControls, SWT.NONE);
+ refreshRight.setText("40s");
+ FormData refreshRightData = new FormData();
+ refreshRightData.right = new FormAttachment(100, -2);
+ refreshRightData.top = new FormAttachment(overlayTransparencyRight, 2);
+ refreshRightData.left = new FormAttachment(overlayTransparencyRight, 0, SWT.LEFT);
+ refreshRight.setLayoutData(refreshRightData);
+
+ Label zoomRight = new Label(pixelPerfectControls, SWT.NONE);
+ zoomRight.setText("24x");
+ FormData zoomRightData = new FormData();
+ zoomRightData.right = new FormAttachment(100, -2);
+ zoomRightData.top = new FormAttachment(refreshRight, 2);
+ zoomRightData.left = new FormAttachment(overlayTransparencyRight, 0, SWT.LEFT);
+ zoomRight.setLayoutData(zoomRightData);
+
+ Label overlayTransparency = new Label(pixelPerfectControls, SWT.NONE);
+ Label refresh = new Label(pixelPerfectControls, SWT.NONE);
+
+ overlayTransparency.setText("Overlay:");
+ FormData overlayTransparencyData = new FormData();
+ overlayTransparencyData.left = new FormAttachment(0, 2);
+ overlayTransparencyData.top = new FormAttachment(0, 2);
+ overlayTransparencyData.right = new FormAttachment(refresh, 0, SWT.RIGHT);
+ overlayTransparency.setLayoutData(overlayTransparencyData);
+
+ refresh.setText("Refresh Rate:");
+ FormData refreshData = new FormData();
+ refreshData.top = new FormAttachment(overlayTransparency, 2);
+ refreshData.left = new FormAttachment(0, 2);
+ refresh.setLayoutData(refreshData);
+
+ Label zoom = new Label(pixelPerfectControls, SWT.NONE);
+ zoom.setText("Zoom:");
+ FormData zoomData = new FormData();
+ zoomData.right = new FormAttachment(refresh, 0, SWT.RIGHT);
+ zoomData.top = new FormAttachment(refresh, 2);
+ zoomData.left = new FormAttachment(0, 2);
+ zoom.setLayoutData(zoomData);
+
+ Label overlayTransparencyLeft = new Label(pixelPerfectControls, SWT.RIGHT);
+ overlayTransparencyLeft.setText("0%");
+ FormData overlayTransparencyLeftData = new FormData();
+ overlayTransparencyLeftData.top = new FormAttachment(0, 2);
+ overlayTransparencyLeftData.left = new FormAttachment(overlayTransparency, 2);
+ overlayTransparencyLeft.setLayoutData(overlayTransparencyLeftData);
+
+ Label refreshLeft = new Label(pixelPerfectControls, SWT.RIGHT);
+ refreshLeft.setText("1s");
+ FormData refreshLeftData = new FormData();
+ refreshLeftData.top = new FormAttachment(overlayTransparencyLeft, 2);
+ refreshLeftData.left = new FormAttachment(refresh, 2);
+ refreshLeft.setLayoutData(refreshLeftData);
+
+ Label zoomLeft = new Label(pixelPerfectControls, SWT.RIGHT);
+ zoomLeft.setText("2x");
+ FormData zoomLeftData = new FormData();
+ zoomLeftData.top = new FormAttachment(refreshLeft, 2);
+ zoomLeftData.left = new FormAttachment(zoom, 2);
+ zoomLeft.setLayoutData(zoomLeftData);
+
+ overlaySlider = new Slider(pixelPerfectControls, SWT.HORIZONTAL);
+ overlaySlider.setMinimum(0);
+ overlaySlider.setMaximum(101);
+ overlaySlider.setThumb(1);
+ overlaySlider.setSelection(50);
+ overlaySlider.setEnabled(false);
+ FormData overlaySliderData = new FormData();
+ overlaySliderData.right = new FormAttachment(overlayTransparencyRight, -4);
+ overlaySliderData.top = new FormAttachment(0, 2);
+ overlaySliderData.left = new FormAttachment(overlayTransparencyLeft, 4);
+ overlaySlider.setLayoutData(overlaySliderData);
+
+ overlaySlider.addSelectionListener(overlaySliderSelectionListener);
+
+ refreshSlider = new Slider(pixelPerfectControls, SWT.HORIZONTAL);
+ refreshSlider.setMinimum(1);
+ refreshSlider.setMaximum(41);
+ refreshSlider.setThumb(1);
+ refreshSlider.setSelection(refreshInterval);
+ FormData refreshSliderData = new FormData();
+ refreshSliderData.right = new FormAttachment(overlayTransparencyRight, -4);
+ refreshSliderData.top = new FormAttachment(overlayTransparencyRight, 2);
+ refreshSliderData.left = new FormAttachment(overlaySlider, 0, SWT.LEFT);
+ refreshSlider.setLayoutData(refreshSliderData);
+
+ refreshSlider.addSelectionListener(refreshSliderSelectionListener);
+
+ ppZoomSlider = new Slider(pixelPerfectControls, SWT.HORIZONTAL);
+ ppZoomSlider.setMinimum(2);
+ ppZoomSlider.setMaximum(25);
+ ppZoomSlider.setThumb(1);
+ ppZoomSlider.setSelection(PixelPerfectModel.DEFAULT_ZOOM);
+ FormData zoomSliderData = new FormData();
+ zoomSliderData.right = new FormAttachment(overlayTransparencyRight, -4);
+ zoomSliderData.top = new FormAttachment(refreshRight, 2);
+ zoomSliderData.left = new FormAttachment(overlaySlider, 0, SWT.LEFT);
+ ppZoomSlider.setLayoutData(zoomSliderData);
+
+ ppZoomSlider.addSelectionListener(ppZoomSliderSelectionListener);
+
+ Composite pixelPerfectContainer = new Composite(mainSash, SWT.BORDER);
+ pixelPerfectContainer.setLayout(new FillLayout());
+ PixelPerfect pixelPerfect = new PixelPerfect(pixelPerfectContainer);
+
+ mainSash.setWeights(new int[] {
+ 272, 376, 346
+ });
+
+ }
+
+ public void setAutoRefresh(boolean value) {
+ if (value) {
+ refreshTimeLeft = refreshInterval;
+ autoRefresh = true;
+ } else {
+ autoRefresh = false;
+ }
+ }
+
+ public void showOverlayInLoupe(boolean value) {
+ pixelPerfectLoupe.setShowOverlay(value);
+ }
+
+ public void startTask(final String taskName) {
+ progressString = taskName;
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ if (progressLabel != null && progressBar != null) {
+ progressLabel.setText(taskName);
+ progressLabel.setVisible(true);
+ progressBar.setVisible(true);
+ statusBar.layout();
+ }
+ }
+ });
+ }
+
+ public void endTask() {
+ progressString = null;
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ if (progressLabel != null && progressBar != null) {
+ progressLabel.setVisible(false);
+ progressBar.setVisible(false);
+ }
+ }
+ });
+ }
+
+ public void showDeviceSelector() {
+ // Show the menus.
+ MenuManager mm = getMenuBarManager();
+ mm.removeAll();
+
+ MenuManager file = new MenuManager("&File");
+ mm.add(file);
+
+ file.add(QuitAction.getAction());
+
+ MenuManager device = new MenuManager("&Devices");
+ mm.add(device);
+
+ device.add(RefreshWindowsAction.getAction());
+ device.add(LoadViewHierarchyAction.getAction());
+ device.add(InspectScreenshotAction.getAction());
+
+ MenuManager help = new MenuManager("&Help");
+ mm.add(help);
+
+ help.add(AboutAction.getAction(getShell()));
+
+ mm.updateAll(true);
+
+ deviceViewButton.setSelection(true);
+ deviceViewButton.setImage(deviceViewSelectedImage);
+
+ treeViewButton.setSelection(false);
+ treeViewButton.setImage(treeViewImage);
+
+ pixelPerfectButton.setSelection(false);
+ pixelPerfectButton.setImage(pixelPerfectImage);
+
+ mainWindowStackLayout.topControl = deviceSelectorPanel;
+
+ mainWindow.layout();
+
+ deviceSelector.setFocus();
+
+ statusBarStackLayout.topControl = null;
+ statusBarControlPanel.setVisible(false);
+ statusBarControlPanel.layout();
+ }
+
+ public void showTreeView() {
+ // Show the menus.
+ MenuManager mm = getMenuBarManager();
+ mm.removeAll();
+
+ MenuManager file = new MenuManager("&File");
+ mm.add(file);
+
+ file.add(QuitAction.getAction());
+
+ MenuManager treeViewMenu = new MenuManager("&Tree View");
+ mm.add(treeViewMenu);
+
+ treeViewMenu.add(SaveTreeViewAction.getAction(getShell()));
+ treeViewMenu.add(CapturePSDAction.getAction(getShell()));
+ treeViewMenu.add(new Separator());
+ treeViewMenu.add(RefreshViewAction.getAction());
+ treeViewMenu.add(DisplayViewAction.getAction(getShell()));
+ treeViewMenu.add(new Separator());
+ treeViewMenu.add(InvalidateAction.getAction());
+ treeViewMenu.add(RequestLayoutAction.getAction());
+
+ MenuManager help = new MenuManager("&Help");
+ mm.add(help);
+
+ help.add(AboutAction.getAction(getShell()));
+
+ mm.updateAll(true);
+
+ deviceViewButton.setSelection(false);
+ deviceViewButton.setImage(deviceViewImage);
+
+ treeViewButton.setSelection(true);
+ treeViewButton.setImage(treeViewSelectedImage);
+
+ pixelPerfectButton.setSelection(false);
+ pixelPerfectButton.setImage(pixelPerfectImage);
+
+ mainWindowStackLayout.topControl = treeViewPanel;
+
+ mainWindow.layout();
+
+ treeView.setFocus();
+
+ statusBarStackLayout.topControl = treeViewControls;
+ statusBarControlPanel.setVisible(true);
+ statusBarControlPanel.layout();
+ }
+
+ public void showPixelPerfect() {
+ // Show the menus.
+ MenuManager mm = getMenuBarManager();
+ mm.removeAll();
+
+ MenuManager file = new MenuManager("&File");
+ mm.add(file);
+
+ file.add(QuitAction.getAction());
+
+ MenuManager pixelPerfect = new MenuManager("&Pixel Perfect");
+ pixelPerfect.add(SavePixelPerfectAction.getAction(getShell()));
+ pixelPerfect.add(RefreshPixelPerfectAction.getAction());
+ pixelPerfect.add(RefreshPixelPerfectTreeAction.getAction());
+ pixelPerfect.add(PixelPerfectAutoRefreshAction.getAction());
+ pixelPerfect.add(new Separator());
+ pixelPerfect.add(LoadOverlayAction.getAction(getShell()));
+ pixelPerfect.add(ShowOverlayAction.getAction());
+
+ mm.add(pixelPerfect);
+
+ MenuManager help = new MenuManager("&Help");
+ mm.add(help);
+
+ help.add(AboutAction.getAction(getShell()));
+
+ mm.updateAll(true);
+
+ deviceViewButton.setSelection(false);
+ deviceViewButton.setImage(deviceViewImage);
+
+ treeViewButton.setSelection(false);
+ treeViewButton.setImage(treeViewImage);
+
+ pixelPerfectButton.setSelection(true);
+ pixelPerfectButton.setImage(pixelPerfectSelectedImage);
+
+ mainWindowStackLayout.topControl = pixelPerfectPanel;
+
+ mainWindow.layout();
+
+ pixelPerfectLoupe.setFocus();
+
+ statusBarStackLayout.topControl = null;
+ statusBarControlPanel.setVisible(false);
+ statusBarControlPanel.layout();
+ }
+
+ private SelectionListener deviceViewButtonSelectionListener = new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ deviceViewButton.setSelection(true);
+ showDeviceSelector();
+ }
+ };
+
+ private SelectionListener treeViewButtonSelectionListener = new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ treeViewButton.setSelection(true);
+ showTreeView();
+ }
+ };
+
+ private SelectionListener pixelPerfectButtonSelectionListener = new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ pixelPerfectButton.setSelection(true);
+ showPixelPerfect();
+ }
+ };
+
+ private SelectionListener onBlackWhiteSelectionListener = new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ if (layoutViewer.getOnBlack()) {
+ layoutViewer.setOnBlack(false);
+ onBlackWhiteButton.setImage(onBlackImage);
+ } else {
+ layoutViewer.setOnBlack(true);
+ onBlackWhiteButton.setImage(onWhiteImage);
+ }
+ }
+ };
+
+ private SelectionListener showExtrasSelectionListener = new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ layoutViewer.setShowExtras(showExtras.getSelection());
+ }
+ };
+
+ private SelectionListener loadAllViewsSelectionListener = new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ showExtras.setSelection(true);
+ showExtrasSelectionListener.widgetSelected(null);
+ }
+ };
+
+ private SelectionListener zoomSliderSelectionListener = new SelectionListener() {
+ private int oldValue;
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ int newValue = zoomSlider.getSelection();
+ if (oldValue != newValue) {
+ TreeViewModel.getModel().removeTreeChangeListener(treeChangeListener);
+ TreeViewModel.getModel().setZoom(newValue / 10.0);
+ TreeViewModel.getModel().addTreeChangeListener(treeChangeListener);
+ oldValue = newValue;
+ }
+ }
+ };
+
+ private Runnable autoRefresher = new Runnable() {
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ break;
+ }
+ refreshTimeLeft--;
+ if (autoRefresh && refreshTimeLeft <= 0) {
+ HierarchyViewerDirector.getDirector().refreshPixelPerfect();
+ refreshTimeLeft = refreshInterval;
+ }
+ }
+ }
+ };
+
+ private SelectionListener overlaySliderSelectionListener = new SelectionListener() {
+ private int oldValue;
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ int newValue = overlaySlider.getSelection();
+ if (oldValue != newValue) {
+ PixelPerfectModel.getModel().removeImageChangeListener(imageChangeListener);
+ PixelPerfectModel.getModel().setOverlayTransparency(newValue / 100.0);
+ PixelPerfectModel.getModel().addImageChangeListener(imageChangeListener);
+ oldValue = newValue;
+ }
+ }
+ };
+
+ private SelectionListener refreshSliderSelectionListener = new SelectionListener() {
+ private int oldValue;
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ int newValue = refreshSlider.getSelection();
+ if (oldValue != newValue) {
+ refreshInterval = newValue;
+ oldValue = newValue;
+ }
+ }
+ };
+
+ private SelectionListener ppZoomSliderSelectionListener = new SelectionListener() {
+ private int oldValue;
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ int newValue = ppZoomSlider.getSelection();
+ if (oldValue != newValue) {
+ PixelPerfectModel.getModel().removeImageChangeListener(imageChangeListener);
+ PixelPerfectModel.getModel().setZoom(newValue);
+ PixelPerfectModel.getModel().addImageChangeListener(imageChangeListener);
+ oldValue = newValue;
+ }
+ }
+ };
+
+ private ModifyListener filterTextModifyListener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ HierarchyViewerDirector.getDirector().filterNodes(filterText.getText());
+ }
+ };
+
+ private WindowChangeListener windowChangeListener = new WindowChangeListener() {
+ public void deviceChanged(IDevice device) {
+ // pass
+ }
+
+ public void deviceConnected(IDevice device) {
+ // pass
+ }
+
+ public void deviceDisconnected(IDevice device) {
+ // pass
+ }
+
+ public void focusChanged(IDevice device) {
+ // pass
+ }
+
+ public void selectionChanged(final IDevice device, final Window window) {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ if (window == null) {
+ LoadViewHierarchyAction.getAction().setEnabled(false);
+ } else {
+ LoadViewHierarchyAction.getAction().setEnabled(true);
+ }
+ if (device == null) {
+ InspectScreenshotAction.getAction().setEnabled(false);
+ } else {
+ InspectScreenshotAction.getAction().setEnabled(true);
+ }
+ }
+ });
+ }
+ };
+
+ private TreeChangeListener treeChangeListener = new TreeChangeListener() {
+ public void selectionChanged() {
+ // pass
+ }
+
+ public void treeChanged() {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ if (TreeViewModel.getModel().getTree() == null) {
+ showDeviceSelector();
+ treeViewButton.setEnabled(false);
+ } else {
+ showTreeView();
+ treeViewButton.setEnabled(true);
+ zoomSlider.setSelection((int) Math
+ .round(TreeViewModel.getModel().getZoom() * 10));
+ filterText.setText("");
+ }
+ }
+ });
+ }
+
+ public void viewportChanged() {
+ // pass
+ }
+
+ public void zoomChanged() {
+ // pass
+ zoomSlider.setSelection((int) Math.round(TreeViewModel.getModel().getZoom() * 10));
+ }
+ };
+
+ private ImageChangeListener imageChangeListener = new ImageChangeListener() {
+
+ public void crosshairMoved() {
+ // pass
+ }
+
+ public void treeChanged() {
+ // pass
+ }
+
+ public void imageChanged() {
+ // pass
+ }
+
+ public void imageLoaded() {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ Image overlayImage = PixelPerfectModel.getModel().getOverlayImage();
+ ShowOverlayAction.getAction().setEnabled(overlayImage != null);
+ overlaySlider.setEnabled(overlayImage != null);
+ if (PixelPerfectModel.getModel().getImage() == null) {
+ pixelPerfectButton.setEnabled(false);
+ showDeviceSelector();
+ } else {
+ ppZoomSlider.setSelection(PixelPerfectModel.getModel().getZoom());
+ pixelPerfectButton.setEnabled(true);
+ showPixelPerfect();
+ }
+ }
+ });
+ }
+
+ public void overlayChanged() {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ Image overlayImage = PixelPerfectModel.getModel().getOverlayImage();
+ ShowOverlayAction.getAction().setEnabled(overlayImage != null);
+ overlaySlider.setEnabled(overlayImage != null);
+ }
+ });
+ }
+
+ public void overlayTransparencyChanged() {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ overlaySlider.setSelection((int) (PixelPerfectModel.getModel()
+ .getOverlayTransparency() * 100));
+ }
+ });
+ }
+
+ public void selectionChanged() {
+ // pass
+ }
+
+ public void zoomChanged() {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ ppZoomSlider.setSelection(PixelPerfectModel.getModel().getZoom());
+ }
+ });
+ }
+
+ };
+
+ public static void main(String[] args) {
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ new HierarchyViewerApplication().run();
+ }
+ });
System.exit(0);
}
}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplicationDirector.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplicationDirector.java
index 8d77410..f26cc2c 100644
--- a/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplicationDirector.java
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplicationDirector.java
@@ -30,6 +30,10 @@ public class HierarchyViewerApplicationDirector extends HierarchyViewerDirector
private final ExecutorService executor = Executors.newSingleThreadExecutor();
+ public static HierarchyViewerDirector createDirector() {
+ return director = new HierarchyViewerApplicationDirector();
+ }
+
@Override
public void terminate() {
super.terminate();
@@ -43,9 +47,6 @@ public class HierarchyViewerApplicationDirector extends HierarchyViewerDirector
@Override
public String getAdbLocation() {
String hvParentLocation = System.getProperty("com.android.hierarchyviewer.bindir");
- // TODO REMOVE THIS.
- hvParentLocation = "/usr/local/google/android-ext/out/host/linux-x86/bin";
- System.out.println(hvParentLocation);
if (hvParentLocation != null && hvParentLocation.length() != 0) {
return hvParentLocation + File.separator + SdkConstants.FN_ADB;
}
@@ -58,12 +59,12 @@ public class HierarchyViewerApplicationDirector extends HierarchyViewerDirector
* progress bar to show that we are doing something in the background.
*/
@Override
- public void executeInBackground(final Runnable task) {
+ public void executeInBackground(final String taskName, final Runnable task) {
executor.execute(new Runnable() {
public void run() {
- System.out.println("STARTING TASK");
+ HierarchyViewerApplication.getApp().startTask(taskName);
task.run();
- System.out.println("ENDING TASK");
+ HierarchyViewerApplication.getApp().endTask();
}
});
}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/UIThread.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/UIThread.java
deleted file mode 100644
index 3da9468..0000000
--- a/hierarchyviewer2/app/src/com/android/hierarchyviewer/UIThread.java
+++ /dev/null
@@ -1,66 +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.hierarchyviewer;
-
-import com.android.ddmuilib.ImageLoader;
-import com.android.hierarchyviewerlib.ComponentRegistry;
-import com.android.hierarchyviewerlib.ui.DeviceSelector;
-import com.android.hierarchyviewerlib.ui.LayoutViewer;
-import com.android.hierarchyviewerlib.ui.PixelPerfect;
-import com.android.hierarchyviewerlib.ui.PixelPerfectLoupe;
-import com.android.hierarchyviewerlib.ui.PixelPerfectTree;
-import com.android.hierarchyviewerlib.ui.ProfileViewer;
-import com.android.hierarchyviewerlib.ui.PropertyViewer;
-import com.android.hierarchyviewerlib.ui.TreeView;
-import com.android.hierarchyviewerlib.ui.TreeViewOverview;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.events.ShellListener;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Slider;
-
-public class UIThread {
- public static void runUI() {
- Display display = new Display();
-
- // CODE BELOW IS FOR TESTING.
- Shell shell = new Shell(display);
- shell.setLayout(new FillLayout());
- DeviceSelector deviceSelector = new DeviceSelector(shell);
- shell.open();
-
- while (!shell.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
-
- // NO LONGER TESTING STUFF.
-
- ImageLoader.dispose();
- display.dispose();
- }
-}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/AboutAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/AboutAction.java
new file mode 100644
index 0000000..9c76ae9
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/AboutAction.java
@@ -0,0 +1,63 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewer.AboutDialog;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class AboutAction extends Action implements ImageAction {
+
+ private static AboutAction action;
+
+ private Image image;
+
+ private Shell shell;
+
+ private AboutAction(Shell shell) {
+ super("&About");
+ this.shell = shell;
+ setAccelerator(SWT.MOD1 + 'A');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("about-small.jpg", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Shows the about dialog");
+ }
+
+ public static AboutAction getAction(Shell shell) {
+ if (action == null) {
+ action = new AboutAction(shell);
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ new AboutDialog(shell).open();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/CapturePSDAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/CapturePSDAction.java
new file mode 100644
index 0000000..6ae0d17
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/CapturePSDAction.java
@@ -0,0 +1,62 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class CapturePSDAction extends Action implements ImageAction {
+
+ private static CapturePSDAction action;
+
+ private Image image;
+
+ private Shell shell;
+
+ private CapturePSDAction(Shell shell) {
+ super("&Capture Layers");
+ this.shell = shell;
+ setAccelerator(SWT.MOD1 + 'C');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("capture-psd.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Capture the window layers as a photoshop document");
+ }
+
+ public static CapturePSDAction getAction(Shell shell) {
+ if (action == null) {
+ action = new CapturePSDAction(shell);
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().capturePSD(shell);
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/DisplayViewAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/DisplayViewAction.java
new file mode 100644
index 0000000..a622eb2
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/DisplayViewAction.java
@@ -0,0 +1,62 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class DisplayViewAction extends Action implements ImageAction {
+
+ private static DisplayViewAction action;
+
+ private Image image;
+
+ private Shell shell;
+
+ private DisplayViewAction(Shell shell) {
+ super("&Display View");
+ this.shell = shell;
+ setAccelerator(SWT.MOD1 + 'D');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("display.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Display the selected view image in a separate window");
+ }
+
+ public static DisplayViewAction getAction(Shell shell) {
+ if (action == null) {
+ action = new DisplayViewAction(shell);
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().showCapture(shell);
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ImageAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ImageAction.java
new file mode 100644
index 0000000..11c98a4
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ImageAction.java
@@ -0,0 +1,27 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import org.eclipse.swt.graphics.Image;
+
+public interface ImageAction {
+ public Image getImage();
+
+ public String getText();
+
+ public String getToolTipText();
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InspectScreenshotAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InspectScreenshotAction.java
new file mode 100644
index 0000000..5109ca5
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InspectScreenshotAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class InspectScreenshotAction extends Action implements ImageAction {
+
+ private static InspectScreenshotAction action;
+
+ private Image image;
+
+ private InspectScreenshotAction() {
+ super("Inspect &Screenshot");
+ setAccelerator(SWT.MOD1 + 'S');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("inspect-screenshot.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Inspect a screenshot in the pixel perfect view");
+ }
+
+ public static InspectScreenshotAction getAction() {
+ if (action == null) {
+ action = new InspectScreenshotAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().inspectScreenshot();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InvalidateAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InvalidateAction.java
new file mode 100644
index 0000000..831a56d
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/InvalidateAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class InvalidateAction extends Action implements ImageAction {
+
+ private static InvalidateAction action;
+
+ private Image image;
+
+ private InvalidateAction() {
+ super("&Invalidate Layout");
+ setAccelerator(SWT.MOD1 + 'I');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("invalidate.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Invalidate the layout for the current window");
+ }
+
+ public static InvalidateAction getAction() {
+ if (action == null) {
+ action = new InvalidateAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().invalidateCurrentNode();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadAllViewsAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadAllViewsAction.java
new file mode 100644
index 0000000..2ea2298
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadAllViewsAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class LoadAllViewsAction extends Action implements ImageAction {
+
+ private static LoadAllViewsAction action;
+
+ private Image image;
+
+ private LoadAllViewsAction() {
+ super("Load All &Views");
+ setAccelerator(SWT.MOD1 + 'V');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("load-all-views.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Load all view images");
+ }
+
+ public static LoadAllViewsAction getAction() {
+ if (action == null) {
+ action = new LoadAllViewsAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().loadAllViews();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadOverlayAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadOverlayAction.java
new file mode 100644
index 0000000..588b995
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadOverlayAction.java
@@ -0,0 +1,62 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class LoadOverlayAction extends Action implements ImageAction {
+
+ private static LoadOverlayAction action;
+
+ private Image image;
+
+ private Shell shell;
+
+ private LoadOverlayAction(Shell shell) {
+ super("Load &Overlay");
+ this.shell = shell;
+ setAccelerator(SWT.MOD1 + 'O');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("load-overlay.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Load an image to overlay the screenshot");
+ }
+
+ public static LoadOverlayAction getAction(Shell shell) {
+ if (action == null) {
+ action = new LoadOverlayAction(shell);
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().loadOverlay(shell);
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadViewHierarchyAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadViewHierarchyAction.java
new file mode 100644
index 0000000..79fd0b3
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/LoadViewHierarchyAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class LoadViewHierarchyAction extends Action implements ImageAction {
+
+ private static LoadViewHierarchyAction action;
+
+ private Image image;
+
+ private LoadViewHierarchyAction() {
+ super("Load View &Hierarchy");
+ setAccelerator(SWT.MOD1 + 'H');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("load-view-hierarchy.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Load the view hierarchy into the tree view");
+ }
+
+ public static LoadViewHierarchyAction getAction() {
+ if (action == null) {
+ action = new LoadViewHierarchyAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().loadViewHierarchy();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/PixelPerfectAutoRefreshAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/PixelPerfectAutoRefreshAction.java
new file mode 100644
index 0000000..325eb86
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/PixelPerfectAutoRefreshAction.java
@@ -0,0 +1,59 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewer.HierarchyViewerApplication;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class PixelPerfectAutoRefreshAction extends Action implements ImageAction {
+
+ private static PixelPerfectAutoRefreshAction action;
+
+ private Image image;
+
+ private PixelPerfectAutoRefreshAction() {
+ super("Auto &Refresh", Action.AS_CHECK_BOX);
+ setAccelerator(SWT.MOD1 + 'R');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("auto-refresh.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Automatically refresh the screenshot");
+ }
+
+ public static PixelPerfectAutoRefreshAction getAction() {
+ if (action == null) {
+ action = new PixelPerfectAutoRefreshAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerApplication.getApp().setAutoRefresh(action.isChecked());
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/QuitAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/QuitAction.java
new file mode 100644
index 0000000..693d55a
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/QuitAction.java
@@ -0,0 +1,44 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.hierarchyviewer.HierarchyViewerApplication;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.SWT;
+
+public class QuitAction extends Action {
+
+ private static QuitAction action;
+
+ private QuitAction() {
+ super("E&xit");
+ setAccelerator(SWT.MOD1 + 'Q');
+ }
+
+ public static QuitAction getAction() {
+ if (action == null) {
+ action = new QuitAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerApplication.getApp().close();
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectAction.java
new file mode 100644
index 0000000..5d68c37
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class RefreshPixelPerfectAction extends Action implements ImageAction {
+
+ private static RefreshPixelPerfectAction action;
+
+ private Image image;
+
+ private RefreshPixelPerfectAction() {
+ super("&Refresh Screenshot");
+ setAccelerator(SWT.F5);
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("refresh-windows.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Refresh the screenshot");
+ }
+
+ public static RefreshPixelPerfectAction getAction() {
+ if (action == null) {
+ action = new RefreshPixelPerfectAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().refreshPixelPerfect();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectTreeAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectTreeAction.java
new file mode 100644
index 0000000..74c577d
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshPixelPerfectTreeAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class RefreshPixelPerfectTreeAction extends Action implements ImageAction {
+
+ private static RefreshPixelPerfectTreeAction action;
+
+ private Image image;
+
+ private RefreshPixelPerfectTreeAction() {
+ super("Refresh &Tree");
+ setAccelerator(SWT.MOD1 + 'T');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("load-view-hierarchy.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Refresh the tree");
+ }
+
+ public static RefreshPixelPerfectTreeAction getAction() {
+ if (action == null) {
+ action = new RefreshPixelPerfectTreeAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().refreshPixelPerfectTree();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshViewAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshViewAction.java
new file mode 100644
index 0000000..36704a7
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshViewAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class RefreshViewAction extends Action implements ImageAction {
+
+ private static RefreshViewAction action;
+
+ private Image image;
+
+ private RefreshViewAction() {
+ super("Load View &Hierarchy");
+ setAccelerator(SWT.MOD1 + 'H');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("load-view-hierarchy.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Reload the view hierarchy");
+ }
+
+ public static RefreshViewAction getAction() {
+ if (action == null) {
+ action = new RefreshViewAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().reloadViewHierarchy();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshWindowsAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshWindowsAction.java
new file mode 100644
index 0000000..63808ee
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RefreshWindowsAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class RefreshWindowsAction extends Action implements ImageAction {
+
+ private static RefreshWindowsAction action;
+
+ private Image image;
+
+ private RefreshWindowsAction() {
+ super("&Refresh");
+ setAccelerator(SWT.F5);
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("refresh-windows.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Refresh the list of devices");
+ }
+
+ public static RefreshWindowsAction getAction() {
+ if (action == null) {
+ action = new RefreshWindowsAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().refreshWindows();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RequestLayoutAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RequestLayoutAction.java
new file mode 100644
index 0000000..9255432
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/RequestLayoutAction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class RequestLayoutAction extends Action implements ImageAction {
+
+ private static RequestLayoutAction action;
+
+ private Image image;
+
+ private RequestLayoutAction() {
+ super("Request &Layout");
+ setAccelerator(SWT.MOD1 + 'L');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("request-layout.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Request the view to lay out");
+ }
+
+ public static RequestLayoutAction getAction() {
+ if (action == null) {
+ action = new RequestLayoutAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().relayoutCurrentNode();
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SavePixelPerfectAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SavePixelPerfectAction.java
new file mode 100644
index 0000000..2221ad8
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SavePixelPerfectAction.java
@@ -0,0 +1,62 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class SavePixelPerfectAction extends Action implements ImageAction {
+
+ private static SavePixelPerfectAction action;
+
+ private Image image;
+
+ private Shell shell;
+
+ private SavePixelPerfectAction(Shell shell) {
+ super("&Save as PNG");
+ this.shell = shell;
+ setAccelerator(SWT.MOD1 + 'S');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("save.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Save the screenshot as a PNG image");
+ }
+
+ public static SavePixelPerfectAction getAction(Shell shell) {
+ if (action == null) {
+ action = new SavePixelPerfectAction(shell);
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().savePixelPerfect(shell);
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SaveTreeViewAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SaveTreeViewAction.java
new file mode 100644
index 0000000..c203ace
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/SaveTreeViewAction.java
@@ -0,0 +1,62 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class SaveTreeViewAction extends Action implements ImageAction {
+
+ private static SaveTreeViewAction action;
+
+ private Image image;
+
+ private Shell shell;
+
+ private SaveTreeViewAction(Shell shell) {
+ super("&Save as PNG");
+ this.shell = shell;
+ setAccelerator(SWT.MOD1 + 'S');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("save.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Save the tree view as a PNG image");
+ }
+
+ public static SaveTreeViewAction getAction(Shell shell) {
+ if (action == null) {
+ action = new SaveTreeViewAction(shell);
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerDirector.getDirector().saveTreeView(shell);
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ShowOverlayAction.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ShowOverlayAction.java
new file mode 100644
index 0000000..b0f51ec
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/actions/ShowOverlayAction.java
@@ -0,0 +1,59 @@
+/*
+ * 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.hierarchyviewer.actions;
+
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewer.HierarchyViewerApplication;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+public class ShowOverlayAction extends Action implements ImageAction {
+
+ private static ShowOverlayAction action;
+
+ private Image image;
+
+ private ShowOverlayAction() {
+ super("Show In &Loupe", Action.AS_CHECK_BOX);
+ setAccelerator(SWT.MOD1 + 'L');
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ image = imageLoader.loadImage("show-overlay.png", Display.getDefault());
+ setImageDescriptor(ImageDescriptor.createFromImage(image));
+ setToolTipText("Show the overlay in the loupe view");
+ }
+
+ public static ShowOverlayAction getAction() {
+ if (action == null) {
+ action = new ShowOverlayAction();
+ }
+ return action;
+ }
+
+ @Override
+ public void run() {
+ HierarchyViewerApplication.getApp().showOverlayInLoupe(action.isChecked());
+ }
+
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/util/ActionButton.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/util/ActionButton.java
new file mode 100644
index 0000000..08fe1ac
--- /dev/null
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/util/ActionButton.java
@@ -0,0 +1,75 @@
+/*
+ * 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.hierarchyviewer.util;
+
+import com.android.hierarchyviewer.actions.ImageAction;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+public class ActionButton implements IPropertyChangeListener, SelectionListener {
+ private Button button;
+
+ private Action action;
+
+ public ActionButton(Composite parent, ImageAction action) {
+ this.action = (Action) action;
+ if (this.action.getStyle() == Action.AS_CHECK_BOX) {
+ button = new Button(parent, SWT.CHECK);
+ } else {
+ button = new Button(parent, SWT.PUSH);
+ }
+ button.setText(action.getText());
+ button.setImage(action.getImage());
+ this.action.addPropertyChangeListener(this);
+ button.addSelectionListener(this);
+ button.setToolTipText(action.getToolTipText());
+ }
+
+ public void propertyChange(PropertyChangeEvent e) {
+ if (e.getProperty().toUpperCase().equals("ENABLED")) {
+ button.setEnabled((Boolean) e.getNewValue());
+ } else if (e.getProperty().toUpperCase().equals("CHECKED")) {
+ button.setSelection(action.isChecked());
+ }
+ }
+
+ public void setLayoutData(Object data) {
+ button.setLayoutData(data);
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // pass
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ if (action.getStyle() == Action.AS_CHECK_BOX) {
+ action.setChecked(button.getSelection());
+ }
+ action.run();
+ }
+
+ public void addSelectionListener(SelectionListener listener) {
+ button.addSelectionListener(listener);
+ }
+}
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
new file mode 100644
index 0000000..72ecabc
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about-small.jpg
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg
new file mode 100644
index 0000000..2183168
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png
new file mode 100644
index 0000000..240862f
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png
new file mode 100644
index 0000000..0f25426
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png
new file mode 100644
index 0000000..fd107ed
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png
new file mode 100644
index 0000000..9a7eed4
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png
new file mode 100644
index 0000000..a9de0ec
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png
new file mode 100644
index 0000000..4fcab3f
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png
index b52a342..800000d 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png
new file mode 100644
index 0000000..6e51701
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png
new file mode 100644
index 0000000..ee75f69
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png
new file mode 100644
index 0000000..3329ec9
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png
new file mode 100644
index 0000000..4817252
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png
new file mode 100644
index 0000000..8f01dda
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png
new file mode 100644
index 0000000..db6f13b
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png
new file mode 100644
index 0000000..cd88803
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png
new file mode 100644
index 0000000..5f05662
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png
Binary files differ
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
new file mode 100644
index 0000000..1e44000
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png
new file mode 100644
index 0000000..ec51cec
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png
index 338c2d9..a2ab855 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png
new file mode 100644
index 0000000..8fddcae
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png
new file mode 100644
index 0000000..92a78c8
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png
new file mode 100644
index 0000000..2c0bab1
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png
new file mode 100644
index 0000000..9ef6b34
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png
new file mode 100644
index 0000000..1f59685
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png
new file mode 100644
index 0000000..538e385
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png
new file mode 100644
index 0000000..5cd5c3f
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png
new file mode 100644
index 0000000..e39e90a
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png
new file mode 100644
index 0000000..175ad1f
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png
new file mode 100644
index 0000000..23aa424
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png
Binary files differ
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png
index b6fadac..e9b5781 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png
Binary files differ