FileDocCategorySizeDatePackage
Workspace.javaAPI DocAndroid 1.5 API51874Wed May 06 22:41:10 BST 2009com.android.hierarchyviewer.ui

Workspace

public class Workspace extends JFrame

Fields Summary
private JLabel
viewCountLabel
private JSlider
zoomSlider
private JSplitPane
sideSplitter
private JSplitPane
mainSplitter
private JTable
propertiesTable
private JTable
profilingTable
private JComponent
pixelPerfectPanel
private JTree
pixelPerfectTree
private ScreenViewer
screenViewer
private JPanel
extrasPanel
private LayoutRenderer
layoutView
private JScrollPane
sceneScroller
private JComponent
sceneView
private com.android.hierarchyviewer.scene.ViewHierarchyScene
scene
private ActionMap
actionsMap
private JPanel
mainPanel
private JProgressBar
progress
private JToolBar
buttonsPanel
private JComponent
deviceSelector
private DevicesTableModel
devicesTableModel
private WindowsTableModel
windowsTableModel
private com.android.ddmlib.Device
currentDevice
private com.android.hierarchyviewer.device.Window
currentWindow
private JButton
displayNodeButton
private JButton
invalidateButton
private JButton
requestLayoutButton
private JButton
loadButton
private JButton
startButton
private JButton
stopButton
private JButton
showDevicesButton
private JButton
refreshButton
private JToggleButton
graphViewButton
private JToggleButton
pixelPerfectViewButton
private JMenuItem
saveMenuItem
private JMenuItem
showDevicesMenuItem
private JMenuItem
loadMenuItem
private JMenuItem
startMenuItem
private JMenuItem
stopMenuItem
private JTable
devices
private JTable
windows
private JLabel
minZoomLabel
private JLabel
maxZoomLabel
private JTextField
filterText
private JLabel
filterLabel
Constructors Summary
public Workspace()


      
        super("Hierarchy Viewer");

        buildActions();
        add(buildMainPanel());
        setJMenuBar(buildMenuBar());

        devices.changeSelection(0, 0, false, false);
        currentDeviceChanged();

        pack();
    
Methods Summary
public voidbeginTask()

        progress.setVisible(true);
    
private voidbuildActions()

        actionsMap = new ActionMap();
        actionsMap.put(ExitAction.ACTION_NAME, new ExitAction(this));
        actionsMap.put(ShowDevicesAction.ACTION_NAME, new ShowDevicesAction(this));
        actionsMap.put(LoadGraphAction.ACTION_NAME, new LoadGraphAction(this));
        actionsMap.put(SaveSceneAction.ACTION_NAME, new SaveSceneAction(this));
        actionsMap.put(StartServerAction.ACTION_NAME, new StartServerAction(this));
        actionsMap.put(StopServerAction.ACTION_NAME, new StopServerAction(this));
        actionsMap.put(InvalidateAction.ACTION_NAME, new InvalidateAction(this));
        actionsMap.put(RequestLayoutAction.ACTION_NAME, new RequestLayoutAction(this));
        actionsMap.put(CaptureNodeAction.ACTION_NAME, new CaptureNodeAction(this));
        actionsMap.put(RefreshWindowsAction.ACTION_NAME, new RefreshWindowsAction(this));
    
