How to add both an image decoration and a custom tooltip to a JFace ViewerColumn
Recently i had to add some image decorations and a custom tooltip to a column of a Jface StructuredViewer. This wasn’t too hard, but i lost a fair amount of time figuring out how to put the pieces together.
This is how i did it:
Setup
To avoid unneeded elements i’ll start with a plug-in project created with the eclipse wizard “RCP application with a view”.
When you run the application created by the wizard you will get the following:
Unfortunately the generated view doesn’t use viewercolumns, so we have to change that:
Adapting the generated view
Change ViewLabelProvider
Since the ViewerColumn accepts only a CellLabelProvider change the ViewLabelProvider to the following:
class ViewLabelProvider extends ColumnLabelProvider { @Override public String getText(Object obj) { return super.getText(obj); } @Override public Image getImage(Object obj) { return PlatformUI.getWorkbench().getSharedImages().getImage( ISharedImages.IMG_OBJ_ELEMENT); } } |
Change method createPartControl(Composite parent)
we need to create a ViewerColumn and add the labelprovider to it.
To make sure the column takes the whole width of the table, we use the TableColumnLayout.
/** * This is a callback that will allow us to create the viewer and initialize * it. */ @Override public void createPartControl(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE); viewerColumn.setLabelProvider(new ViewLabelProvider()); TableColumnLayout tableColumnLayout = new TableColumnLayout(); tableColumnLayout.setColumnData(viewerColumn.getColumn(), new ColumnWeightData(1)); parent.setLayout(tableColumnLayout); viewer.setContentProvider(new ViewContentProvider()); viewer.setInput(getViewSite()); } |
Generating a model
The model is going to be used later on, to decide wether to decorate or not.
Create the model class
class ViewModel { private boolean active = true; private final String name; public ViewModel(String name) { super(); this.name = name; } protected ViewModel(String name, boolean active) { this(name); this.active = active; } public boolean isActive() { return active; } public String getName() { return name; } } |
Adapt the labelprovider
Change the method getText(Object obj).
@Override public String getText(Object obj) { if (obj instanceof ViewModel) { ViewModel viewModel = (ViewModel) obj; return viewModel.getName(); } return super.getText(obj); } |
Adapt the contentprovider
Change the method getElements(Object parent).
public Object[] getElements(Object parent) { return new ViewModel[] { new ViewModel("One", false), new ViewModel("Two"), new ViewModel("Three", false)}; } |
Adding decorations
We are going to use the DecoratingStyledCellLabelProvider to add decorations.
The DecoratingStyledCellLabelProvider needs a ILabelDecorator and a IStyledLabelProvider.
Creating a labelDecorator
We only want to decorate the image, therefore we implement the method decorateImage(Image image, Object element, IDecorationContext context and the method dispose (to dispose the generated image).
It would be nice though if there existed a LabelDecoratorAdapter in JFace so we didn’t have to add the other methods.
class ViewLabelDecorator extends LabelDecorator { private final ImageDescriptor warningImageDescriptor = Activator .getImageDescriptor("icons/bullet_error.png"); private Image decoratedImage = null; @Override public Image decorateImage(Image image, Object element, IDecorationContext context) { if (element instanceof ViewModel && !((ViewModel) element).isActive()) { if (decoratedImage == null) { decoratedImage = new DecorationOverlayIcon(image, warningImageDescriptor, IDecoration.BOTTOM_RIGHT) .createImage(); } return decoratedImage; } return null; } @Override public void dispose() { decoratedImage.dispose(); decoratedImage = null; } @Override public String decorateText(String text, Object element, IDecorationContext context) { return null; } @Override public boolean prepareDecoration(Object element, String originalText, IDecorationContext context) { return false; } @Override public Image decorateImage(Image image, Object element) { return null; } @Override public String decorateText(String text, Object element) { return null; } @Override public void addListener(ILabelProviderListener listener) { } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { } } |
Adapting the labelProvider
We need to make the LabelProvider implement the interface IStyledLabelProvider.
class ViewLabelProvider extends ColumnLabelProvider implements IStyledLabelProvider { ..... @Override public StyledString getStyledText(Object element) { return new StyledString(getText(element)); } } |
Using the DecoratingStyledCellLabelProvider
Change the method createPartControl(Composite parent) of the view as follows:
@Override public void createPartControl(Composite parent) { ..... TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE); viewerColumn.setLabelProvider(new DecoratingStyledCellLabelProvider( new ViewLabelProvider(), new ViewLabelDecorator(), null)); ..... } |
Result
When you run the application now you will get the following:
Adding tooltips
Adding tooltips is a two-step process: the CellabelProvider provides methods for tooltips that we can implement, and by using the ColumnViewerToolTipSupport we have tooltips. Well, that would it be if the DelegatingStyledCellLabelProvider would try to delegate all the methods.
Adapting the labelprovider
Implement the method getTooltipText(Object element):
@Override public String getToolTipText(Object element) { return getText(element) + ", shown in a tooltip"; } |
Extend the DecoratingStyledCellLabelProvider
class ViewDecoratingStyledCellLabelProvider extends DecoratingStyledCellLabelProvider { private final IStyledLabelProvider labelProvider; public ViewDecoratingStyledCellLabelProvider( IStyledLabelProvider labelProvider, ILabelDecorator decorator, IDecorationContext decorationContext) { super(labelProvider, decorator, decorationContext); this.labelProvider = labelProvider; } @Override public Color getToolTipBackgroundColor(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipBackgroundColor(object); } return super.getToolTipBackgroundColor(object); } @Override public int getToolTipDisplayDelayTime(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipDisplayDelayTime(object); } return super.getToolTipDisplayDelayTime(object); } @Override public Font getToolTipFont(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipFont(object); } return super.getToolTipFont(object); } @Override public Color getToolTipForegroundColor(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipForegroundColor(object); } return super.getToolTipForegroundColor(object); } @Override public Image getToolTipImage(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipImage(object); } return super.getToolTipImage(object); } @Override public Point getToolTipShift(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipShift(object); } return super.getToolTipShift(object); } @Override public int getToolTipStyle(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipStyle(object); } return super.getToolTipStyle(object); } @Override public String getToolTipText(Object element) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipText(element); } return super.getToolTipText(element); } @Override public int getToolTipTimeDisplayed(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipTimeDisplayed(object); } return super.getToolTipTimeDisplayed(object); } @Override public boolean useNativeToolTip(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .useNativeToolTip(object); } return super.useNativeToolTip(object); } } |
Enabling the tooltips
Change the method createPartControl(Composite parent) of the view as follows:
@Override public void createPartControl(Composite parent) { ..... viewerColumn .setLabelProvider(new ViewDecoratingStyledCellLabelProvider( new ViewLabelProvider(), new ViewLabelDecorator(), null)); ..... viewer.setInput(getViewSite()); ColumnViewerToolTipSupport.enableFor(viewer); } |
Result
When you run the application now you will get the following:
Custom tooltips
By extending the ColumnViewerToolTipSupport it is possible to provide custom tooltips.
Extending ColumnViewerToolTipSupport
static class ViewColumnViewerToolTipSupport extends ColumnViewerToolTipSupport { protected ViewColumnViewerToolTipSupport(ColumnViewer viewer, int style, boolean manualActivation) { super(viewer, style, manualActivation); } @Override protected Composite createViewerToolTipContentArea(Event event, ViewerCell cell, Composite parent) { final Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new RowLayout(SWT.VERTICAL)); Text text = new Text(composite, SWT.SINGLE); text.setText(getText(event)); text.setSize(100, 60); DateTime calendar = new DateTime(composite, SWT.CALENDAR); calendar.setEnabled(false); calendar.setSize(100, 100); composite.pack(); return composite; } public static final void enableFor(final ColumnViewer viewer) { new ViewColumnViewerToolTipSupport(viewer, ToolTip.NO_RECREATE, false); } } |
Using the ViewColumnViewerToolTipSupport
Change the method createPartControl(Composite parent) of the view as follows:
@Override public void createPartControl(Composite parent) { ..... ViewColumnViewerToolTipSupport.enableFor(viewer); } |
Result
When you run the application now you will get the following:
Source code
Following is the view class. For simplicity i added all classes as internal class to the generated view class. Make sure the image “icons/bullet_error.png”exists.
package net.davymeers.examples.jface.columnviewerdecorationandtooltip.internal; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider; import org.eclipse.jface.viewers.DecorationOverlayIcon; import org.eclipse.jface.viewers.IDecoration; import org.eclipse.jface.viewers.IDecorationContext; import org.eclipse.jface.viewers.ILabelDecorator; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.LabelDecorator; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; import org.eclipse.jface.window.ToolTip; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DateTime; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; public class View extends ViewPart { public static final String ID = "net.davymeers.examples.jface.columnviewerDecorationAndTooltip.view"; private TableViewer viewer; /** * The content provider class is responsible for providing objects to the * view. It can wrap existing objects in adapters or simply return objects * as-is. These objects may be sensitive to the current input of the view, * or ignore it and always show the same content (like Task List, for * example). */ class ViewContentProvider implements IStructuredContentProvider { public void inputChanged(Viewer v, Object oldInput, Object newInput) { } public void dispose() { } public Object[] getElements(Object parent) { return new ViewModel[] { new ViewModel("One", false), new ViewModel("Two"), new ViewModel("Three", false) }; } } class ViewLabelProvider extends ColumnLabelProvider implements IStyledLabelProvider { @Override public String getText(Object obj) { if (obj instanceof ViewModel) { ViewModel viewModel = (ViewModel) obj; return viewModel.getName(); } return super.getText(obj); } @Override public Image getImage(Object obj) { return PlatformUI.getWorkbench().getSharedImages().getImage( ISharedImages.IMG_OBJ_ELEMENT); } @Override public StyledString getStyledText(Object element) { return new StyledString(getText(element)); } @Override public String getToolTipText(Object element) { return getText(element) + ", shown in a tooltip"; } } class ViewModel { private boolean active = true; private final String name; public ViewModel(String name) { super(); this.name = name; } protected ViewModel(String name, boolean active) { this(name); this.active = active; } public boolean isActive() { return active; } public String getName() { return name; } } class ViewLabelDecorator extends LabelDecorator { private final ImageDescriptor warningImageDescriptor = Activator .getImageDescriptor("icons/bullet_error.png"); private Image decoratedImage = null; @Override public Image decorateImage(Image image, Object element, IDecorationContext context) { if (element instanceof ViewModel && !((ViewModel) element).isActive()) { if (decoratedImage == null) { decoratedImage = new DecorationOverlayIcon(image, warningImageDescriptor, IDecoration.BOTTOM_RIGHT) .createImage(); } return decoratedImage; } return null; } @Override public void dispose() { decoratedImage.dispose(); decoratedImage = null; } @Override public String decorateText(String text, Object element, IDecorationContext context) { return null; } @Override public boolean prepareDecoration(Object element, String originalText, IDecorationContext context) { return false; } @Override public Image decorateImage(Image image, Object element) { return null; } @Override public String decorateText(String text, Object element) { return null; } @Override public void addListener(ILabelProviderListener listener) { } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { } } class ViewDecoratingStyledCellLabelProvider extends DecoratingStyledCellLabelProvider { private final IStyledLabelProvider labelProvider; public ViewDecoratingStyledCellLabelProvider( IStyledLabelProvider labelProvider, ILabelDecorator decorator, IDecorationContext decorationContext) { super(labelProvider, decorator, decorationContext); this.labelProvider = labelProvider; } @Override public Color getToolTipBackgroundColor(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipBackgroundColor(object); } return super.getToolTipBackgroundColor(object); } @Override public int getToolTipDisplayDelayTime(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipDisplayDelayTime(object); } return super.getToolTipDisplayDelayTime(object); } @Override public Font getToolTipFont(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipFont(object); } return super.getToolTipFont(object); } @Override public Color getToolTipForegroundColor(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipForegroundColor(object); } return super.getToolTipForegroundColor(object); } @Override public Image getToolTipImage(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipImage(object); } return super.getToolTipImage(object); } @Override public Point getToolTipShift(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipShift(object); } return super.getToolTipShift(object); } @Override public int getToolTipStyle(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipStyle(object); } return super.getToolTipStyle(object); } @Override public String getToolTipText(Object element) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipText(element); } return super.getToolTipText(element); } @Override public int getToolTipTimeDisplayed(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .getToolTipTimeDisplayed(object); } return super.getToolTipTimeDisplayed(object); } @Override public boolean useNativeToolTip(Object object) { if (labelProvider instanceof CellLabelProvider) { return ((CellLabelProvider) labelProvider) .useNativeToolTip(object); } return super.useNativeToolTip(object); } } static class ViewColumnViewerToolTipSupport extends ColumnViewerToolTipSupport { protected ViewColumnViewerToolTipSupport(ColumnViewer viewer, int style, boolean manualActivation) { super(viewer, style, manualActivation); } @Override protected Composite createViewerToolTipContentArea(Event event, ViewerCell cell, Composite parent) { final Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new RowLayout(SWT.VERTICAL)); Text text = new Text(composite, SWT.SINGLE); text.setText(getText(event)); text.setSize(100, 60); DateTime calendar = new DateTime(composite, SWT.CALENDAR); calendar.setEnabled(false); calendar.setSize(100, 100); composite.pack(); return composite; } public static final void enableFor(final ColumnViewer viewer) { new ViewColumnViewerToolTipSupport(viewer, ToolTip.NO_RECREATE, false); } } /** * This is a callback that will allow us to create the viewer and initialize * it. */ @Override public void createPartControl(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE); viewerColumn .setLabelProvider(new ViewDecoratingStyledCellLabelProvider( new ViewLabelProvider(), new ViewLabelDecorator(), null)); TableColumnLayout tableColumnLayout = new TableColumnLayout(); tableColumnLayout.setColumnData(viewerColumn.getColumn(), new ColumnWeightData(1)); parent.setLayout(tableColumnLayout); viewer.setContentProvider(new ViewContentProvider()); viewer.setInput(getViewSite()); ViewColumnViewerToolTipSupport.enableFor(viewer); } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { viewer.getControl().setFocus(); } } |






October 13th, 2010 at 09:47
Nice example, helped me to find a solution for my problem.
February 23rd, 2011 at 21:57
Nice blog post Davy. You write more and ask to get aggregate at PlanetEclipse.
February 23rd, 2011 at 22:50
Thank you Lars!
Currently i am trying to balance time between my work and my master study.
But i hope to blog a bit more in the future (i have some posts in the pipeline).
March 29th, 2012 at 16:57
Mr. Meers,
Great post!. Your examples are an excellent way for educating people. They’ve helped me tremendously.
I look forward to your future entries.
Lawrence