diff options
author | Konstantin Lopyrev <klopyrev@google.com> | 2010-08-18 22:08:09 -0700 |
---|---|---|
committer | Konstantin Lopyrev <klopyrev@google.com> | 2010-08-27 09:09:02 -0700 |
commit | 97b0639645d9c387cdd9884272e053c467a240da (patch) | |
tree | 7c952e2b4b5287d866832f9ce95a9e3aaf2bea89 | |
parent | 70a830d8ab396328ab984c75f923400af6a52e55 (diff) | |
download | sdk-97b0639645d9c387cdd9884272e053c467a240da.zip sdk-97b0639645d9c387cdd9884272e053c467a240da.tar.gz sdk-97b0639645d9c387cdd9884272e053c467a240da.tar.bz2 |
Creating the application
Change-Id: I8f2fce7328cc1d93caed1cf003f04e41204f864c
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 Binary files differnew file mode 100644 index 0000000..72ecabc --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about-small.jpg diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg Binary files differnew file mode 100644 index 0000000..2183168 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png Binary files differnew file mode 100644 index 0000000..240862f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png Binary files differnew file mode 100644 index 0000000..0f25426 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png Binary files differnew file mode 100644 index 0000000..fd107ed --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png Binary files differnew file mode 100644 index 0000000..9a7eed4 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png Binary files differnew file mode 100644 index 0000000..a9de0ec --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png Binary files differnew file mode 100644 index 0000000..4fcab3f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png Binary files differindex b52a342..800000d 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png Binary files differnew file mode 100644 index 0000000..6e51701 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png Binary files differnew file mode 100644 index 0000000..ee75f69 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png Binary files differnew file mode 100644 index 0000000..3329ec9 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png Binary files differnew file mode 100644 index 0000000..4817252 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png Binary files differnew file mode 100644 index 0000000..8f01dda --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png Binary files differnew file mode 100644 index 0000000..db6f13b --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png Binary files differnew file mode 100644 index 0000000..cd88803 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png Binary files differnew file mode 100644 index 0000000..5f05662 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png Binary files differnew file mode 100644 index 0000000..1e44000 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png Binary files differnew file mode 100644 index 0000000..ec51cec --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png Binary files differindex 338c2d9..a2ab855 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png Binary files differnew file mode 100644 index 0000000..8fddcae --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png Binary files differnew file mode 100644 index 0000000..92a78c8 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png Binary files differnew file mode 100644 index 0000000..2c0bab1 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png Binary files differnew file mode 100644 index 0000000..9ef6b34 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png Binary files differnew file mode 100644 index 0000000..1f59685 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png Binary files differnew file mode 100644 index 0000000..538e385 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png Binary files differnew file mode 100644 index 0000000..5cd5c3f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png Binary files differnew file mode 100644 index 0000000..e39e90a --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png Binary files differnew file mode 100644 index 0000000..175ad1f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png Binary files differnew file mode 100644 index 0000000..23aa424 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png Binary files differindex b6fadac..e9b5781 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png |