org.eclipse.jface.viewers.OwnerDrawLabelProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jface.viewers.OwnerDrawLabelProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.jface.viewers;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

/**
 * OwnerDrawLabelProvider is an abstract implementation of a label provider that
 * handles custom draw.
 *
 * <p>
 * <b>This class is intended to be subclassed by implementors.</b>
 * </p>
 *
 * @since 3.3
 *
 */
public abstract class OwnerDrawLabelProvider extends CellLabelProvider {

    static class OwnerDrawListener implements Listener {
        Set<ViewerColumn> enabledColumns = new HashSet<>();
        int enabledGlobally = 0;
        private ColumnViewer viewer;

        OwnerDrawListener(ColumnViewer viewer) {
            this.viewer = viewer;
        }

        @Override
        public void handleEvent(Event event) {
            ViewerColumn column = viewer.getViewerColumn(event.index);
            if (column != null && (enabledGlobally > 0 || enabledColumns.contains(column))) {
                CellLabelProvider provider = column.getLabelProvider();
                if (provider instanceof OwnerDrawLabelProvider) {
                    Object element = event.item.getData();
                    OwnerDrawLabelProvider ownerDrawProvider = (OwnerDrawLabelProvider) provider;
                    switch (event.type) {
                    case SWT.MeasureItem:
                        ownerDrawProvider.measure(event, element);
                        break;
                    case SWT.PaintItem:
                        ownerDrawProvider.paint(event, element);
                        break;
                    case SWT.EraseItem:
                        ownerDrawProvider.erase(event, element);
                        break;
                    }
                }
            }
        }
    }

    private static final String OWNER_DRAW_LABEL_PROVIDER_LISTENER = "owner_draw_label_provider_listener"; //$NON-NLS-1$

    /**
     * Set up the owner draw callbacks for the viewer.
     *
     * @param viewer
     *            the viewer the owner draw is set up
     *
     * @deprecated Since 3.4, the default implementation of
     *             {@link CellLabelProvider#initialize(ColumnViewer, ViewerColumn)}
     *             in this class will set up the necessary owner draw callbacks
     *             automatically. Calls to this method can be removed.
     */
    @Deprecated
    public static void setUpOwnerDraw(final ColumnViewer viewer) {
        getOrCreateOwnerDrawListener(viewer).enabledGlobally++;
    }

    private static OwnerDrawListener getOrCreateOwnerDrawListener(final ColumnViewer viewer) {
        Control control = viewer.getControl();
        OwnerDrawListener listener = (OwnerDrawListener) control.getData(OWNER_DRAW_LABEL_PROVIDER_LISTENER);
        if (listener == null) {
            listener = new OwnerDrawListener(viewer);
            control.setData(OWNER_DRAW_LABEL_PROVIDER_LISTENER, listener);
            control.addListener(SWT.MeasureItem, listener);
            control.addListener(SWT.EraseItem, listener);
            control.addListener(SWT.PaintItem, listener);
        }
        return listener;
    }

    /**
     * Create a new instance of the receiver based on a column viewer.
     *
     */
    public OwnerDrawLabelProvider() {

    }

    @Override
    public void dispose(ColumnViewer viewer, ViewerColumn column) {
        if (!viewer.getControl().isDisposed()) {
            setOwnerDrawEnabled(viewer, column, false);
        }
        super.dispose(viewer, column);
    }

    /**
     * This implementation of
     * {@link CellLabelProvider#initialize(ColumnViewer, ViewerColumn)}
     * delegates to {@link #initialize(ColumnViewer, ViewerColumn, boolean)}
     * with a value of <code>true</code> for <code>enableOwnerDraw</code>.
     * Subclasses may override this method but should either call the super
     * implementation or, alternatively,
     * {@link #initialize(ColumnViewer, ViewerColumn, boolean)}.
     */
    @Override
    protected void initialize(ColumnViewer viewer, ViewerColumn column) {
        this.initialize(viewer, column, true);
    }