private javax.swing.JComponentbuildDeviceSelector()

        JPanel panel = new JPanel(new GridBagLayout());
        if (OS.isMacOsX() && OS.isLeopardOrLater()) {
            panel.setBorder(new UnifiedContentBorder());
        }

        devicesTableModel = new DevicesTableModel();
        for (Device device : DeviceBridge.getDevices()) {
            DeviceBridge.setupDeviceForward(device);
            devicesTableModel.addDevice(device);
        }
        DeviceBridge.startListenForDevices(devicesTableModel);

        devices = new JTable(devicesTableModel);
        devices.getSelectionModel().addListSelectionListener(new DeviceSelectedListener());
        devices.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        devices.setBorder(null);
        JScrollPane devicesScroller = new JScrollPane(devices);
        devicesScroller.setBorder(null);
        panel.add(devicesScroller, new GridBagConstraints(0, 0, 1, 1, 0.5, 1.0,
                GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0),
                0, 0));

        windowsTableModel = new WindowsTableModel();
        windowsTableModel.setVisible(false);

        windows = new JTable(windowsTableModel);
        windows.getSelectionModel().addListSelectionListener(new WindowSelectedListener());
        windows.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        windows.setBorder(null);
        JScrollPane windowsScroller = new JScrollPane(windows);
        windowsScroller.setBorder(null);
        panel.add(windowsScroller, new GridBagConstraints(2, 0, 1, 1, 0.5, 1.0,
                GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0),
                0, 0));

        return panel;
    
private javax.swing.JPanelbuildExtrasPanel()

        extrasPanel = new JPanel(new BorderLayout());
        JScrollPane p = new JScrollPane(layoutView = new LayoutRenderer(scene, sceneView));
        JScrollBar b = p.getVerticalScrollBar();
        b.setUnitIncrement(10);
        extrasPanel.add(p);
        extrasPanel.add(scene.createSatelliteView(), BorderLayout.SOUTH);
        extrasPanel.add(buildLayoutViewControlButtons(), BorderLayout.NORTH);
        return extrasPanel;
    
private javax.swing.JComponentbuildGraphPanel()

        sceneScroller = new JScrollPane();
        sceneScroller.setBorder(null);

        mainSplitter = new JSplitPane();
        mainSplitter.setResizeWeight(1.0);
        mainSplitter.setContinuousLayout(true);
        if (OS.isMacOsX() && OS.isLeopardOrLater()) {
            mainSplitter.setBorder(new UnifiedContentBorder());
        }

        mainSplitter.setLeftComponent(sceneScroller);
        mainSplitter.setRightComponent(buildSideSplitter());

        return mainSplitter;
    
private javax.swing.JComponentbuildLayoutViewControlButtons()

        buttonsPanel = new JToolBar();
        buttonsPanel.setFloatable(false);

        ButtonGroup group = new ButtonGroup();

        JToggleButton white = new JToggleButton("On White");
        toggleColorOnSelect(white);
        white.putClientProperty("JButton.buttonType", "segmentedTextured");
        white.putClientProperty("JButton.segmentPosition", "first");
        white.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                layoutView.setBackground(Color.WHITE);
                layoutView.setForeground(Color.BLACK);
            }
        });
        group.add(white);
        buttonsPanel.add(white);

        JToggleButton black = new JToggleButton("On Black");
        toggleColorOnSelect(black);
        black.putClientProperty("JButton.buttonType", "segmentedTextured");
        black.putClientProperty("JButton.segmentPosition", "last");
        black.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                layoutView.setBackground(Color.BLACK);
                layoutView.setForeground(Color.WHITE);
            }
        });
        group.add(black);
        buttonsPanel.add(black);

        black.setSelected(true);

        JCheckBox showExtras = new JCheckBox("Show Extras");
        showExtras.putClientProperty("JComponent.sizeVariant", "small");
        showExtras.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                layoutView.setShowExtras(((JCheckBox) e.getSource()).isSelected());
            }
        });
        buttonsPanel.add(showExtras);

        return buttonsPanel;
    
private javax.swing.JComponentbuildMainPanel()

        mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());
        mainPanel.add(buildToolBar(), BorderLayout.PAGE_START);
        mainPanel.add(deviceSelector = buildDeviceSelector(), BorderLayout.CENTER);
        mainPanel.add(buildStatusPanel(), BorderLayout.SOUTH);

        mainPanel.setPreferredSize(new Dimension(950, 800));

        return mainPanel;
    
