org.eclipse.cdt.internal.ui.search.PDOMSearchViewPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.cdt.internal.ui.search.PDOMSearchViewPage.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2010 QNX Software Systems 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:
 *     QNX - Initial API and implementation
 *     Ed Swartz (Nokia)
 *     Andrey Eremchenko (LEDAS)
 *     Sergey Prigogin (Google)
 *******************************************************************************/
package org.eclipse.cdt.internal.ui.search;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
import org.eclipse.search.ui.text.Match;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.texteditor.ITextEditor;

import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IndexLocationFactory;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.ui.CUIPlugin;

import org.eclipse.cdt.internal.ui.util.EditorUtility;
import org.eclipse.cdt.internal.ui.viewsupport.ColoringLabelProvider;

/**
 * Implementation of the search view page for index based searches.
 */
public class PDOMSearchViewPage extends AbstractTextSearchViewPage {
    public static final int LOCATION_COLUMN_INDEX = 0;
    public static final int DEFINITION_COLUMN_INDEX = 1;
    public static final int MATCH_COLUMN_INDEX = 2;

    private static final String[] fColumnLabels = new String[] {
            CSearchMessages.PDOMSearchViewPageLocationColumn_label,
            CSearchMessages.PDOMSearchViewPageDefinitionColumn_label,
            CSearchMessages.PDOMSearchViewPageMatchColumn_label };

    private static final String KEY_LOCATION_COLUMN_WIDTH = "locationColumnWidth"; //$NON-NLS-1$
    private static final String KEY_DEFINITION_COLUMN_WIDTH = "definitionColumnWidth"; //$NON-NLS-1$
    private static final String KEY_MATCH_COLUMN_WIDTH = "matchColumnWidth"; //$NON-NLS-1$
    private static final String KEY_SHOW_ENCLOSING_DEFINITIONS = "showEnclosingDefinitions"; //$NON-NLS-1$

    private IPDOMSearchContentProvider contentProvider;
    private boolean fShowEnclosingDefinitions;
    private ShowEnclosingDefinitionsAction fShowEnclosingDefinitionsAction;
    private int[] fColumnWidths = { 300, 150, 300 };

    private class ShowEnclosingDefinitionsAction extends Action {
        public ShowEnclosingDefinitionsAction() {
            super(CSearchMessages.PDOMSearchViewPage_ShowEnclosingDefinitions_actionLabel, SWT.CHECK);
            setChecked(fShowEnclosingDefinitions);
        }

        @Override
        public void run() {
            setShowEnclosingDefinitions(isChecked());
        }
    }

    public PDOMSearchViewPage(int supportedLayouts) {
        super(supportedLayouts);
    }

    public PDOMSearchViewPage() {
        super();
    }

    @Override
    public void init(IPageSite pageSite) {
        super.init(pageSite);
        fShowEnclosingDefinitionsAction = new ShowEnclosingDefinitionsAction();
        IMenuManager menuManager = pageSite.getActionBars().getMenuManager();
        menuManager.add(fShowEnclosingDefinitionsAction);
        menuManager.updateAll(true);
        pageSite.getActionBars().updateActionBars();
    }

    @Override
    public void restoreState(IMemento memento) {
        super.restoreState(memento);
        IDialogSettings settings = getSettings();
        boolean showEnclosingDefinitions = true;
        if (settings.get(KEY_SHOW_ENCLOSING_DEFINITIONS) != null)
            showEnclosingDefinitions = settings.getBoolean(KEY_SHOW_ENCLOSING_DEFINITIONS);
        if (memento != null) {
            Boolean value = memento.getBoolean(KEY_SHOW_ENCLOSING_DEFINITIONS);
            if (value != null)
                showEnclosingDefinitions = value.booleanValue();
            String[] keys = { KEY_LOCATION_COLUMN_WIDTH, KEY_DEFINITION_COLUMN_WIDTH, KEY_MATCH_COLUMN_WIDTH };
            for (int i = 0; i < keys.length; i++) {
                Integer width = memento.getInteger(keys[i]);
                if (width == null)
                    continue;
                if (width > 0)
                    fColumnWidths[i] = width;
            }
        }
        setShowEnclosingDefinitions(showEnclosingDefinitions);
    }

