blob: 68ec4b43f934daaee534de1d311a4cbf9c74d09f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2008 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
*******************************************************************************/
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 enabledColumns = new HashSet();
int enabledGlobally = 0;
private ColumnViewer viewer;
OwnerDrawListener(ColumnViewer viewer) {
this.viewer = viewer;
}
public void handleEvent(Event event) {
CellLabelProvider provider = viewer.getViewerColumn(event.index)
.getLabelProvider();
ViewerColumn column = viewer.getViewerColumn(event.index);
if (enabledGlobally > 0 || enabledColumns.contains(column)) {
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.
*/
public static void setUpOwnerDraw(final ColumnViewer viewer) {
getOrCreateOwnerDrawListener(viewer).enabledGlobally++;
}
/**
* @param viewer
* @param control
* @return
*/
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() {
}
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)}.
*/
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);
}
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);
}
}
}
}
}