/*******************************************************************************
* Copyright (c) 2012-2015 INRIA.
* 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:
* Generoso Pagano - initial API and implementation
******************************************************************************/
package fr.inria.soctrace.framesoc.ui.providers;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.OwnerDrawLabelProvider;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.TreeItem;
import fr.inria.soctrace.framesoc.ui.colors.FramesocColor;
/**
* Generic label provider for tree and table viewers, drawing colored squares before names.
*
* @author "Generoso Pagano <generoso.pagano@inria.fr>"
*/
public abstract class SquareIconLabelProvider extends OwnerDrawLabelProvider implements
ILabelProvider {
/**
* References to the images (cache).
*/
private Map<String, Image> images = new HashMap<>();
private static final int SPACE_BEFORE_SQUARE = 2;
/**
* Get the item bounds.
*
* @param event
* paint event
* @return the bounds, or null if the item is not a TreeItem or a TableItem
*/
private Rectangle getBounds(Event event) {
if (event.item instanceof TreeItem) {
return ((TreeItem) event.item).getBounds(event.index);
}
if (event.item instanceof TableItem) {
return ((TableItem) event.item).getBounds(event.index);
}
return null;
}
@Override
protected void measure(Event event, Object element) {
// nothing to do
}
@Override
protected void paint(Event event, Object element) {
Rectangle bounds = getBounds(event);
Assert.isNotNull(bounds);
String text = getText(element);
Image img = null;
if (images.containsKey(text)) {
img = images.get(text);
} else {
Color swtColor = getColor(element);
if (swtColor != null) {
img = new Image(event.display, bounds.height / 2, bounds.height / 2);
GC gc = new GC(img);
if (!swtColor.isDisposed()) {
/*
* We check for disposed because of the following problem: - when I change the
* color associated to a type in the color manager, the color manager disposes
* the old color associated to that type - the color, however, was cached in the
* statistic table row object - such row was not completed here, due to the
* exception, thus it was probably requested twice
*/
gc.setBackground(swtColor);
} else {
gc.setBackground(FramesocColor.BLACK.getSwtColor());
}
gc.fillRectangle(0, 0, bounds.height / 2, bounds.height / 2);
gc.dispose();
images.put(text, img);
}
}
if (img != null) {
// center image and text on y
bounds.height = bounds.height / 2 - img.getBounds().height / 2;
int imgy = bounds.height > 0 ? bounds.y + bounds.height : bounds.y;
int texty = bounds.y + 3;
event.gc.drawText(text, bounds.x + img.getBounds().width + 5 + SPACE_BEFORE_SQUARE, texty, true);
event.gc.drawImage(img, bounds.x + SPACE_BEFORE_SQUARE, imgy);
} else {
event.gc.drawText(text, bounds.x + 2, bounds.y + 3, true);
}
}
@Override
public Image getImage(Object element) {
return null;
}
@Override
public void dispose() {
disposeImages();
super.dispose();
}
/**
* Dispose all the images in the cache. Call this method if colors have changed and you want to
* force the loading of new colors.
*/
public void disposeImages() {
for (Image img : images.values()) {
img.dispose();
}
images = new HashMap<>();
}
/**
* Get the element color. If no color is defined, return null. If null is returned, the
* implementation of {@link #paint(Event, Object)} will not draw the image.
*
* @param element
* the element
* @return the color, or null if no color is defined.
*/
public abstract Color getColor(Object element);
}