org.eclipse.contribution.xref.internal.ui.inplace.XReferenceInplaceDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.contribution.xref.internal.ui.inplace.XReferenceInplaceDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *     Helen Hawkins   - initial version
 *     Sian January    - removed deprecated API use in 1.3
 *******************************************************************************/
package org.eclipse.contribution.xref.internal.ui.inplace;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.contribution.xref.core.IXReferenceNode;
import org.eclipse.contribution.xref.core.XReferenceProviderManager;
import org.eclipse.contribution.xref.internal.ui.actions.DoubleClickAction;
import org.eclipse.contribution.xref.internal.ui.actions.XReferenceCustomFilterActionInplace;
import org.eclipse.contribution.xref.internal.ui.providers.TreeObject;
import org.eclipse.contribution.xref.internal.ui.providers.TreeParent;
import org.eclipse.contribution.xref.internal.ui.providers.XReferenceContentProvider;
import org.eclipse.contribution.xref.internal.ui.providers.XReferenceLabelProvider;
import org.eclipse.contribution.xref.internal.ui.text.XRefMessages;
import org.eclipse.contribution.xref.internal.ui.utils.XRefUIUtils;
import org.eclipse.contribution.xref.ui.XReferenceUIPlugin;
import org.eclipse.core.commands.Command;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.util.StringMatcher;
import org.eclipse.jdt.internal.ui.viewsupport.MemberFilter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.SWTKeySupport;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.util.Geometry;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Tracker;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.keys.IBindingService;

/**
 * Class to create and populate the inplace Cross Reference view.
 * A lot of the functionality in this class has been adapted from
 * org.eclipse.jdt.internal.ui.text.AbstractInformationControl
 */
public class XReferenceInplaceDialog {

    /**
     * Dialog constants telling whether this control can be resized or move.
     */
    public static final String STORE_DISABLE_RESTORE_SIZE = "DISABLE_RESTORE_SIZE"; //$NON-NLS-1$
    public static final String STORE_DISABLE_RESTORE_LOCATION = "DISABLE_RESTORE_LOCATION"; //$NON-NLS-1$

    /**
     * Dialog store constant for the location's x-coordinate, location's
     * y-coordinate and the size's width and height.
     */
    private static final String STORE_LOCATION_X = "location.x"; //$NON-NLS-1$
    private static final String STORE_LOCATION_Y = "location.y"; //$NON-NLS-1$
    private static final String STORE_SIZE_WIDTH = "size.width"; //$NON-NLS-1$
    private static final String STORE_SIZE_HEIGHT = "size.height"; //$NON-NLS-1$

    /**
     * The name of the dialog store's section associated with the 
     * inplace XReference view.
     */
    private final String sectionName = "org.eclipse.contribution.internal.xref.QuickXRef"; //$NON-NLS-1$

    /**
     * Fields for text matching and filtering
     */
    private Text filterText;
    private StringMatcher stringMatcher;
    private Font statusTextFont;
    private List filteredElements = new ArrayList();

    /**
     * Remembers the bounds for this information control.
     */
    private Rectangle bounds;
    private Rectangle trim;

    /**
     * Fields for view menu support.
     */
    private ToolBar toolBar;
    private MenuManager viewMenuManager;

    /**
     * Fields which are updated by the IWorkbenchWindowActionDelegate
     * to record the selection in the editor
     */
    private ISelection lastSelection;
    private IWorkbenchPart workbenchPart;

    /**
     * Fields for view toggling support - to show or hide 
     * parent crosscutting
     */
    private final String invokingCommandId = "org.eclipse.contribution.xref.show.xref"; //$NON-NLS-1$
    private boolean isShowingParentCrosscutting = false;
    private Command invokingCommand;
    private KeyAdapter keyAdapter;
    private TriggerSequence[] invokingCommandTriggerSequences;
    private Label statusField;
    private List /*IXReferenceAdapter*/ previousXRefAdapterList;

    private Action doubleClickAction;
    private Action xReferenceActionInplace;
    private boolean isDeactivateListenerActive = false;
    private Composite composite, viewMenuButtonComposite;
    private int shellStyle;
    private Listener deactivateListener;
    private Shell parentShell;
    private Shell dialogShell;
    private TreeViewer viewer;
    private XReferenceContentProvider contentProvider;
    private XReferenceLabelProvider labelProvider;

    private IKeyBindingService fKeyBindingService;
    private String[] fKeyBindingScopes;
    private IAction fShowViewMenuAction;
    private IHandlerActivation handlerActivation;

    /**
     * For testing purposes need to be able to get hold 
     * of the XReferenceInplaceDialog instance
     */
    public static XReferenceInplaceDialog dialog;

