content: /*******************************************************************************
   * Copyright (c) 2007 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.wst.jsdt.internal.ui.viewsupport;
  
  import java.util.Iterator;
  
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.graphics.Color;
  import org.eclipse.swt.graphics.Font;
  import org.eclipse.swt.graphics.GC;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.swt.graphics.Rectangle;
  import org.eclipse.swt.graphics.TextLayout;
  import org.eclipse.swt.graphics.TextStyle;
  import org.eclipse.swt.widgets.Control;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Event;
  import org.eclipse.swt.widgets.Item;
  import org.eclipse.swt.widgets.Listener;
  import org.eclipse.swt.widgets.TableItem;
  import org.eclipse.swt.widgets.TreeItem;
  
  /**
   * Adding owner draw support to a control
   */
  public abstract class OwnerDrawSupport implements Listener {
  	
  	private TextLayout fTextLayout;
  	private final Control fControl;
  	
  	public OwnerDrawSupport(Control control) {
  		fControl= control;
  		fTextLayout= new TextLayout(control.getDisplay());
  		
  		control.addListener(SWT.PaintItem, this);
  		control.addListener(SWT.EraseItem, this);
  		control.addListener(SWT.Dispose, this);
  	}
  	
  	/**
  	 * Return the colored label for the given item.
  	 * @param item the item to return the colored label for
  	 * @return the colored string
  	 */
  	public abstract ColoredString getColoredLabel(Item item);
  	
  	/**
  	 * Return the color for the given style
  	 * @param foregroundColorName the name of the color
  	 * @param display the current display
  	 * @return the color
  	 */
  	public abstract Color getColor(String foregroundColorName, Display display);
  	
  	/* (non-Javadoc)
  	 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
  	 */
  	public void handleEvent(Event event) {
  		if (event.type == SWT.PaintItem) {
  			performPaint(event);
  		} else if (event.type == SWT.EraseItem) {
  			performErase(event);
  		} else if (event.type == SWT.Dispose) {
  			dispose();
  		}
  	}
  	
  	private void performErase(Event event) {
  		event.detail &= ~SWT.FOREGROUND;
  	}
  			
  	private void performPaint(Event event) {
  		Item item= (Item) event.item;
  		GC gc= event.gc;
  
  		ColoredString coloredLabel= getColoredLabel(item);
  		boolean isSelected= (event.detail & SWT.SELECTED) != 0 && fControl.isFocusControl();
  		if (item instanceof TreeItem) {
  			TreeItem treeItem= (TreeItem) item;
  			Image image = treeItem.getImage(event.index);
  			if (image != null) {
  				processImage(image, gc, treeItem.getImageBounds(event.index));
  			}
  			Rectangle textBounds= treeItem.getTextBounds(event.index);
  			Font font= treeItem.getFont(event.index);
  			processColoredLabel(coloredLabel, gc, textBounds, isSelected, font);
  			
  			Rectangle bounds= treeItem.getBounds();
  			if ((event.detail & SWT.FOCUSED) != 0) {
  				gc.drawFocus(bounds.x, bounds.y, bounds.width, bounds.height);
  			}
  		} else if (item instanceof TableItem) {
  			TableItem tableItem= (TableItem) item;
  			Image image = tableItem.getImage(event.index);
  			if (image != null) {
  				processImage(image, gc, tableItem.getImageBounds(event.index));
  			}
  			Rectangle textBounds= tableItem.getTextBounds(event.index);
  			Font font= tableItem.getFont(event.index);
  			processColoredLabel(coloredLabel, gc, textBounds, isSelected, font);
  			
  			Rectangle bounds= tableItem.getBounds();
  			if ((event.detail & SWT.FOCUSED) != 0) {
  				gc.drawFocus(bounds.x, bounds.y, bounds.width, bounds.height);
  			}
  		}
  	}
  	
  	private void processImage(Image image, GC gc, Rectangle imageBounds) {
  		Rectangle bounds= image.getBounds();
  		int x= imageBounds.x + Math.max(0, (imageBounds.width - bounds.width) / 2);
  		int y= imageBounds.y + Math.max(0, (imageBounds.height - bounds.height) / 2);
  		gc.drawImage(image, x, y);
  	}
  	
  	private void processColoredLabel(ColoredString richLabel, GC gc, Rectangle textBounds, boolean isSelected, Font font) {
  		String text= richLabel.getString();
  		fTextLayout.setText(text);
  		fTextLayout.setFont(font);
  		
  		if (!isSelected) {
  			// apply the styled ranges only when element is not selected
  			Display display= (Display) gc.getDevice();
  			Iterator ranges= richLabel.getRanges();
  			while (ranges.hasNext()) {
  				ColoredString.StyleRange curr= (ColoredString.StyleRange) ranges.next();
  				ColoredString.Style style= curr.style;
  				if (style != null) {
  					Color foreground= getColor(style.getForegroundColorName(), display);
  					TextStyle textStyle= new TextStyle(null, foreground, null);
  					fTextLayout.setStyle(textStyle, curr.offset, curr.offset + curr.length - 1);
  				}
  			}
  		}
  		
  		Rectangle bounds= fTextLayout.getBounds();
  		int x= textBounds.x;
  		int y = textBounds.y + Math.max(0, (textBounds.height - bounds.height) / 2);
  		
  		fTextLayout.draw(gc, x, y);
  		fTextLayout.setText(""); // clear all ranges //$NON-NLS-1$
  	}
  	
  	public void dispose() {
      	if (fTextLayout != null) {
      		fTextLayout.dispose();
      		fTextLayout= null;
      	}
      	if (!fControl.isDisposed()) {
  			fControl.removeListener(SWT.PaintItem, this);
  			fControl.removeListener(SWT.EraseItem, this);
  			fControl.removeListener(SWT.Dispose, this);
      	}
  	}
  }
  