private javax.swing.JMenuBarbuildMenuBar()

        JMenuBar menuBar = new JMenuBar();

        JMenu fileMenu = new JMenu();
        JMenu viewMenu = new JMenu();
        JMenu viewHierarchyMenu = new JMenu();
        JMenu serverMenu = new JMenu();

        saveMenuItem = new JMenuItem();
        JMenuItem exitMenuItem = new JMenuItem();

        showDevicesMenuItem = new JMenuItem();

        loadMenuItem = new JMenuItem();

        startMenuItem = new JMenuItem();
        stopMenuItem = new JMenuItem();

        fileMenu.setText("File");

        saveMenuItem.setAction(actionsMap.get(SaveSceneAction.ACTION_NAME));
        fileMenu.add(saveMenuItem);

        exitMenuItem.setAction(actionsMap.get(ExitAction.ACTION_NAME));
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        viewMenu.setText("View");

        showDevicesMenuItem.setAction(actionsMap.get(ShowDevicesAction.ACTION_NAME));
        showDevicesMenuItem.setEnabled(false);
        viewMenu.add(showDevicesMenuItem);

        menuBar.add(viewMenu);        

        viewHierarchyMenu.setText("Hierarchy");

        loadMenuItem.setAction(actionsMap.get(LoadGraphAction.ACTION_NAME));
        viewHierarchyMenu.add(loadMenuItem);

        menuBar.add(viewHierarchyMenu);

        serverMenu.setText("Server");

        startMenuItem.setAction(actionsMap.get(StartServerAction.ACTION_NAME));
        serverMenu.add(startMenuItem);

        stopMenuItem.setAction(actionsMap.get(StopServerAction.ACTION_NAME));
        serverMenu.add(stopMenuItem);

        menuBar.add(serverMenu);

        return menuBar;
    
private javax.swing.JComponentbuildPixelPerfectPanel()

        JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

        pixelPerfectTree = new JTree(new Object[0]);
        pixelPerfectTree.setBorder(null);
        pixelPerfectTree.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
        pixelPerfectTree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent event) {
                ViewNode node = (ViewNode) event.getPath().getLastPathComponent();
                screenViewer.select(node);
            }
        });

        JScrollPane scroller = new JScrollPane(pixelPerfectTree);
        scroller.setBorder(null);
        scroller.getViewport().setBorder(null);

        splitter.setContinuousLayout(true);
        splitter.setLeftComponent(scroller);
        splitter.setRightComponent(buildPixelPerfectViewer(splitter));
        splitter.setBorder(null);

        if (OS.isMacOsX() && OS.isLeopardOrLater()) {
            splitter.setBorder(new UnifiedContentBorder());
        }

        return splitter;
    
private javax.swing.JComponentbuildPixelPerfectViewer(javax.swing.JSplitPane splitter)

        screenViewer = new ScreenViewer(this, currentDevice, splitter.getDividerSize());
        return screenViewer;
    
private javax.swing.JComponentbuildSideSplitter()

        propertiesTable = new JTable();
        propertiesTable.setModel(new DefaultTableModel(new Object[][] { },
                new String[] { "Property", "Value" }));
        propertiesTable.setBorder(null);
        propertiesTable.getTableHeader().setBorder(null);

        JScrollPane tableScroller = new JScrollPane(propertiesTable);
        tableScroller.setBorder(null);

        profilingTable = new JTable();
        profilingTable.setModel(new DefaultTableModel(new Object[][] {
                { " " , " " }, { " " , " " }, { " " , " " } },
                new String[] { "Operation", "Duration (ms)" }));
        profilingTable.setBorder(null);
        profilingTable.getTableHeader().setBorder(null);

        JScrollPane firstTableScroller = new JScrollPane(profilingTable);
        firstTableScroller.setBorder(null);

        setVisibleRowCount(profilingTable, 5);
        firstTableScroller.setMinimumSize(profilingTable.getPreferredScrollableViewportSize());
        
        JSplitPane tablesSplitter = new JSplitPane();
        tablesSplitter.setBorder(null);
        tablesSplitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
        tablesSplitter.setResizeWeight(0);
        tablesSplitter.setLeftComponent(firstTableScroller);
        tablesSplitter.setBottomComponent(tableScroller);
        tablesSplitter.setContinuousLayout(true);

        sideSplitter = new JSplitPane();
        sideSplitter.setBorder(null);
        sideSplitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
        sideSplitter.setResizeWeight(0.5);
        sideSplitter.setLeftComponent(tablesSplitter);
        sideSplitter.setBottomComponent(null);
        sideSplitter.setContinuousLayout(true);

        return sideSplitter;
    
