package rocks.inspectit.ui.rcp.editor.viewers; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.TextLayout; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TreeItem; import ch.qos.logback.core.status.Status; import rocks.inspectit.ui.rcp.InspectIT; /** * Extension of the {@link StyledCellLabelProvider} that fixes the Eclipse bug with the image sizes * in the columns must be same width. Does this by custom painting. Note is not applicable for * viewers using PendingAdapterUpdates. * * @author Ivan Senic * */ public class ImageFixStyledCellIndexLabelProvider extends StyledCellIndexLabelProvider { /** * Margin to display left and right to image. */ private static final int IMAGE_MARGIN = 1; /** * We are using reflection to have possibility of calling the private method in the superclass. */ private static Method getSharedTextLayoutMethod; static { try { getSharedTextLayoutMethod = StyledCellLabelProvider.class.getDeclaredMethod("getSharedTextLayout", new Class<?>[] { Display.class }); getSharedTextLayoutMethod.setAccessible(true); } catch (NoSuchMethodException | SecurityException e) { InspectIT.getDefault().log(Status.WARN, "Can no load the getSharedTextLayout() method on the Display class.", e); } } /** * {@inheritDoc} */ @Override public void update(ViewerCell cell) { super.update(cell); // we set image to null cause we will draw it on our own cell.setImage(null); } /** * {@inheritDoc} */ @Override protected void paint(Event event, Object element) { // first get cell bounds Rectangle cellBounds = getViewerCellBounds(event); if (cellBounds == null) { return; } // check if we have image for the element on the index Image image = getColumnImage(element, event.index); Rectangle imageBounds = null; // if we have ident the text for the image width plus the left + right margin if (null != image) { imageBounds = image.getBounds(); TextLayout textLayout = getSharedTextLayout(event.display); textLayout.setIndent(imageBounds.width + IMAGE_MARGIN + IMAGE_MARGIN); } // then execute super paint super.paint(event, element); // additionally paint image ourself if we have it if (imageBounds != null) { // add margin to x int x = cellBounds.x + IMAGE_MARGIN; // center horizontally int y = cellBounds.y + Math.max(0, (cellBounds.height - imageBounds.height) / 2); // draw event.gc.drawImage(image, x, y); } } /** * @param event * Event * @return Returns the {@link Rectangle} describing the bounds of a cell for an event. */ private Rectangle getViewerCellBounds(Event event) { if (event.item instanceof TableItem) { return ((TableItem) event.item).getBounds(event.index); } else if (event.item instanceof TreeItem) { return ((TreeItem) event.item).getBounds(event.index); } throw new RuntimeException("ImageFixStyledCellIndexLabelProvider can only run with tree or table"); } /** * Using reflection to call {@link #getSharedTextLayout(Display)} in the super class. * * @param display * {@link Display} * @return {@link TextLayout} given by mentioned method or <code>null</code> if not available. */ private TextLayout getSharedTextLayout(Display display) { if (null == getSharedTextLayoutMethod) { return null; } try { return (TextLayout) getSharedTextLayoutMethod.invoke(this, display); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { return null; } } }