/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.ui.views;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.util.Messages;
import org.apache.log4j.Logger;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.OwnerDrawLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.TableItem;
public abstract class AbstractTreeOwnerDrawLabelProvider extends OwnerDrawLabelProvider {
private static final Logger log = Logger.getLogger( AbstractTreeOwnerDrawLabelProvider.class );
// the margin between a minus/plus image and the bounds of a draw event
protected int _margin;
// the center point (width equals height) of a minus/plus image
protected int _midpoint;
// the size (width equals height) of a minus/plus image
protected int _imageSize;
// the margin between a minus/plus image and the text
protected int _imageInterval;
// the color of the frame of a minus/plus image
protected Color _imageFramColor;
protected TableViewer _viewer;
int _displayLevel = -1;
static final int MINUS_IMAGE_INDEX = -1;
static final int PLUS_IMAGE_INDEX = 1;
public AbstractTreeOwnerDrawLabelProvider( TableViewer viewer ) {
_viewer = viewer;
}
/**
* Sets the display level. If the display level is <em>-1</em>, there is no level restriction and all data should be
* displayed.
*
* @param level
*/
public void setDiaplsyLevel( int level ) {
_displayLevel = level;
}
/**
* Gets the display level. If the display level is <em>-1</em>, there is no level restriction and all data should be
* displayed.
*
* @return
*/
public int getDisplayLevel() {
return _displayLevel;
}
private void initialization( Event event ) {
int height = event.getBounds().height;
_margin = (int) ( height * 0.2 );
_margin = Math.max( 0, _margin );
_imageSize = (int) ( height * 0.6 );
_imageSize = ( ( _imageSize + 1 ) / 2 ) * 2; // size must be an even
// number
_midpoint = _margin + _imageSize / 2;
_imageInterval = height;
_imageFramColor = event.display.getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW );
int index = _viewer.getTable().getSelectionIndex();
if( index != -1 ) {
TableItem item = _viewer.getTable().getItem( index );
Rectangle rect = item.getBounds( event.index );
Rectangle headRect = new Rectangle( 0, rect.y, rect.x, rect.height );
event.gc.fillRectangle( headRect );
event.gc.fillRectangle( rect );
}
}
/**
* This method should be override in subclass, but subclass method must call the super.paint(Event, Object) first.
*/
protected void paint( Event event, Object element ) {
initialization( event );
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.OwnerDrawLabelProvider#erase(org.eclipse.swt.widgets.Event, java.lang.Object)
*/
protected void erase( Event event, Object element ) {
// do nothing
}
protected void drawFirstColumn( Event event, Object element, String text, boolean highlight ) {
int startX = event.x;
int startY = event.y;
int indent = getIndent( element );
int extraWidth = indent * _imageInterval;
event.width += extraWidth + _imageInterval;
for( int i = 0; i < indent; i++ ) {
if( findRowAtSameIndent( event.item, i ) ) {
int lineStyle = event.gc.getLineStyle();
event.gc.setLineDash( new int[] { 1 } );
// draw line "|"
drawLine1( event, startX + i * _imageInterval, startY );
event.gc.setLineStyle( lineStyle );
}
}
boolean shouldDisplayImage = true;
if( _displayLevel >= 0 && _displayLevel >= calculateDisplayLevel( element ) )
shouldDisplayImage = false;
if( hasChildren( element ) && shouldDisplayImage ) {
if( indent != 0 ) {
// draw line "|" (above an image)
drawLine6( event, startX + extraWidth, startY );
}
// draw minus/plus image
if( isExpanded( element ) ) {
drawImage( MINUS_IMAGE_INDEX, event, startX + extraWidth, startY, _imageInterval );
// draw line "|" (below half size)
drawLine9( event, startX + extraWidth + _imageInterval, startY );
} else
drawImage( PLUS_IMAGE_INDEX, event, startX + extraWidth, startY, _imageInterval );
// draw line "-" (right side of an image)
drawLine7( event, startX + extraWidth, startY );
if( findRowAtSameIndent( event.item, indent ) )
// draw line "|" (below an image)
drawLine8( event, startX + extraWidth, startY );
} else {
if( indent != 0 ) {
if( findRowAtSameIndent( event.item, indent ) )
// draw line "|-"
drawLine2( event, startX + extraWidth, startY );
else
// line "|_".
drawLine3( event, startX + extraWidth, startY );
}
}
drawText( event, text, startX + extraWidth + _imageInterval + _imageInterval, startY, highlight );
}
private void drawLine( Event event, int lineStartX, int lineStartY, int lineEndX, int lineEndY ) {
int lineStyle = event.gc.getLineStyle();
event.gc.setLineDash( new int[] { 1 } );
Color frontColor = event.gc.getForeground();
event.gc.setForeground( _imageFramColor );
event.gc.drawLine( lineStartX, lineStartY, lineEndX, lineEndY );
event.gc.setForeground( frontColor );
event.gc.setLineStyle( lineStyle );
}
/**
* Draws line "|".
*
* @param event
* @param startX
* @param startY
*/
private void drawLine1( Event event, int startX, int startY ) {
int lineStartX = startX + _midpoint;
int lineStartY = startY;
int lineEndX = lineStartX;
int lineEndY = startY + _imageInterval;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
/**
* Draws line "|" (above an image).
*
* @param event
* @param startX
* @param startY
*/
private void drawLine6( Event event, int startX, int startY ) {
int lineStartX = startX + _midpoint;
int lineStartY = startY;
int lineEndX = lineStartX;
int lineEndY = startY + _margin;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
/**
* Draws line "-" (right side of an image).
*
* @param event
* @param startX
* @param startY
*/
private void drawLine7( Event event, int startX, int startY ) {
int lineStartX = startX + _margin + _imageSize;
int lineStartY = startY + _midpoint;
int lineEndX = startX + event.getBounds().height + _imageInterval;
int lineEndY = lineStartY;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
/**
* Draws line "|" (below an image).
*
* @param event
* @param startX
* @param startY
*/
private void drawLine8( Event event, int startX, int startY ) {
int lineStartX = startX + _midpoint;
int lineStartY = startY + _margin + _imageSize;
int lineEndX = lineStartX;
int lineEndY = startY + event.getBounds().height;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
/**
* Draws line "|-".
*
* @param event
* @param startX
* @param startY
*/
private void drawLine2( Event event, int startX, int startY ) {
drawLine1( event, startX, startY );
drawLine4( event, startX, startY );
}
/**
* Draws line "|_".
*
* @param event
* @param startX
* @param startY
*/
private void drawLine3( Event event, int startX, int startY ) {
drawLine5( event, startX, startY );
drawLine4( event, startX, startY );
}
/**
* Draws "-".
*
* @param event
* @param startX
* @param startY
*/
private void drawLine4( Event event, int startX, int startY ) {
int lineStartX = startX + _midpoint;
int lineStartY = startY + _midpoint;
int lineEndX = lineStartX + _midpoint + _imageInterval;
int lineEndY = lineStartY;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
/**
* Draws "|" (up half size).
*
* @param event
* @param startX
* @param startY
*/
private void drawLine5( Event event, int startX, int startY ) {
int lineStartX = startX + _midpoint;
int lineStartY = startY;
int lineEndX = lineStartX;
int lineEndY = startY + _midpoint;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
/**
* Draws "|" (below half size).
*
* @param event
* @param startX
* @param startY
*/
private void drawLine9( Event event, int startX, int startY ) {
int lineStartX = startX + _midpoint;
int lineStartY = startY + _midpoint;
int lineEndX = lineStartX;
int lineEndY = startY + _imageInterval;
drawLine( event, lineStartX, lineStartY, lineEndX, lineEndY );
}
private void drawImage( int image, Event event, int x, int y, int height ) {
GC gc = event.gc;
Color foreground = gc.getForeground();
/* Plus image */
gc.setForeground( _imageFramColor );
gc.drawRectangle( x + _margin, y + _margin, _imageSize, _imageSize );
gc.setForeground( foreground );
if( image == MINUS_IMAGE_INDEX )
drawMinusImage( event, x, y, height );
else if( image == PLUS_IMAGE_INDEX )
drawPlusImage( event, x, y, height );
else
log.error( NLS.bind( Messages.AbstractTreeOwnerDrawLabelProvider_UNKNOWN_IMAGE_MESSAGE, image ) );
}
/**
* Draws a "+" sign with a frame.
*
* @param event
* @param x
* @param y
* @param height
*/
private void drawPlusImage( Event event, int x, int y, int height ) {
event.gc.drawLine( x + _midpoint, y + _margin + 2, x + _midpoint, y + _margin + _imageSize - 2 );
event.gc.drawLine( x + _margin + 2, y + _midpoint, x + _margin + _imageSize - 2, y + _midpoint );
}
/**
* Draws a "-" sign with a frame.
*
* @param event
* @param x
* @param y
* @param height
*/
private void drawMinusImage( Event event, int x, int y, int height ) {
event.gc.drawLine( x + _margin + 2, y + _midpoint, x + _margin + _imageSize - 2, y + _midpoint );
}
protected Color getForeground() {
if( _viewer.getTable().getSelectionIndex() >= 0 )
return _viewer.getTable().getItem( _viewer.getTable().getSelectionIndex() ).getForeground();
else
return _viewer.getTable().getForeground();
}
protected Color getBackground() {
// This method must be overriden otherwise, in a TableTree in which the
// first
// item has no sub items, a grey (Widget background colour) square will
// appear in
// the first column of the first item.
// It is not possible in the constructor to set the background of the
// TableTree
// to be the same as the background of the Table because this interferes
// with n
// the TableTree adapting to changes in the System color settings.
if( _viewer.getTable().getSelectionIndex() >= 0 )
return _viewer.getTable().getItem( _viewer.getTable().getSelectionIndex() ).getBackground();
else
return _viewer.getTable().getBackground();
}
public ColumnViewer getViewer() {
return _viewer;
}
public void drawText( Event event, String text, int x, int y, boolean highlight ) {
if( highlight )
event.gc.setForeground( event.display.getSystemColor( SWT.COLOR_DARK_RED ) );
event.gc.drawText( IConstants.ONE_BLANK_STRING + IConstants.ONE_BLANK_STRING + text.trim(), x, y );
}
public Rectangle getImageBounds( Object item, Rectangle rectangle ) {
return new Rectangle( rectangle.x + getIndent( item ) * _imageInterval + _margin, rectangle.y + _margin, _imageSize,
_imageSize );
}
// --- Abstract methods ---
/**
* Finds if there is any other row which has the same indent as the given <code>indent</code>.
*
* @param obj
* It could be a TableItem object or the data of a TableItem.
* @param indent
* indent of given <code>obj</code>.
* @return <code>true</code>if there is any other row which has the same indent as the given <code>indent</code>,
* <code>false</code> otherwise;
*/
abstract public boolean findRowAtSameIndent( Object obj, int indent );
/**
* Gets the indent of given <code>obj</code>.
*
* @param obj
* @return indent of given <code>obj</code>.
*/
abstract public int getIndent( Object obj );
/**
* Gets the index of given <code>obj</code>.
*
* @param obj
* @return index of given <code>obj</code>.
*/
abstract public int getIndex( Object obj );
/**
* Checks if <code>obj</code> has children.
*
* @param obj
* @return <code>true</code>if <code>obj</code> has children, <code>false</code>otherwise;
*/
abstract public boolean hasChildren( Object obj );
/**
* Checks if <code>obj</code> was expanded..
*
* @param obj
* @return <code>true</code>if <code>obj</code> was expanded, <code>false</code>otherwise;
*/
abstract public boolean isExpanded( Object obj );
/**
* Calculates the display level of given <code>obj</code>.
*
* @param obj
* @return display level of given <code>obj</code>.
*/
abstract public int calculateDisplayLevel( Object obj );
}