private javax.swing.JPanelbuildStatusPanel()

        JPanel statusPanel = new JPanel();
        statusPanel.setLayout(new BorderLayout());

        JPanel leftSide = new JPanel();
        leftSide.setOpaque(false);
        leftSide.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 5));
        leftSide.add(Box.createHorizontalStrut(6));

        ButtonGroup group = new ButtonGroup();

        graphViewButton = new JToggleButton(IconLoader.load(getClass(),
                "/images/icon-graph-view.png"));
        graphViewButton.setSelectedIcon(IconLoader.load(getClass(),
                "/images/icon-graph-view-selected.png"));
        graphViewButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        graphViewButton.putClientProperty("JButton.segmentPosition", "first");
        graphViewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                toggleGraphView();
            }
        });
        group.add(graphViewButton);
        leftSide.add(graphViewButton);

        pixelPerfectViewButton = new JToggleButton(IconLoader.load(getClass(),
                "/images/icon-pixel-perfect-view.png"));
        pixelPerfectViewButton.setSelectedIcon(IconLoader.load(getClass(),
                "/images/icon-pixel-perfect-view-selected.png"));
        pixelPerfectViewButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        pixelPerfectViewButton.putClientProperty("JButton.segmentPosition", "last");
        pixelPerfectViewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                togglePixelPerfectView();
            }
        });
        group.add(pixelPerfectViewButton);
        leftSide.add(pixelPerfectViewButton);

        graphViewButton.setSelected(true);

        filterText = new JTextField(20);
        filterText.putClientProperty("JComponent.sizeVariant", "small");
        filterText.getDocument().addDocumentListener(new DocumentListener() {
            public void insertUpdate(DocumentEvent e) {
                updateFilter(e);
            }

            public void removeUpdate(DocumentEvent e) {
                updateFilter(e);
            }

            public void changedUpdate(DocumentEvent e) {
                updateFilter(e);
            }
        });

        filterLabel = new JLabel("Filter by class or id:");
        filterLabel.putClientProperty("JComponent.sizeVariant", "small");
        filterLabel.setBorder(BorderFactory.createEmptyBorder(0, 6, 0, 6));

        leftSide.add(filterLabel);
        leftSide.add(filterText);

        minZoomLabel = new JLabel();
        minZoomLabel.setText("20%");
        minZoomLabel.putClientProperty("JComponent.sizeVariant", "small");
        minZoomLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
        leftSide.add(minZoomLabel);

        zoomSlider = new JSlider();
        zoomSlider.putClientProperty("JComponent.sizeVariant", "small");
        zoomSlider.setMaximum(200);
        zoomSlider.setMinimum(20);
        zoomSlider.setValue(100);
        zoomSlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent evt) {
                zoomSliderStateChanged(evt);
            }
        });
        leftSide.add(zoomSlider);

        maxZoomLabel = new JLabel();
        maxZoomLabel.putClientProperty("JComponent.sizeVariant", "small");
        maxZoomLabel.setText("200%");
        leftSide.add(maxZoomLabel);

        viewCountLabel = new JLabel();
        viewCountLabel.setText("0 views");
        viewCountLabel.putClientProperty("JComponent.sizeVariant", "small");
        viewCountLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
        leftSide.add(viewCountLabel);

        statusPanel.add(leftSide, BorderLayout.LINE_START);

        JPanel rightSide = new JPanel();
        rightSide.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 12));
        rightSide.setLayout(new FlowLayout(FlowLayout.RIGHT));

        progress = new JProgressBar();
        progress.setVisible(false);
        progress.setIndeterminate(true);
        progress.putClientProperty("JComponent.sizeVariant", "mini");
        progress.putClientProperty("JProgressBar.style", "circular");
        rightSide.add(progress);

        statusPanel.add(rightSide, BorderLayout.LINE_END);

        hideStatusBarComponents();

        return statusPanel;
    