    /**
     * Constructor which takes the parent shell
     */
    public XReferenceInplaceDialog(Shell parent) {
        parentShell = parent;
        shellStyle = SWT.RESIZE;
        dialog = this;
    }

    /**
     * Open the dialog
     */
    public void open() {
        // If the dialog is already open, dispose the shell and recreate it
        if (dialogShell != null) {
            close();
        }
        // set isInplace to true after calling close
        XReferenceProviderManager.getManager().setIsInplace(true);

        if (invokingCommandId != null) {
            ICommandService commandService = (ICommandService) PlatformUI.getWorkbench()
                    .getAdapter(ICommandService.class);
            invokingCommand = commandService.getCommand(invokingCommandId);
            if (invokingCommand != null && !invokingCommand.isDefined())
                invokingCommand = null;
            else
                // Pre-fetch key sequence - do not change because scope will change later.
                getInvokingCommandKeySequences();
        }

        createShell();
        // bug 102140 - need to pass the action the shell of the inplace
        // view so that focus is returned to the inplace view when the
        // filter dialog is closed.
        xReferenceActionInplace = new XReferenceCustomFilterActionInplace(dialogShell);
        createComposites();
        filterText = createFilterText(viewMenuButtonComposite);
        // creates the drop down menu and creates the actions
        createViewMenu(viewMenuButtonComposite);
        createHorizontalSeparator(composite);
        viewer = createTreeViewer(composite, SWT.V_SCROLL | SWT.H_SCROLL);

        createStatusField(composite);
        addListenersToTree(viewer);
        // set the tab order
        viewMenuButtonComposite.setTabList(new Control[] { filterText });
        composite.setTabList(new Control[] { viewMenuButtonComposite, viewer.getTree() });

        setInfoSystemColor();
        installFilter();
        addListenersToShell();
        createContents();
        initializeBounds();
        // open the window
        dialogShell.open();
    }