    @Override
    public void saveState(IMemento memento) {
        super.saveState(memento);
        saveColumnWidths();
        memento.putInteger(KEY_DEFINITION_COLUMN_WIDTH, fColumnWidths[DEFINITION_COLUMN_INDEX]);
        memento.putInteger(KEY_LOCATION_COLUMN_WIDTH, fColumnWidths[LOCATION_COLUMN_INDEX]);
        memento.putInteger(KEY_MATCH_COLUMN_WIDTH, fColumnWidths[MATCH_COLUMN_INDEX]);
        memento.putBoolean(KEY_SHOW_ENCLOSING_DEFINITIONS, fShowEnclosingDefinitions);
    }

    public void setShowEnclosingDefinitions(boolean showEnclosingDefinitions) {
        if (fShowEnclosingDefinitions == showEnclosingDefinitions)
            return;
        fShowEnclosingDefinitions = showEnclosingDefinitions;
        getSettings().put(KEY_SHOW_ENCLOSING_DEFINITIONS, fShowEnclosingDefinitions);
        if (fShowEnclosingDefinitionsAction.isChecked() != showEnclosingDefinitions)
            fShowEnclosingDefinitionsAction.setChecked(showEnclosingDefinitions);
        StructuredViewer viewer = getViewer();
        if (viewer instanceof TableViewer) {
            TableViewer tableViewer = (TableViewer) viewer;
            TableColumn tableColumn = tableViewer.getTable().getColumn(DEFINITION_COLUMN_INDEX);
            if (fShowEnclosingDefinitions) {
                tableColumn.setWidth(fColumnWidths[DEFINITION_COLUMN_INDEX]);
                tableColumn.setResizable(true);
            } else {
                fColumnWidths[DEFINITION_COLUMN_INDEX] = tableColumn.getWidth();
                tableColumn.setWidth(0);
                tableColumn.setResizable(false);
            }
        }
        if (viewer != null)
            viewer.refresh();
    }

    public boolean isShowEnclosingDefinitions() {
        return fShowEnclosingDefinitions;
    }

    @Override
    protected void elementsChanged(Object[] objects) {
        if (contentProvider != null)
            contentProvider.elementsChanged(objects);
    }

    @Override
    protected void clear() {
        if (contentProvider != null)
            contentProvider.clear();
    }