private javax.swing.JToolBarbuildToolBar()

        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        toolBar.setRollover(true);

        startButton = new JButton();
        startButton.setAction(actionsMap.get(StartServerAction.ACTION_NAME));
        startButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        startButton.putClientProperty("JButton.segmentPosition", "first");
        toolBar.add(startButton);

        stopButton = new JButton();
        stopButton.setAction(actionsMap.get(StopServerAction.ACTION_NAME));
        stopButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        stopButton.putClientProperty("JButton.segmentPosition", "middle");
        toolBar.add(stopButton);

        refreshButton = new JButton();
        refreshButton.setAction(actionsMap.get(RefreshWindowsAction.ACTION_NAME));
        refreshButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        refreshButton.putClientProperty("JButton.segmentPosition", "last");
        toolBar.add(refreshButton);

        showDevicesButton = new JButton();
        showDevicesButton.setAction(actionsMap.get(ShowDevicesAction.ACTION_NAME));
        showDevicesButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        showDevicesButton.putClientProperty("JButton.segmentPosition", "first");
        toolBar.add(showDevicesButton);
        showDevicesButton.setEnabled(false);

        loadButton = new JButton();
        loadButton.setAction(actionsMap.get(LoadGraphAction.ACTION_NAME));
        loadButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        loadButton.putClientProperty("JButton.segmentPosition", "last");
        toolBar.add(loadButton);

        displayNodeButton = new JButton();
        displayNodeButton.setAction(actionsMap.get(CaptureNodeAction.ACTION_NAME));
        displayNodeButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        displayNodeButton.putClientProperty("JButton.segmentPosition", "first");
        toolBar.add(displayNodeButton);

        invalidateButton = new JButton();
        invalidateButton.setAction(actionsMap.get(InvalidateAction.ACTION_NAME));
        invalidateButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        invalidateButton.putClientProperty("JButton.segmentPosition", "middle");
        toolBar.add(invalidateButton);

        requestLayoutButton = new JButton();
        requestLayoutButton.setAction(actionsMap.get(RequestLayoutAction.ACTION_NAME));
        requestLayoutButton.putClientProperty("JButton.buttonType", "segmentedTextured");
        requestLayoutButton.putClientProperty("JButton.segmentPosition", "last");
        toolBar.add(requestLayoutButton);

        return toolBar;
    
private voidcheckForServerOnCurrentDevice()

        if (DeviceBridge.isViewServerRunning(currentDevice)) {
            startButton.setEnabled(false);
            startMenuItem.setEnabled(false);
            stopButton.setEnabled(true);
            stopMenuItem.setEnabled(true);
            loadButton.setEnabled(true);
            refreshButton.setEnabled(true);
        } else {
            startButton.setEnabled(true);
            startMenuItem.setEnabled(true);
            stopButton.setEnabled(false);
            stopMenuItem.setEnabled(false);
            loadButton.setEnabled(false);
            refreshButton.setEnabled(false);
        }
    
public voidcleanupDevices()

        for (Device device : devicesTableModel.getDevices()) {
            DeviceBridge.removeDeviceForward(device);
        }
    