    private void createShell() {
        // Create the shell
        dialogShell = new Shell(parentShell, shellStyle);

        // To handle "ESC" case
        dialogShell.addShellListener(new ShellAdapter() {
            public void shellClosed(ShellEvent event) {
                event.doit = false; // don't close now
                dispose();
            }
        });

        Display display = dialogShell.getDisplay();
        dialogShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK));

        int border = ((shellStyle & SWT.NO_TRIM) == 0) ? 0 : 1;
        dialogShell.setLayout(new BorderFillLayout(border));

    }

    private void createComposites() {
        // Composite for filter text and tree
        composite = new Composite(dialogShell, SWT.RESIZE);
        GridLayout layout = new GridLayout(1, false);
        composite.setLayout(layout);
        composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        viewMenuButtonComposite = new Composite(composite, SWT.NONE);
        layout = new GridLayout(2, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        viewMenuButtonComposite.setLayout(layout);
        viewMenuButtonComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    }

    private TreeViewer createTreeViewer(Composite parent, int style) {
        viewer = new TreeViewer(parent, SWT.SINGLE | (style & ~SWT.MULTI));
        viewer.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));

        contentProvider = new XReferenceContentProvider();
        viewer.setContentProvider(contentProvider);
        labelProvider = new XReferenceLabelProvider();
        viewer.setLabelProvider(labelProvider);
        viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);

        // adding these filters which restrict the contents of 
        // the view according to what has been typed in the 
        // text bar
        viewer.addFilter(new NamePatternFilter());
        viewer.addFilter(new MemberFilter());

        return viewer;
    }

    private void createHorizontalSeparator(Composite parent) {
        Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.LINE_DOT);
        separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    }

    private void setInfoSystemColor() {
        Display display = dialogShell.getDisplay();

        // set the foreground colour
        viewer.getTree().setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
        filterText.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
        composite.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
        viewMenuButtonComposite.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
        toolBar.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
        statusField.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));

        // set the background colour
        viewer.getTree().setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
        filterText.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
        composite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
        viewMenuButtonComposite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
        toolBar.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
        statusField.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
    }

    // --------------------- adding listeners ---------------------------

    private void addListenersToTree(TreeViewer treeViewer) {
        final Tree tree = treeViewer.getTree();
        tree.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                if (e.character == 0x1B) // ESC
                    dispose();
            }

            public void keyReleased(KeyEvent e) {
                // do nothing
            }
        });

        tree.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                // do nothing
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                gotoSelectedElement();
            }
        });

        tree.addMouseMoveListener(new MouseMoveListener() {
            TreeItem fLastItem = null;

            public void mouseMove(MouseEvent e) {
                if (tree.equals(e.getSource())) {
                    Object o = tree.getItem(new Point(e.x, e.y));
                    if (o instanceof TreeItem) {
                        if (!o.equals(fLastItem)) {
                            fLastItem = (TreeItem) o;
                            tree.setSelection(new TreeItem[] { fLastItem });
                        } else if (e.y < tree.getItemHeight() / 4) {
                            // Scroll up
                            Point p = tree.toDisplay(e.x, e.y);
                            Item item = viewer.scrollUp(p.x, p.y);
                            if (item instanceof TreeItem) {
                                fLastItem = (TreeItem) item;
                                tree.setSelection(new TreeItem[] { fLastItem });
                            }
                        } else if (e.y > tree.getBounds().height - tree.getItemHeight() / 4) {
                            // Scroll down
                            Point p = tree.toDisplay(e.x, e.y);
                            Item item = viewer.scrollDown(p.x, p.y);
                            if (item instanceof TreeItem) {
                                fLastItem = (TreeItem) item;
                                tree.setSelection(new TreeItem[] { fLastItem });
                            }
                        }
                    }
                }
            }
        });

        tree.addMouseListener(new MouseAdapter() {
            public void mouseUp(MouseEvent e) {

                if (tree.getSelectionCount() < 1)
                    return;

                if (e.button != 1)
                    return;

                if (tree.equals(e.getSource())) {
                    Object o = tree.getItem(new Point(e.x, e.y));
                    TreeItem selection = tree.getSelection()[0];
                    if (selection.equals(o)) {
                        gotoSelectedElement();
                    }
                }
            }
        });

        doubleClickAction = new DoubleClickAction(dialogShell, treeViewer);

        treeViewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                doubleClickAction.run();
                if (dialogShell != null && dialogShell.isDisposed()) {
                    dispose();
                }
            }
        });

        treeViewer.getTree().addKeyListener(getKeyAdapter());
    }

    private void addListenersToShell() {
        dialogShell.addDisposeListener(new DisposeListener() {

            public void widgetDisposed(DisposeEvent e) {
                close();
                if (statusTextFont != null && !statusTextFont.isDisposed())
                    statusTextFont.dispose();

                dialogShell = null;
                viewer = null;
                composite = null;
                filterText = null;
                statusTextFont = null;

            }
        });

        deactivateListener = new Listener() {
            /*
             * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
             */
            public void handleEvent(Event event) {
                if (isDeactivateListenerActive)
                    dispose();
            }
        };

        dialogShell.addListener(SWT.Deactivate, deactivateListener);
        isDeactivateListenerActive = true;
        dialogShell.addShellListener(new ShellAdapter() {
            /*
             * @see org.eclipse.swt.events.ShellAdapter#shellActivated(org.eclipse.swt.events.ShellEvent)
             */
            public void shellActivated(ShellEvent e) {
                if (e.widget == dialogShell && dialogShell.getShells().length == 0)
                    isDeactivateListenerActive = true;
            }
        });

        dialogShell.addControlListener(new ControlAdapter() {
            /**
             * {@inheritDoc}
             */
            public void controlMoved(ControlEvent e) {
                bounds = dialogShell.getBounds();
                if (trim != null) {
                    Point location = composite.getLocation();
                    bounds.x = bounds.x - trim.x + location.x;
                    bounds.y = bounds.y - trim.y + location.y;
                }

            }

            /**
             * {@inheritDoc}
             */
            public void controlResized(ControlEvent e) {
                bounds = dialogShell.getBounds();
                if (trim != null) {
                    Point location = composite.getLocation();
                    bounds.x = bounds.x - trim.x + location.x;
                    bounds.y = bounds.y - trim.y + location.y;
                }
            }
        });
    }

    // --------------------- creating and filling the menu ---------------------------   

    private void createViewMenu(Composite parent) {
        toolBar = new ToolBar(parent, SWT.FLAT);
        ToolItem viewMenuButton = new ToolItem(toolBar, SWT.PUSH, 0);

        GridData data = new GridData();
        data.horizontalAlignment = GridData.END;
        data.verticalAlignment = GridData.BEGINNING;
        toolBar.setLayoutData(data);

        viewMenuButton.setImage(JavaPluginImages.get(JavaPluginImages.IMG_ELCL_VIEW_MENU));
        viewMenuButton.setDisabledImage(JavaPluginImages.get(JavaPluginImages.IMG_DLCL_VIEW_MENU));
        viewMenuButton.setToolTipText(XRefMessages.XReferenceInplaceDialog_viewMenu_toolTipText);

        //Used to enable the menu to be accessed from the keyboard
        // Key binding service
        IWorkbenchPart part = JavaPlugin.getActivePage().getActivePart();
        IWorkbenchPartSite site = part.getSite();
        fKeyBindingService = site.getKeyBindingService();

        // Remember current scope and then set window context.
        fKeyBindingScopes = fKeyBindingService.getScopes();
        fKeyBindingService.setScopes(new String[] { IContextService.CONTEXT_ID_WINDOW });

        // Create show view menu action
        fShowViewMenuAction = new Action("showViewMenu") { //$NON-NLS-1$
            /*
             * @see org.eclipse.jface.action.Action#run()
             */
            public void run() {
                showViewMenu();
            }
        };
        fShowViewMenuAction.setEnabled(true);
        fShowViewMenuAction.setActionDefinitionId("org.eclipse.ui.window.showViewMenu"); //$NON-NLS-1$

        // Register action with handler service
        IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench()
                .getAdapter(IHandlerService.class);
        handlerActivation = handlerService.activateHandler(fShowViewMenuAction.getActionDefinitionId(),
                new ActionHandler(fShowViewMenuAction));

        viewMenuButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                showViewMenu();
            }
        });
    }

    private void showViewMenu() {
        isDeactivateListenerActive = false;

        Menu aMenu = getViewMenuManager().createContextMenu(dialogShell);

        Rectangle bounds = toolBar.getBounds();
        Point topLeft = new Point(bounds.x, bounds.y + bounds.height);
        topLeft = dialogShell.toDisplay(topLeft);
        aMenu.setLocation(topLeft.x, topLeft.y);

        aMenu.setVisible(true);
    }

    private MenuManager getViewMenuManager() {
        if (viewMenuManager == null) {
            viewMenuManager = new MenuManager();
            fillViewMenu(viewMenuManager);
        }
        return viewMenuManager;
    }

    private void fillViewMenu(IMenuManager viewMenu) {
        viewMenu.add(new GroupMarker("SystemMenuStart")); //$NON-NLS-1$
        viewMenu.add(new MoveAction());
        viewMenu.add(new ResizeAction());
        viewMenu.add(new RememberBoundsAction());
        viewMenu.add(new Separator("SystemMenuEnd")); //$NON-NLS-1$
        viewMenu.add(xReferenceActionInplace);
    }

    // --------------------- creating and filling the status field ---------------------------   

    private void createStatusField(Composite parent) {

        Composite comp = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout(1, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        comp.setLayout(layout);
        comp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        createHorizontalSeparator(comp);

        // Status field label
        statusField = new Label(parent, SWT.RIGHT);
        statusField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        statusField.setText(getStatusFieldText());
        Font font = statusField.getFont();
        Display display = parent.getDisplay();
        FontData[] fontDatas = font.getFontData();
        for (int i = 0; i < fontDatas.length; i++)
            fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10);
        Font statusTextFont = new Font(display, fontDatas);
        statusField.setFont(statusTextFont);
    }

    private String getStatusFieldText() {
        TriggerSequence[] sequences = getInvokingCommandKeySequences();
        if (sequences == null || sequences.length == 0)
            return ""; //$NON-NLS-1$

        String keySequence = sequences[0].format();

        if (isShowingParentCrosscutting)
            return NLS.bind(XRefMessages.XReferenceInplaceDialog_statusFieldText_hideParentCrosscutting,
                    keySequence);
        return NLS.bind(XRefMessages.XReferenceInplaceDialog_statusFieldText_showParentCrosscutting, keySequence);
    }

    private TriggerSequence[] getInvokingCommandKeySequences() {
        IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench()
                .getAdapter(IBindingService.class);
        TriggerSequence[] bindings = bindingService.getActiveBindingsFor(invokingCommandId);
        if (bindings.length > 0) {
            invokingCommandTriggerSequences = bindings;
        }
        return invokingCommandTriggerSequences;
    }

    private KeyAdapter getKeyAdapter() {
        if (keyAdapter == null) {
            keyAdapter = new KeyAdapter() {
                public void keyPressed(KeyEvent e) {
                    int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
                    KeySequence keySequence = KeySequence
                            .getInstance(SWTKeySupport.convertAcceleratorToKeyStroke(accelerator));
                    TriggerSequence[] sequences = getInvokingCommandKeySequences();
                    if (sequences == null)
                        return;
                    for (int i = 0; i < sequences.length; i++) {
                        if (sequences[i].equals(keySequence)) {
                            e.doit = false;
                            toggleShowParentCrosscutting();
                            return;
                        }
                    }
                }
            };
        }
        return keyAdapter;
    }

    public void refresh() {
        if (lastSelection != null && workbenchPart != null) {
            List xraList = null;
            if (isShowingParentCrosscutting) {
                xraList = XRefUIUtils.getXRefAdapterForSelection(workbenchPart, lastSelection, true);
            } else {
                xraList = XRefUIUtils.getXRefAdapterForSelection(workbenchPart, lastSelection, false);
            }
            if (xraList != null) {
                ISelection sel = viewer.getSelection();
                if (sel == null) {
                    sel = lastSelection;
                }
                viewer.setInput(xraList);
                XRefUIUtils.setSelection(workbenchPart, sel, viewer);
            }
        }
    }

    protected void toggleShowParentCrosscutting() {
        if (lastSelection != null && workbenchPart != null) {
            List xraList = null;
            if (!isShowingParentCrosscutting) {
                xraList = XRefUIUtils.getXRefAdapterForSelection(workbenchPart, lastSelection, true);
            } else {
                xraList = XRefUIUtils.getXRefAdapterForSelection(workbenchPart, lastSelection, false);
            }
            if (xraList != null) {
                ISelection sel = viewer.getSelection();
                if (sel == null) {
                    sel = lastSelection;
                }
                viewer.setInput(xraList);
                XRefUIUtils.setSelection(workbenchPart, sel, viewer);
            }
        }

        isShowingParentCrosscutting = !isShowingParentCrosscutting;
        updateStatusFieldText();
    }

    protected void updateStatusFieldText() {
        if (statusField != null)
            statusField.setText(getStatusFieldText());
    }

    // ----------- all to do with setting the bounds of the dialog -------------

    /**
     * Initialize the shell's bounds.
     */
    private void initializeBounds() {
        // if we don't remember the dialog bounds then reset
        // to be the defaults (behaves like inplace outline view)
        Rectangle oldBounds = restoreBounds();
        if (oldBounds != null) {
            dialogShell.setBounds(oldBounds);
            return;
        }
        dialogShell.setBounds(getDefaultBounds());
    }

    public Rectangle getDefaultBounds() {
        GC gc = new GC(composite);
        gc.setFont(composite.getFont());
        int width = gc.getFontMetrics().getAverageCharWidth();
        int height = gc.getFontMetrics().getHeight();
        gc.dispose();

        Point size = new Point(60 * width, 10 * height);
        Point location = getDefaultLocation(size);
        return new Rectangle(location.x, location.y, size.x, size.y);
    }

    private Point getDefaultLocation(Point initialSize) {
        Monitor monitor = dialogShell.getDisplay().getPrimaryMonitor();
        if (parentShell != null) {
            monitor = parentShell.getMonitor();
        }

        Rectangle monitorBounds = monitor.getClientArea();
        Point centerPoint;
        if (parentShell != null) {
            centerPoint = Geometry.centerPoint(parentShell.getBounds());
        } else {
            centerPoint = Geometry.centerPoint(monitorBounds);
        }

        return new Point(centerPoint.x - (initialSize.x / 2),
                Math.max(monitorBounds.y, Math.min(centerPoint.y - (initialSize.y * 2 / 3),
                        monitorBounds.y + monitorBounds.height - initialSize.y)));
    }

    private IDialogSettings getDialogSettings() {
        IDialogSettings settings = XReferenceUIPlugin.getDefault().getDialogSettings().getSection(sectionName);
        if (settings == null)
            settings = XReferenceUIPlugin.getDefault().getDialogSettings().addNewSection(sectionName);

        return settings;
    }

    private void storeBounds() {
        IDialogSettings dialogSettings = getDialogSettings();

        boolean controlRestoresSize = !dialogSettings.getBoolean(STORE_DISABLE_RESTORE_SIZE);
        boolean controlRestoresLocation = !dialogSettings.getBoolean(STORE_DISABLE_RESTORE_LOCATION);

        if (bounds == null)
            return;

        if (controlRestoresSize) {
            dialogSettings.put(STORE_SIZE_WIDTH, bounds.width);
            dialogSettings.put(STORE_SIZE_HEIGHT, bounds.height);
        }
        if (controlRestoresLocation) {
            dialogSettings.put(STORE_LOCATION_X, bounds.x);
            dialogSettings.put(STORE_LOCATION_Y, bounds.y);
        }
    }

    private Rectangle restoreBounds() {

        IDialogSettings dialogSettings = getDialogSettings();

        boolean controlRestoresSize = !dialogSettings.getBoolean(STORE_DISABLE_RESTORE_SIZE);
        boolean controlRestoresLocation = !dialogSettings.getBoolean(STORE_DISABLE_RESTORE_LOCATION);

        Rectangle bounds = new Rectangle(-1, -1, -1, -1);

        if (controlRestoresSize) {
            try {
                bounds.width = dialogSettings.getInt(STORE_SIZE_WIDTH);
                bounds.height = dialogSettings.getInt(STORE_SIZE_HEIGHT);
            } catch (NumberFormatException ex) {
                bounds.width = -1;
                bounds.height = -1;
            }
        }

        if (controlRestoresLocation) {
            try {
                bounds.x = dialogSettings.getInt(STORE_LOCATION_X);
                bounds.y = dialogSettings.getInt(STORE_LOCATION_Y);
            } catch (NumberFormatException ex) {
                bounds.x = -1;
                bounds.y = -1;
            }
        }

        // sanity check
        if (bounds.x == -1 && bounds.y == -1 && bounds.width == -1 && bounds.height == -1) {
            return null;
        }

        Rectangle maxBounds = null;
        if (dialogShell != null && !dialogShell.isDisposed())
            maxBounds = dialogShell.getDisplay().getBounds();
        else {
            // fallback
            Display display = Display.getCurrent();
            if (display == null)
                display = Display.getDefault();
            if (display != null && !display.isDisposed())
                maxBounds = display.getBounds();
        }

        if (bounds.width > -1 && bounds.height > -1) {
            if (maxBounds != null) {
                bounds.width = Math.min(bounds.width, maxBounds.width);
                bounds.height = Math.min(bounds.height, maxBounds.height);
            }
            // Enforce an absolute minimal size
            bounds.width = Math.max(bounds.width, 30);
            bounds.height = Math.max(bounds.height, 30);
        }

        if (bounds.x > -1 && bounds.y > -1 && maxBounds != null) {
            bounds.x = Math.max(bounds.x, maxBounds.x);
            bounds.y = Math.max(bounds.y, maxBounds.y);

            if (bounds.width > -1 && bounds.height > -1) {
                bounds.x = Math.min(bounds.x, maxBounds.width - bounds.width);
                bounds.y = Math.min(bounds.y, maxBounds.height - bounds.height);
            }
        }
        return bounds;
    }

    // ----------- all to do with filtering text

    private Text createFilterText(Composite parent) {
        filterText = new Text(parent, SWT.NONE);

        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        GC gc = new GC(parent);
        gc.setFont(parent.getFont());
        FontMetrics fontMetrics = gc.getFontMetrics();
        gc.dispose();

        data.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, 1);
        data.horizontalAlignment = GridData.FILL;
        data.verticalAlignment = GridData.CENTER;
        filterText.setLayoutData(data);

        filterText.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                if (e.keyCode == 0x0D) // return
                    gotoSelectedElement();
                if (e.keyCode == SWT.ARROW_DOWN)
                    viewer.getTree().setFocus();
                if (e.keyCode == SWT.ARROW_UP)
                    viewer.getTree().setFocus();
                if (e.character == 0x1B) // ESC
                    dispose();
            }

            public void keyReleased(KeyEvent e) {
                // do nothing
            }
        });

        filterText.addKeyListener(getKeyAdapter());
        return filterText;
    }

    private void gotoSelectedElement() {
        Object selectedElement = getSelectedElement();
        if (selectedElement instanceof IStructuredSelection) {
            Object sel = (IStructuredSelection) selectedElement;
            Object data = ((TreeObject) sel).getData();
            if (data != null) {
                if (data instanceof IXReferenceNode) {
                    XRefUIUtils.revealInEditor(((IXReferenceNode) data).getJavaElement());
                } else if (data instanceof IJavaElement) {
                    XRefUIUtils.revealInEditor((IJavaElement) data);
                }
                dispose();
            }
        } else if (selectedElement instanceof TreeObject) {
            TreeObject item = (TreeObject) selectedElement;
            Object data = item.getData();
            if (data != null) {
                if (data instanceof IXReferenceNode) {
                    XRefUIUtils.revealInEditor(((IXReferenceNode) data).getJavaElement());
                } else if (data instanceof IJavaElement) {
                    XRefUIUtils.revealInEditor((IJavaElement) data);
                }
                dispose();
            }
        }
    }

    private Object getSelectedElement() {
        if (viewer == null)
            return null;
        return ((IStructuredSelection) viewer.getSelection()).getFirstElement();
    }

    private void installFilter() {
        filterText.setText(""); //$NON-NLS-1$

        filterText.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                String text = ((Text) e.widget).getText();
                int length = text.length();
                if (length > 0 && text.charAt(length - 1) != '*') {
                    text = text + '*';
                }
                setMatcherString(text);
            }
        });
    }

    private void setMatcherString(String pattern) {
        if (pattern.length() == 0) {
            stringMatcher = null;
        } else {
            boolean ignoreCase = pattern.toLowerCase().equals(pattern);
            stringMatcher = new StringMatcher(pattern, ignoreCase, false);
        }
        stringMatcherUpdated();
    }

    private void stringMatcherUpdated() {
        filteredElements.clear();
        // refresh viewer to refilter
        viewer.getControl().setRedraw(false);
        viewer.refresh();
        viewer.expandAll();
        selectFirstMatch();
        viewer.getControl().setRedraw(true);
    }

    private void selectFirstMatch() {
        Tree tree = viewer.getTree();
        Object element = findElement(tree.getItems());
        if (element != null)
            viewer.setSelection(new StructuredSelection(element), true);
        else
            viewer.setSelection(StructuredSelection.EMPTY);
    }

    private Object findElement(TreeItem[] items) {
        ILabelProvider labelProvider = (ILabelProvider) viewer.getLabelProvider();
        for (int i = 0; i < items.length; i++) {
            Object o = items[i].getData();
            TreeParent treeParent = null;
            TreeObject treeObject = null;
            if (o instanceof TreeParent) {
                treeParent = (TreeParent) o;
            } else if (o instanceof TreeObject) {
                treeObject = (TreeObject) o;
            }
            Object element = null;
            if (treeParent == null) {
                element = treeObject;
            } else {
                element = treeParent;
            }
            if (stringMatcher == null)
                return element;

            if (element != null) {
                String label = labelProvider.getText(element);
                if (stringMatcher.match(label))
                    return element;
            }

            element = findElement(items[i].getItems());
            if (element != null)
                return element;
        }
        return null;
    }

    protected class NamePatternFilter extends ViewerFilter {

        public NamePatternFilter() {
        }

        /*
         * (non-Javadoc) Method declared on ViewerFilter.
         */
        public boolean select(Viewer viewer, Object parentElement, Object element) {
            StringMatcher matcher = getMatcher();
            if (matcher == null || !(viewer instanceof TreeViewer))
                return true;
            TreeViewer treeViewer = (TreeViewer) viewer;

            String matchName = ((ILabelProvider) treeViewer.getLabelProvider()).getText(element);
            if (matchName != null && matcher.match(matchName)) {
                if (element instanceof TreeParent) {
                    filteredElements.add(element);
                }
                return true;
            }
            return hasUnfilteredChild(treeViewer, element);
        }

        private boolean hasUnfilteredChild(TreeViewer viewer, Object element) {
            if (element instanceof TreeParent) {
                Object[] children = ((ITreeContentProvider) viewer.getContentProvider()).getChildren(element);
                for (int i = 0; i < children.length; i++) {

                    if (select(viewer, element, children[i])) {
                        return true;
                    }
                }
            }
            return false;
        }

        /*
         * (non-Javadoc) Method declared on ViewerFilter.
         */
        public Object[] filter(Viewer viewer, Object parent, Object[] elements) {
            int size = elements.length;
            ArrayList out = new ArrayList(size);
            for (int i = 0; i < size; ++i) {
                Object element = elements[i];
                if (filteredElements.contains(parent)) {
                    if (element instanceof TreeParent) {
                        filteredElements.add(element);
                    }
                    out.add(element);
                } else if (filteredElements.contains(element)) {
                    out.add(element);
                } else if (select(viewer, parent, element)) {
                    out.add(element);
                }
            }
            return out.toArray();
        }
    }

    private StringMatcher getMatcher() {
        return stringMatcher;
    }

    /**
     * Static inner class which sets the layout for the inplace view. Without
     * this, the inplace view will not be populated.
     * 
     * @see org.eclipse.jdt.internal.ui.text.AbstractInformationControl
     */
    private static class BorderFillLayout extends Layout {

        /** The border widths. */
        final int fBorderSize;

        /**
         * Creates a fill layout with a border.
         */
        public BorderFillLayout(int borderSize) {
            if (borderSize < 0)
                throw new IllegalArgumentException();
            fBorderSize = borderSize;
        }

        /**
         * Returns the border size.
         */
        public int getBorderSize() {
            return fBorderSize;
        }

        /*
         * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite,
         *      int, int, boolean)
         */
        protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {

            Control[] children = composite.getChildren();
            Point minSize = new Point(0, 0);

            if (children != null) {
                for (int i = 0; i < children.length; i++) {
                    Point size = children[i].computeSize(wHint, hHint, flushCache);
                    minSize.x = Math.max(minSize.x, size.x);
                    minSize.y = Math.max(minSize.y, size.y);
                }
            }

            minSize.x += fBorderSize * 2 + 3;
            minSize.y += fBorderSize * 2;

            return minSize;
        }

        /*
         * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite,
         *      boolean)
         */
        protected void layout(Composite composite, boolean flushCache) {

            Control[] children = composite.getChildren();
            Point minSize = new Point(composite.getClientArea().width, composite.getClientArea().height);

            if (children != null) {
                for (int i = 0; i < children.length; i++) {
                    Control child = children[i];
                    child.setSize(minSize.x - fBorderSize * 2, minSize.y - fBorderSize * 2);
                    child.setLocation(fBorderSize, fBorderSize);
                }
            }
        }
    }

    // ---------- shuts down the dialog ---------------

    /**
     * Close the dialog 
     */
    public void close() {
        storeBounds();
        toolBar = null;
        viewMenuManager = null;
        labelProvider.dispose();
        contentProvider.dispose();
        XReferenceProviderManager.getManager().setIsInplace(false);
    }

    public void dispose() {
        filterText = null;
        if (dialogShell != null) {
            if (!dialogShell.isDisposed())
                dialogShell.dispose();
            dialogShell = null;
            parentShell = null;
            viewer = null;
            composite = null;
            dialog = null;
        }
        IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench()
                .getAdapter(IHandlerService.class);
        handlerService.deactivateHandler(handlerActivation);

        // Restore editor's key binding scope
        if (fKeyBindingScopes != null && fKeyBindingService != null) {
            fKeyBindingService.setScopes(fKeyBindingScopes);
            fKeyBindingScopes = null;
            fKeyBindingService = null;
        }

        XReferenceProviderManager.getManager().setIsInplace(false);
    }

    // ------------------ moving actions --------------------------

    /**
     * Move action for the dialog.
     */
    private class MoveAction extends Action {

        MoveAction() {
            super(XRefMessages.XReferenceInplaceDialog_viewMenu_move_label, IAction.AS_PUSH_BUTTON);
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.action.IAction#run()
         */
        public void run() {
            performTrackerAction(SWT.NONE);
            isDeactivateListenerActive = true;
        }

    }

    /**
     * Remember bounds action for the dialog.
     */
    private class RememberBoundsAction extends Action {

        RememberBoundsAction() {
            super(XRefMessages.XReferenceInplaceDialog_viewMenu_rememberBounds_label, IAction.AS_CHECK_BOX);
            setChecked(!getDialogSettings().getBoolean(STORE_DISABLE_RESTORE_LOCATION));
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.action.IAction#run()
         */
        public void run() {
            IDialogSettings settings = getDialogSettings();

            boolean newValue = !isChecked();
            // store new value
            settings.put(STORE_DISABLE_RESTORE_LOCATION, newValue);
            settings.put(STORE_DISABLE_RESTORE_SIZE, newValue);

            isDeactivateListenerActive = true;
        }
    }

    /**
     * Resize action for the dialog.
     */
    private class ResizeAction extends Action {

        ResizeAction() {
            super(XRefMessages.XReferenceInplaceDialog_viewMenu_resize_label, IAction.AS_PUSH_BUTTON);
        }

        /*
         * @see org.eclipse.jface.action.Action#run()
         */
        public void run() {
            performTrackerAction(SWT.RESIZE);
            isDeactivateListenerActive = true;
        }

    }

    /**
     * Perform the requested tracker action (resize or move).
     * 
     * @param style
     *            The track style (resize or move).
     */
    private void performTrackerAction(int style) {
        Tracker tracker = new Tracker(dialogShell.getDisplay(), style);
        tracker.setStippled(true);
        Rectangle[] r = new Rectangle[] { dialogShell.getBounds() };
        tracker.setRectangles(r);

        if (tracker.open()) {
            dialogShell.setBounds(tracker.getRectangles()[0]);

        }
    }

    // -------------------- all to do with the contents of the view --------------------

    private void createContents() {
        if (lastSelection != null && workbenchPart != null) {
            previousXRefAdapterList = XRefUIUtils.getXRefAdapterForSelection(workbenchPart, lastSelection, false);

            if (previousXRefAdapterList != null) {
                viewer.setInput(previousXRefAdapterList);
                XRefUIUtils.setSelection(workbenchPart, lastSelection, viewer);
            }
        }
        filterText.setText(""); //$NON-NLS-1$
    }

    /**
     * @param lastSelection The lastSelection to set.
     */
    public void setLastSelection(ISelection lastSelection) {
        this.lastSelection = lastSelection;
    }

    /**
     * @param workbenchPart The workbenchPart to set.
     */
    public void setWorkbenchPart(IWorkbenchPart workbenchPart) {
        this.workbenchPart = workbenchPart;
    }

    public boolean isOpen() {
        return dialogShell != null;
    }

    // -------- the following methods are all for testing purposes --------

    /**
     * Returns the dialog for the xref inplace view - this method is for testing
     * purposes and not part of the published API.
     */
    public static XReferenceInplaceDialog getInplaceDialog() {
        return dialog;
    }

    /**
     * Returns the shell for the xref inplace view - this method is for testing
     * purposes and not part of the published API.
     */
    public Shell getShell() {
        return dialogShell;
    }

    /**
     * Returns the action for the xref inplace view - this method is for testing
     * purposes and not part of the published API.
     */
    public Action getCustomFilterActionInplace() {
        return xReferenceActionInplace;
    }

    /**
     * Returns the tree viewer for the xref inplace view - this method is for testing
     * purposes and not part of the published API.
     */
    public TreeViewer getTreeViewer() {
        return viewer;
    }
}