org.eclipse.mat.ui.internal.views.NavigatorViewPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mat.ui.internal.views.NavigatorViewPage.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2010 SAP AG. 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 * 
 * Contributors: SAP AG - initial API and implementation
 ******************************************************************************/
package org.eclipse.mat.ui.internal.views;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.mat.ui.MemoryAnalyserPlugin;
import org.eclipse.mat.ui.MemoryAnalyserPlugin.ISharedImages;
import org.eclipse.mat.ui.Messages;
import org.eclipse.mat.ui.QueryExecution;
import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter;
import org.eclipse.mat.ui.compare.CompareBasketView;
import org.eclipse.mat.ui.editor.AbstractEditorPane;
import org.eclipse.mat.ui.editor.CompositeHeapEditorPane;
import org.eclipse.mat.ui.editor.EditorPaneRegistry;
import org.eclipse.mat.ui.editor.MultiPaneEditor;
import org.eclipse.mat.ui.util.Copy;
import org.eclipse.mat.ui.util.ErrorHelper;
import org.eclipse.mat.ui.util.NavigatorState.IStateChangeListener;
import org.eclipse.mat.ui.util.PaneState;
import org.eclipse.mat.ui.util.PaneState.PaneType;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.Page;
import org.eclipse.ui.themes.ColorUtil;