private voidcreateGraph(com.android.hierarchyviewer.scene.ViewHierarchyScene scene)

        scene.addObjectSceneListener(new SceneFocusListener(),
                ObjectSceneEventType.OBJECT_FOCUS_CHANGED);

        if (mainSplitter == null) {
            mainPanel.remove(deviceSelector);
            mainPanel.add(buildGraphPanel(), BorderLayout.CENTER);
            showDevicesButton.setEnabled(true);
            showDevicesMenuItem.setEnabled(true);
            graphViewButton.setEnabled(true);
            pixelPerfectViewButton.setEnabled(true);

            showStatusBarComponents();
        }

        sceneView = scene.createView();
        sceneView.addMouseListener(new NodeClickListener());
        sceneView.addMouseWheelListener(new WheelZoomListener());
        sceneScroller.setViewportView(sceneView);

        if (extrasPanel != null) {
            sideSplitter.remove(extrasPanel);
        }
        sideSplitter.setBottomComponent(buildExtrasPanel());

        mainSplitter.setDividerLocation(getWidth() - mainSplitter.getDividerSize() -
                buttonsPanel.getPreferredSize().width);

        saveMenuItem.setEnabled(true);
        showPixelPerfectTree();

        updateStatus();
        layoutScene();
    
private voidcurrentDeviceChanged()

        if (currentDevice == null) {
            startButton.setEnabled(false);
            startMenuItem.setEnabled(false);
            stopButton.setEnabled(false);
            stopMenuItem.setEnabled(false);
            refreshButton.setEnabled(false);
            saveMenuItem.setEnabled(false);
            loadButton.setEnabled(false);
            displayNodeButton.setEnabled(false);
            invalidateButton.setEnabled(false);
            graphViewButton.setEnabled(false);
            pixelPerfectViewButton.setEnabled(false);
            requestLayoutButton.setEnabled(false);
            loadMenuItem.setEnabled(false);
        } else {
            loadMenuItem.setEnabled(true);
            checkForServerOnCurrentDevice();
        }
    
public voidendTask()

        progress.setVisible(false);
    
private static voidexpandAll(javax.swing.JTree tree, boolean expand)

        ViewNode root = (ViewNode) tree.getModel().getRoot();
        expandAll(tree, new TreePath(root), expand);
    
private static voidexpandAll(javax.swing.JTree tree, javax.swing.tree.TreePath parent, boolean expand)

        // Traverse children
        ViewNode node = (ViewNode)parent.getLastPathComponent();
        if (node.children != null) {
            for (ViewNode n : node.children) {
                TreePath path = parent.pathByAddingChild(n);
                expandAll(tree, path, expand);
            }
        }

        if (expand) {
            tree.expandPath(parent);
        } else {
            tree.collapsePath(parent);
        }
    
private voidfilterNodes(java.util.regex.Pattern pattern, com.android.hierarchyviewer.scene.ViewNode root)

        root.filter(pattern);

        for (ViewNode node : root.children) {
            filterNodes(pattern, node);
        }
    
private voidhideStatusBarComponents()

        viewCountLabel.setVisible(false);
        zoomSlider.setVisible(false);
        minZoomLabel.setVisible(false);
        maxZoomLabel.setVisible(false);
        filterLabel.setVisible(false);
        filterText.setVisible(false);
    
public org.jdesktop.swingworker.SwingWorkerinvalidateView()

        if (scene.getFocusedObject() == null) {
            return null;
        }
        return new InvalidateTask();
    
private voidlayoutScene()

        TreeGraphLayout<ViewNode, String> layout =
                new TreeGraphLayout<ViewNode, String>(scene, 50, 50, 70, 30, true);
        layout.layout(scene.getRoot());
    
public org.jdesktop.swingworker.SwingWorkerloadGraph()

        return new LoadGraphTask();
    
public org.jdesktop.swingworker.SwingWorkerloadWindows()

        return new LoadWindowsTask();
    