    /**
     * Supply a sorter for the list and tree content providers to supply some order to the
     * large numbers of matches that may result.  
     * <p>
     * This sorter categorizes the different kinds of ICElement matches (as well as IStatus
     * messages and External Files groups) to place them in groups.  The items within a
     * category are sorted in the default way {@link ViewerSorter#compare(Viewer, Object, Object)} works,
     * by comparing text labels.
     * <p>
     * A potential concern here is that, in sorting the elements by name, the user may 
     * find himself randomly jumping around a file when navigating search results in order.
     * As this only happens when a search matches different identifiers or identifiers of
     * different types, and since the user can use a textual search within a file to navigate
     * the same results (ignoring extraneous hits in comments or disabled code), I argue it's not
     * a big deal.  Furthermore, usually it would be a wildcard search that would result in 
     * this situation -- indicating the user doesn't know the identifier and wants to find it using
     * search.  In such a case, a sorted list of results in much more friendly to navigate.
     * @author eswartz
     *
     */
    private class SearchViewerComparator extends ViewerComparator {
        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
         */
        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            if (e1 instanceof LineSearchElement && e2 instanceof LineSearchElement) {
                LineSearchElement l1 = (LineSearchElement) e1;
                LineSearchElement l2 = (LineSearchElement) e2;
                if (viewer instanceof TableViewer) {
                    String p1 = l1.getLocation().getURI().getPath();
                    String p2 = l2.getLocation().getURI().getPath();
                    int cmp = p1.compareTo(p2);
                    if (cmp != 0)
                        return cmp;
                }
                return l1.getLineNumber() - l2.getLineNumber();
            }
            return super.compare(viewer, e1, e2);
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object)
         */
        @Override
        public int category(Object element) {
            // place status messages first
            if (element instanceof IStatus) {
                return -1000;
            }

            // keep elements of the same type together
            if (element instanceof TypeInfoSearchElement) {
                TypeInfoSearchElement searchElement = (TypeInfoSearchElement) element;
                int type = searchElement.getTypeInfo().getCElementType();
                // handle unknown types
                if (type < 0) {
                    type = 0;
                }
                return type;
            } else if (element instanceof ICElement) {
                int type = ((ICElement) element).getElementType();
                // handle unknown types
                if (type < 0) {
                    type = 0;
                }
                return Math.min(Math.max(0, type), 900);
            }

            // place external folders next to last
            if (element instanceof IPath || element instanceof IIndexFileLocation) {
                return 999;
            }

            // place external file matches last
            if (element == IPDOMSearchContentProvider.URI_CONTAINER) {
                return 1000;
            }

            return 2000;
        }
    }

    @Override
    protected void configureTreeViewer(TreeViewer viewer) {
        contentProvider = new PDOMSearchTreeContentProvider(this);
        viewer.setComparator(new SearchViewerComparator());
        viewer.setContentProvider((PDOMSearchTreeContentProvider) contentProvider);
        PDOMSearchTreeLabelProvider innerLabelProvider = new PDOMSearchTreeLabelProvider(this);
        ColoringLabelProvider labelProvider = new ColoringLabelProvider(innerLabelProvider);
        viewer.setLabelProvider(labelProvider);
    }

    @Override
    protected void configureTableViewer(TableViewer viewer) {
        createColumns(viewer);
        contentProvider = new PDOMSearchListContentProvider(this);
        viewer.setComparator(new SearchViewerComparator());
        viewer.setContentProvider((PDOMSearchListContentProvider) contentProvider);
    }

    @Override
    protected TableViewer createTableViewer(Composite parent) {
        TableViewer tableViewer = new TableViewer(parent,
                SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
        tableViewer.getControl().addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                saveColumnWidths();
            }
        });
        return tableViewer;
    }

    private void saveColumnWidths() {
        StructuredViewer viewer = getViewer();
        if (viewer instanceof TableViewer) {
            TableViewer tableViewer = (TableViewer) viewer;
            for (int i = 0; i < fColumnLabels.length; i++) {
                if (i == DEFINITION_COLUMN_INDEX && !fShowEnclosingDefinitions)
                    continue;
                fColumnWidths[i] = tableViewer.getTable().getColumn(i).getWidth();
            }
        }
    }

    private void createColumns(TableViewer viewer) {
        for (int i = 0; i < fColumnLabels.length; i++) {
            TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
            viewerColumn.setLabelProvider(new PDOMSearchListLabelProvider(this, i));
            TableColumn tableColumn = viewerColumn.getColumn();
            tableColumn.setText(fColumnLabels[i]);
            tableColumn.setWidth(fColumnWidths[i]);
            tableColumn.setResizable(true);
            tableColumn.setMoveable(false);
            if (i == DEFINITION_COLUMN_INDEX && !fShowEnclosingDefinitions) {
                tableColumn.setWidth(0);
                tableColumn.setResizable(false);
            }
        }
        Table table = viewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
    }

    @Override
    protected void showMatch(Match match, int currentOffset, int currentLength, boolean activate)
            throws PartInitException {
        if (!(match instanceof PDOMSearchMatch))
            return;

        try {
            Object element = ((PDOMSearchMatch) match).getElement();
            IIndexFileLocation ifl = ((PDOMSearchElement) element).getLocation();
            IPath path = IndexLocationFactory.getPath(ifl);
            IEditorPart editor = EditorUtility.openInEditor(path, null, activate);
            if (editor instanceof ITextEditor) {
                ITextEditor textEditor = (ITextEditor) editor;
                textEditor.selectAndReveal(currentOffset, currentLength);
            }
        } catch (CoreException e) {
            CUIPlugin.log(e);
        }
    }

    @Override
    public StructuredViewer getViewer() {
        return super.getViewer();
    }
}