/*******************************************************************************
* Copyright (c) 2014 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.ui.swt.listener;
import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
/**
* Abstract cell paint listener implementation
*/
public abstract class AbstractCellPaintListener implements Listener {
private final int[] columns;
/**
* Constructor.
* @param colums The valid columns.
* @param widget The widget.
*/
public AbstractCellPaintListener(Widget widget, int... columns) {
this.columns = columns;
register(widget);
}
/**
* Add this listener to the widget.
* @param widget The widget.
*/
protected void register(Widget widget) {
if (widget != null && !widget.isDisposed()) {
widget.addListener(SWT.MeasureItem, this);
widget.addListener(SWT.PaintItem, this);
widget.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
deregister(e.widget);
}
});
}
}
/**
* Remove this listener from the widget.
* @param widget The widget.
*/
protected void deregister(Widget widget) {
if (widget != null) {
widget.removeListener(SWT.MeasureItem, this);
widget.removeListener(SWT.PaintItem, this);
}
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
*/
@Override
public void handleEvent(Event event) {
// Check if the event type is handled.
if (!isHandledEventType(event.type)) {
return;
}
// We can paint something only if the item is available
if (event.item instanceof Item) {
// Check if the table item is valid
if (isValid(event)) {
// Forward to the event type specific handler methods
switch (event.type) {
case SWT.MeasureItem:
doHandleMeasureItemEvent(event);
break;
case SWT.PaintItem:
doHandlePaintItemEvent(event);
break;
}
}
}
}
/**
* Returns if or if not the given event type is handled by this handler.
* <p>
* The default implementation accepts {@link SWT#MeasureItem} and {@link SWT#PaintItem}.
*
* @param type The event type.
* @return <code>True</code> if the event type is handled by this handler, <code>false</code> otherwise.
*/
protected boolean isHandledEventType(int type) {
return SWT.MeasureItem == type || SWT.PaintItem == type;
}
/**
* Handle the measure item event.
* @param event The event.
*/
protected void doHandleMeasureItemEvent(Event event) {
Assert.isNotNull(event);
// Get the image to draw.
Image image = getImageToDraw((Item)event.item, event.index);
// We have to measure anything only if the returned image is not null.
if (image != null) {
// Width must be minimum image width + 1 pixels at each side
event.width = Math.max(event.width, image.getImageData().width + 2);
// Height must be minimum image width + 1 pixels at each side
event.height = Math.max(event.height, image.getImageData().height + 2);
}
}
/**
* Handle the paint item event.
* @param event The event.
*/
protected void doHandlePaintItemEvent(Event event) {
Assert.isNotNull(event);
// Get the image to draw.
Image image = getImageToDraw((Item)event.item, event.index);
// We have to draw anything only if the returned image is not null.
if (image != null) {
Point point = getPaintOrigin(event, image);
// Paint the image
event.gc.drawImage(image, point.x, point.y);
}
}
/**
* Get the origin where the image should be painted.
* @param event The event.
* @param image The image.
* @return The origin.
*/
protected abstract Point getPaintOrigin(Event event, Image image);
/**
* Get the width of the widget where the image to draw into.
* @param event The event.
* @return The width.
*/
protected int getWidgetWidth(Event event) {
if (event.widget instanceof Table) {
TableColumn column = ((Table)event.widget).getColumn(event.index);
return column.getWidth();
}
else if (event.widget instanceof Tree) {
TreeColumn column = ((Tree)event.widget).getColumn(event.index);
return column.getWidth();
}
return event.width;
}
/**
* Get the image to draw
* @param item The item to draw the image for.
* @param columnIndex The column index.
* @return The image or <code>null</code>.
*/
protected abstract Image getImageToDraw(Item item, int columnIndex);
/**
* Returns if or if not the given events data is valid.
* Subclass implementers may check if the associated data object
* is matching and expected data type.
*
* @param event The event. Must not be <code>null</code>.
* @return <code>True</code> if the events data is valid, <code>false</code> otherwise.
*/
protected boolean isValid(Event event) {
return (event.item != null && isPaintImageInColumn(event.index) &&
((event.widget instanceof Table && event.item instanceof TableItem) ||
(event.widget instanceof Tree && event.item instanceof TreeItem)));
}
/**
* Returns if or if not the managed image shall be painted to the
* given column.
*
* @param columnIndex The column index of the current column.
* @return <code>True</code> if the image shall be painted, <code>false</code> otherwise.
*/
protected boolean isPaintImageInColumn(int columnIndex) {
for (int col : columns) {
if (col == columnIndex) {
return true;
}
}
return false;
}
}