public org.jdesktop.swingworker.SwingWorkerrequestLayout()

        if (scene.getFocusedObject() == null) {
            return null;
        }
        return new RequestLayoutTask();
    
private voidreset()

        currentDevice = null;
        currentWindow = null;
        currentDeviceChanged();
        windowsTableModel.setVisible(false);
        windowsTableModel.clear();

        showDevicesSelector();
    
public org.jdesktop.swingworker.SwingWorkersaveSceneAsImage()

        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new PngFileFilter());
        int choice = chooser.showSaveDialog(sceneView);
        if (choice == JFileChooser.APPROVE_OPTION) {
            return new SaveSceneTask(chooser.getSelectedFile());
        } else {
            return null;
        }
    
public static voidsetVisibleRowCount(javax.swing.JTable table, int rows)

        int height = 0;
        for (int row = 0; row < rows; row++) {
            height += table.getRowHeight(row);
        }

        Dimension size = new Dimension(table.getPreferredScrollableViewportSize().width, height);
        table.setPreferredScrollableViewportSize(size);
        table.revalidate();
    
private voidshowCaptureWindow(com.android.hierarchyviewer.scene.ViewNode node, java.lang.String captureParams, java.awt.Image image)

        if (image != null) {
            layoutView.repaint();

            JFrame frame = new JFrame(captureParams);
            JPanel panel = new JPanel(new BorderLayout());

            final CaptureRenderer label = new CaptureRenderer(new ImageIcon(image), node);
            label.setBorder(BorderFactory.createEmptyBorder(24, 24, 24, 24));

            final JPanel solidColor = new JPanel(new BorderLayout());
            solidColor.setBackground(Color.BLACK);
            solidColor.add(label);

            JToolBar toolBar = new JToolBar();
            toolBar.setFloatable(false);

            ButtonGroup group = new ButtonGroup();

            JToggleButton white = new JToggleButton("On White");
            toggleColorOnSelect(white);
            white.putClientProperty("JButton.buttonType", "segmentedTextured");
            white.putClientProperty("JButton.segmentPosition", "first");
            white.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    solidColor.setBackground(Color.WHITE);
                }
            });
            group.add(white);
            toolBar.add(white);

            JToggleButton black = new JToggleButton("On Black");
            toggleColorOnSelect(black);
            black.putClientProperty("JButton.buttonType", "segmentedTextured");
            black.putClientProperty("JButton.segmentPosition", "last");
            black.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    solidColor.setBackground(Color.BLACK);
                }
            });
            group.add(black);
            toolBar.add(black);

            black.setSelected(true);

            JCheckBox showExtras = new JCheckBox("Show Extras");
            showExtras.addChangeListener(new ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                    label.setShowExtras(((JCheckBox) e.getSource()).isSelected());
                }
            });
            toolBar.add(showExtras);

            panel.add(toolBar, BorderLayout.NORTH);
            panel.add(solidColor);
            frame.add(panel);

            frame.pack();
            frame.setResizable(false);
            frame.setLocationRelativeTo(Workspace.this);
            frame.setVisible(true);
        }
    
public voidshowDevicesSelector()

        if (mainSplitter != null) {
            if (pixelPerfectPanel != null) {
                screenViewer.start();                
            }
            mainPanel.remove(graphViewButton.isSelected() ? mainSplitter : pixelPerfectPanel);
            mainPanel.add(deviceSelector, BorderLayout.CENTER);
            pixelPerfectPanel = mainSplitter = null;
            graphViewButton.setSelected(true);

            hideStatusBarComponents();

            saveMenuItem.setEnabled(false);            
            showDevicesMenuItem.setEnabled(false);
            showDevicesButton.setEnabled(false);
            displayNodeButton.setEnabled(false);
            invalidateButton.setEnabled(false);
            requestLayoutButton.setEnabled(false);
            graphViewButton.setEnabled(false);
            pixelPerfectViewButton.setEnabled(false);

            if (currentDevice != null) {
                if (!DeviceBridge.isViewServerRunning(currentDevice)) {
                    DeviceBridge.startViewServer(currentDevice);
                }
                loadWindows().execute();
                windowsTableModel.setVisible(true);
            }

            validate();
            repaint();
        }
    