public class NavigatorViewPage extends Page
        implements ISelectionProvider, IDoubleClickListener, IStateChangeListener {
    private class NavigatorLabelProvider extends LabelProvider implements IFontProvider, IColorProvider {
        @Override
        public Image getImage(Object element) {
            return ((PaneState) element).getImage();
        }

        @Override
        public String getText(Object element) {
            // Convert multi-line text to a single line, for example OQL statements
            return ((PaneState) element).getIdentifier().replaceAll("(\\s*[\\r\\n]\\s*)+", " "); //$NON-NLS-1$//$NON-NLS-2$
        }

        public Font getFont(Object element) {
            if (((PaneState) element).isReproducable())
                return null;
            return font;
        }

        public Color getBackground(Object element) {
            return null;
        }

        public Color getForeground(Object element) {
            if (((PaneState) element).isActive())
                return null;
            return greyColor;
        }
    }

    private static class NavigatorContentProvider implements ITreeContentProvider {
        private List<PaneState> elements;

        public Object[] getChildren(Object element) {
            return ((PaneState) element).getChildren().toArray();
        }

        public Object[] getElements(Object element) {
            return elements.toArray();
        }

        public boolean hasChildren(Object element) {
            return ((PaneState) element).hasChildren();
        }

        public Object getParent(Object element) {
            return ((PaneState) element).getParentPaneState();
        }

        public void dispose() {
        }

        @SuppressWarnings("unchecked")
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            elements = (List<PaneState>) newInput;
        }
    }

    private TreeViewer treeViewer;
    private MultiPaneEditor editor;
    private Font font;
    private Color greyColor;
    private Action showPaneAction;
    private Action removeWithChildrenAction;
    private Action closePaneAction;
    private Action closeWithChildrenAction;
    private Action addToCompareBasketAction;

    public NavigatorViewPage(MultiPaneEditor editor) {
        super();
        this.editor = editor;
    }

    public void createControl(Composite parent) {
        treeViewer = new TreeViewer(parent);
        createContextMenu(treeViewer.getTree());
        AccessibleCompositeAdapter.access(treeViewer.getTree());

        treeViewer.setContentProvider(new NavigatorContentProvider());
        treeViewer.setLabelProvider(new NavigatorLabelProvider());
        treeViewer.addDoubleClickListener(this);
        editor.getNavigatorState().addChangeStateListener(this);
        initializeFont();

        treeViewer.setInput(editor.getNavigatorState().getElements());
        treeViewer.expandAll();

        makeActions();
    }

    private void makeActions() {
        showPaneAction = new Action() {
            public void run() {
                bringToTop((IStructuredSelection) treeViewer.getSelection());
            }
        };
        showPaneAction.setText(Messages.NavigatorViewPage_Activate);
        showPaneAction.setImageDescriptor(MemoryAnalyserPlugin.getImageDescriptor(ISharedImages.SHOW_PANE));

        removeWithChildrenAction = new Action() {
            public void run() {
                close(true, true);
            }
        };
        removeWithChildrenAction.setText(Messages.NavigatorViewPage_RemoveFromList);
        removeWithChildrenAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
                .getImageDescriptor(org.eclipse.ui.ISharedImages.IMG_TOOL_DELETE));

        closePaneAction = new Action() {
            public void run() {
                close(false, false);
            }
        };
        closePaneAction.setText(Messages.NavigatorViewPage_Close);
        closePaneAction.setImageDescriptor(MemoryAnalyserPlugin.getImageDescriptor(ISharedImages.CLOSE_PANE));

        closeWithChildrenAction = new Action() {
            public void run() {
                close(false, true);
            }
        };
        closeWithChildrenAction.setText(Messages.NavigatorViewPage_CloseBranch);
        closeWithChildrenAction
                .setImageDescriptor(MemoryAnalyserPlugin.getImageDescriptor(ISharedImages.CLOSE_BRANCH));

        addToCompareBasketAction = new Action() {
            public void run() {
                addToCompareBasket((IStructuredSelection) treeViewer.getSelection());
            }
        };
        addToCompareBasketAction.setText(Messages.NavigatorViewPage_AddToCompareBasketMenuItem);
        addToCompareBasketAction.setImageDescriptor(MemoryAnalyserPlugin.getImageDescriptor(ISharedImages.COMPARE));

        Action copyAction = new Action() {
            @Override
            public void run() {
                Copy.copyToClipboard(treeViewer.getTree());
            }
        };
        getSite().getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
        getSite().getActionBars().updateActionBars();

    }

    private void close(boolean remove, boolean recursive) {
        TreeItem[] selection = treeViewer.getTree().getSelection();
        List<PaneState> selectedStates = new ArrayList<PaneState>(selection.length);
        for (TreeItem treeItem : selection) {
            if (treeItem.isDisposed())
                continue;
            PaneState state = (PaneState) treeItem.getData();
            selectedStates.add(state);
        }
        for (PaneState paneState : selectedStates) {
            closePane(paneState, remove, recursive);
        }
    }

    private void closePane(PaneState state, boolean remove, boolean recursive) {
        if (state.getType() == PaneType.COMPOSITE_CHILD) {
            CompositeHeapEditorPane composite = (CompositeHeapEditorPane) editor
                    .getEditor(state.getParentPaneState());
            if (composite != null)
                composite.closePage(state);
        } else {
            editor.closePage(state);
        }

        if (remove) {
            editor.getNavigatorState().removeEntry(state);
        }

        if (recursive) {
            List<PaneState> children = new ArrayList<PaneState>(state.getChildren());
            for (PaneState child : children)
                closePane(child, remove, true);
        }

        // last composite child closes & removes parent too
        if (state.getType() == PaneType.COMPOSITE_CHILD && !state.getParentPaneState().hasActiveChildren()) {
            closePane(state.getParentPaneState(), remove && !state.getParentPaneState().hasChildren(), false);
        }
    }

    private void initializeFont() {
        Font defaultFont = JFaceResources.getDefaultFont();
        FontDescriptor fontDescriptor = FontDescriptor.createFrom(defaultFont);
        fontDescriptor = fontDescriptor.setStyle(SWT.ITALIC);
        this.font = fontDescriptor.createFont(treeViewer.getTree().getDisplay());
        Color foreground = treeViewer.getTree().getForeground();
        Color background = treeViewer.getTree().getBackground();
        RGB grey = ColorUtil.blend(foreground.getRGB(), background.getRGB());
        this.greyColor = new Color(treeViewer.getTree().getDisplay(), grey);
    }

    private void createContextMenu(Control control) {
        MenuManager menuManager = new MenuManager();
        menuManager.setRemoveAllWhenShown(true);
        menuManager.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager menu) {
                IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
                if (selection.size() != 0)
                    editorContextMenuAboutToShow(menu, selection);
            }
        });
        Menu menu = menuManager.createContextMenu(control);
        control.setMenu(menu);
    }

    private void editorContextMenuAboutToShow(IMenuManager menu, IStructuredSelection selection) {
        menu.add(showPaneAction);
        menu.add(addToCompareBasketAction);
        menu.add(closePaneAction);
        menu.add(closeWithChildrenAction);
        menu.add(new Separator());
        menu.add(removeWithChildrenAction);

        if (selection.size() > 1) {
            boolean enabled = false;
            for (Iterator<?> i = selection.iterator(); i.hasNext();) {
                PaneState state = (PaneState) i.next();
                if (state.isActive()) {
                    enabled = true;
                    break;
                }
            }

            /*
             * check if all selected results are tables which can be added to
             * the compare basket
             */
            boolean areTables = true;
            for (Iterator<?> i = selection.iterator(); i.hasNext();) {
                PaneState state = (PaneState) i.next();
                if (!(canBeCompared(state) && (state.isActive() || state.isReproducable()))) {
                    areTables = false;
                    break;
                }
            }
            closePaneAction.setEnabled(enabled);
            showPaneAction.setEnabled(false);
            addToCompareBasketAction.setEnabled(areTables);
            closeWithChildrenAction.setEnabled(false);
        } else {
            PaneState state = (PaneState) selection.getFirstElement();

            showPaneAction.setEnabled(state.isReproducable() || state.isActive());
            addToCompareBasketAction
                    .setEnabled(canBeCompared(state) && (state.isReproducable() || state.isActive()));
            closePaneAction.setEnabled(state.isActive());
            closeWithChildrenAction.setEnabled(state.isActive());
        }
    }

    public Control getControl() {
        if (treeViewer == null)
            return null;
        return treeViewer.getControl();
    }

    public void setFocus() {
        treeViewer.getControl().setFocus();
    }

    public void update() {
        if (treeViewer != null) {
            Control control = treeViewer.getControl();
            if (control != null && !control.isDisposed()) {
                control.setRedraw(false);
                treeViewer.setInput(editor.getNavigatorState().getElements());
                treeViewer.expandAll();
                control.setRedraw(true);
            }
        }
    }

    public void doubleClick(DoubleClickEvent event) {
        ISelection selection = event.getSelection();
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection elements = (IStructuredSelection) selection;
            if (elements.size() == 1) {
                bringToTop(elements);
            }
        }
    }

    private void bringToTop(IStructuredSelection selection) {
        PaneState state = (PaneState) selection.getFirstElement();

        if (state.isActive()) {// bring to top
            if (state.getType() == PaneType.COMPOSITE_CHILD)
                state = state.getParentPaneState();
            editor.bringPageToTop(state);
        } else if (state.isReproducable()) { // reopen
            try {
                PaneType type = state.getType();
                switch (type) {
                case EDITOR: {
                    AbstractEditorPane pane = EditorPaneRegistry.instance().createNewPane(state.getIdentifier());
                    pane.setPaneState(state);
                    editor.addNewPage(pane, null, null, null);
                    break;
                }
                case QUERY: {
                    QueryExecution.executeAgain(editor, state);
                    break;
                }
                case COMPOSITE_CHILD: {
                    AbstractEditorPane parent = editor.getEditor(state.getParentPaneState());
                    if (parent == null) {
                        parent = EditorPaneRegistry.instance()
                                .createNewPane(state.getParentPaneState().getIdentifier());
                        parent.setPaneState(state.getParentPaneState());
                        editor.addNewPage(parent, null, null, null);
                    }

                    parent.initWithArgument(state);
                    break;
                }
                case COMPOSITE_PARENT:
                    // not applicable
                default:
                }
            } catch (Exception e) {
                ErrorHelper.logThrowableAndShowMessage(e);
            }
        }
    }

    private void addToCompareBasket(IStructuredSelection selection) {

        // first get the compare basket view
        IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
        if (page == null)
            return;

        IWorkbenchPart view = (CompareBasketView) page.findView(CompareBasketView.ID);
        if (view != null) {
            page.bringToTop(view);
        } else {
            try {
                view = page.showView(CompareBasketView.ID, null, IWorkbenchPage.VIEW_VISIBLE);
            } catch (PartInitException ex) {
                Logger.getLogger("org.eclipse.mat").log(Level.SEVERE, "Could not start Compare Basket View", ex); //$NON-NLS-1$ //$NON-NLS-2$
                return;
            }
        }

        // then add all selected results
        CompareBasketView compareBasket = (CompareBasketView) view;
        for (Iterator<?> i = selection.iterator(); i.hasNext();) {
            PaneState state = (PaneState) i.next();
            compareBasket.addResultToCompare(state, editor);
        }
    }

    private boolean canBeCompared(PaneState state) {
        return CompareBasketView.accepts(state, editor);
    }

    @Override
    public void init(IPageSite pageSite) {
        super.init(pageSite);
        pageSite.setSelectionProvider(this);
    }

    public void onStateChanged(PaneState state) {
        if (state == null) {
            update();
        } else {// update only this state and its children
            Control control = treeViewer.getControl();
            if (control != null && !control.isDisposed()) {
                control.setRedraw(false);
                treeViewer.refresh(state);
                treeViewer.expandToLevel(state, -1);
                control.setRedraw(true);
            }
        }
    }

    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        treeViewer.addSelectionChangedListener(listener);
    }

    public ISelection getSelection() {
        return treeViewer.getSelection();
    }

    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        treeViewer.removeSelectionChangedListener(listener);
    }

    public void setSelection(ISelection selection) {
        treeViewer.setSelection(selection);
    }

    @Override
    public void dispose() {
        editor.getNavigatorState().removeChangeStateListener(this);
        if (font != null)
            font.dispose();
        if (greyColor != null)
            greyColor.dispose();
        super.dispose();
    }
}