    /**
     * May be called from subclasses that override
     * {@link #initialize(ColumnViewer, ViewerColumn)} but want to customize
     * whether owner draw will be enabled. This method calls
     * <code>super.initialize(ColumnViewer, ViewerColumn)</code>, and then
     * enables or disables owner draw by calling
     * {@link #setOwnerDrawEnabled(ColumnViewer, ViewerColumn, boolean)}.
     *
     * @param viewer
     *            the viewer
     * @param column
     *            the column, or <code>null</code> if a column is not
     *            available.
     * @param enableOwnerDraw
     *            <code>true</code> if owner draw should be enabled for the
     *            given viewer and column, <code>false</code> otherwise.
     *
     * @since 3.4
     */
    final protected void initialize(ColumnViewer viewer, ViewerColumn column, boolean enableOwnerDraw) {
        super.initialize(viewer, column);
        setOwnerDrawEnabled(viewer, column, enableOwnerDraw);
    }

    @Override
    public void update(ViewerCell cell) {
        // Force a redraw
        Rectangle cellBounds = cell.getBounds();
        cell.getControl().redraw(cellBounds.x, cellBounds.y, cellBounds.width, cellBounds.height, true);

    }

    /**
     * Handle the erase event. The default implementation colors the background
     * of selected areas with {@link SWT#COLOR_LIST_SELECTION} and foregrounds
     * with {@link SWT#COLOR_LIST_SELECTION_TEXT}. Note that this
     * implementation causes non-native behavior on some platforms. Subclasses
     * should override this method and <b>not</b> call the super
     * implementation.
     *
     * @param event
     *            the erase event
     * @param element
     *            the model object
     * @see SWT#EraseItem
     * @see SWT#COLOR_LIST_SELECTION
     * @see SWT#COLOR_LIST_SELECTION_TEXT
     */
    protected void erase(Event event, Object element) {

        Rectangle bounds = event.getBounds();
        if ((event.detail & SWT.SELECTED) != 0) {

            Color oldForeground = event.gc.getForeground();
            Color oldBackground = event.gc.getBackground();

            event.gc.setBackground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION));
            event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
            event.gc.fillRectangle(bounds);
            /* restore the old GC colors */
            event.gc.setForeground(oldForeground);
            event.gc.setBackground(oldBackground);
            /* ensure that default selection is not drawn */
            event.detail &= ~SWT.SELECTED;

        }

    }

    /**
     * Handle the measure event.
     *
     * @param event
     *            the measure event
     * @param element
     *            the model element
     * @see SWT#MeasureItem
     */
    protected abstract void measure(Event event, Object element);

    /**
     * Handle the paint event.
     *
     * @param event
     *            the paint event
     * @param element
     *            the model element
     * @see SWT#PaintItem
     */
    protected abstract void paint(Event event, Object element);

    /**
     * Enables or disables owner draw for the given viewer and column. This
     * method will attach or remove a listener to the underlying control as
     * necessary. This method is called from
     * {@link #initialize(ColumnViewer, ViewerColumn)} and
     * {@link #dispose(ColumnViewer, ViewerColumn)} but may be called from
     * subclasses to enable or disable owner draw dynamically.
     *
     * @param viewer
     *            the viewer
     * @param column
     *            the column, or <code>null</code> if a column is not
     *            available
     * @param enabled
     *            <code>true</code> if owner draw should be enabled,
     *            <code>false</code> otherwise
     *
     * @since 3.4
     */
    protected void setOwnerDrawEnabled(ColumnViewer viewer, ViewerColumn column, boolean enabled) {
        if (enabled) {
            OwnerDrawListener listener = getOrCreateOwnerDrawListener(viewer);
            if (column == null) {
                listener.enabledGlobally++;
            } else {
                listener.enabledColumns.add(column);
            }
        } else {
            OwnerDrawListener listener = (OwnerDrawListener) viewer.getControl()
                    .getData(OWNER_DRAW_LABEL_PROVIDER_LISTENER);
            if (listener != null) {
                if (column == null) {
                    listener.enabledGlobally--;
                } else {
                    listener.enabledColumns.remove(column);
                }
                if (listener.enabledColumns.isEmpty() && listener.enabledGlobally <= 0) {
                    viewer.getControl().removeListener(SWT.MeasureItem, listener);
                    viewer.getControl().removeListener(SWT.EraseItem, listener);
                    viewer.getControl().removeListener(SWT.PaintItem, listener);
                    viewer.getControl().setData(OWNER_DRAW_LABEL_PROVIDER_LISTENER, null);
                }
            }
        }
    }

}