public org.jdesktop.swingworker.SwingWorkershowNodeCapture()

        if (scene.getFocusedObject() == null) {
            return null;
        }
        return new CaptureNodeTask();
    
private voidshowPixelPerfectTree()

        if (pixelPerfectTree == null) {
            return;
        }
        pixelPerfectTree.setModel(new ViewsTreeModel(scene.getRoot()));
        pixelPerfectTree.setCellRenderer(new ViewsTreeCellRenderer());
        expandAll(pixelPerfectTree, true);

    
private voidshowProperties(com.android.hierarchyviewer.scene.ViewNode node)

        propertiesTable.setModel(new PropertiesTableModel(node));
    
private voidshowStatusBarComponents()

        viewCountLabel.setVisible(true);
        zoomSlider.setVisible(true);
        minZoomLabel.setVisible(true);
        maxZoomLabel.setVisible(true);
        filterLabel.setVisible(true);
        filterText.setVisible(true);
    
public org.jdesktop.swingworker.SwingWorkerstartServer()

        return new StartServerTask();
    
public org.jdesktop.swingworker.SwingWorkerstopServer()

        return new StopServerTask();
    
private static voidtoggleColorOnSelect(javax.swing.JToggleButton button)

        if (!OS.isMacOsX() || !OS.isLeopardOrLater()) {
            return;
        }

        button.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent event) {
                JToggleButton button = (JToggleButton) event.getSource();
                if (button.isSelected()) {
                    button.setForeground(Color.WHITE);
                } else {
                    button.setForeground(Color.BLACK);
                }
            }
        });
    
private voidtoggleGraphView()

        showStatusBarComponents();

        screenViewer.stop();
        mainPanel.remove(pixelPerfectPanel);
        mainPanel.add(mainSplitter, BorderLayout.CENTER);

        validate();
        repaint();
    
private voidtogglePixelPerfectView()

        if (pixelPerfectPanel == null) {
            pixelPerfectPanel = buildPixelPerfectPanel();
            showPixelPerfectTree();
        } else {
            screenViewer.start();
        }

        hideStatusBarComponents();

        mainPanel.remove(mainSplitter);
        mainPanel.add(pixelPerfectPanel, BorderLayout.CENTER);

        validate();
        repaint();
    
private voidupdateFilter(javax.swing.event.DocumentEvent e)

        final Document document = e.getDocument();
        try {
            updateFilteredNodes(document.getText(0, document.getLength()));
        } catch (BadLocationException e1) {
            e1.printStackTrace();
        }
    
private voidupdateFilteredNodes(java.lang.String filterText)

        final ViewNode root = scene.getRoot();
        try {
            final Pattern pattern = Pattern.compile(filterText, Pattern.CASE_INSENSITIVE);
            filterNodes(pattern, root);
        } catch (PatternSyntaxException e) {
            filterNodes(null, root);
        }
        repaint();
    
private voidupdateProfiles(double[] profiles)

        profilingTable.setModel(new ProfilesTableModel(profiles));
        setVisibleRowCount(profilingTable, profiles.length + 1);
    
private voidupdateStatus()

        viewCountLabel.setText("" + scene.getNodes().size() + " views");
        zoomSlider.setEnabled(scene.getNodes().size() > 0);
    
private voidzoomSliderStateChanged(javax.swing.event.ChangeEvent evt)

        JSlider slider = (JSlider) evt.getSource();
        if (sceneView != null) {
            scene.setZoomFactor(slider.getValue() / 100.0d);
            sceneView.repaint();
        }