blob: 7ba6964818d40382ee5a55e5041da16e30a4623a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.contentassist;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.text.IEventConsumer;
/**
* An <code>AbstractControlContentAssistSubjectAdapter</code> delegates assistance requests from a
* {@linkplain org.eclipse.jface.text.contentassist.ContentAssistant content assistant}
* to a <code>Control</code>.
*
* A visual affordance can be configured via {@link #setContentAssistCueProvider(ILabelProvider)}.
*
* @since 3.0
*/
public abstract class AbstractControlContentAssistSubjectAdapter implements IContentAssistSubjectControl {
protected static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jface.text/debug/ContentAssistSubjectAdapters")); //$NON-NLS-1$//$NON-NLS-2$
/**
* VerifyKeyListeners for the control.
*/
private List fVerifyKeyListeners;
/**
* KeyListeners for the control.
*/
private Set fKeyListeners;
/**
* The Listener installed on the control which passes events to
* {@link #fVerifyKeyListeners fVerifyKeyListeners} and {@link #fKeyListeners fKeyListeners}.
*/
private Listener fControlListener;
/**
* Creates a new {@link AbstractControlContentAssistSubjectAdapter}.
**/
public AbstractControlContentAssistSubjectAdapter() {
fVerifyKeyListeners= new ArrayList(1);
fKeyListeners= new HashSet(1);
}
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistSubjectControl#getControl()
*/
public abstract Control getControl();
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistSubjectControl#addKeyListener(org.eclipse.swt.events.KeyListener)
*/
public void addKeyListener(KeyListener keyListener) {
fKeyListeners.add(keyListener);
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#addKeyListener()"); //$NON-NLS-1$
installControlListener();
}
/**
* {@inheritDoc}
*/
public void removeKeyListener(KeyListener keyListener) {
boolean deleted= fKeyListeners.remove(keyListener);
if (DEBUG) {
if (!deleted)
System.out.println("removeKeyListener -> wasn't here"); //$NON-NLS-1$
System.out.println("AbstractControlContentAssistSubjectAdapter#removeKeyListener() -> " + fKeyListeners.size()); //$NON-NLS-1$
}
uninstallControlListener();
}
/**
* {@inheritDoc}
*/
public boolean supportsVerifyKeyListener() {
return true;
}
/**
* {@inheritDoc}
*/
public boolean appendVerifyKeyListener(final VerifyKeyListener verifyKeyListener) {
fVerifyKeyListeners.add(verifyKeyListener);
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#appendVerifyKeyListener() -> " + fVerifyKeyListeners.size()); //$NON-NLS-1$
installControlListener();
return true;
}
/**
* {@inheritDoc}
*/
public boolean prependVerifyKeyListener(final VerifyKeyListener verifyKeyListener) {
fVerifyKeyListeners.add(0, verifyKeyListener);
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#prependVerifyKeyListener() -> " + fVerifyKeyListeners.size()); //$NON-NLS-1$
installControlListener();
return true;
}
/**
* {@inheritDoc}
*/
public void removeVerifyKeyListener(VerifyKeyListener verifyKeyListener) {
fVerifyKeyListeners.remove(verifyKeyListener);
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#removeVerifyKeyListener() -> " + fVerifyKeyListeners.size()); //$NON-NLS-1$
uninstallControlListener();
}
/**
* {@inheritDoc}
*/
public void setEventConsumer(IEventConsumer eventConsumer) {
// this is not supported
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#setEventConsumer()"); //$NON-NLS-1$
}
/**
* {@inheritDoc}
*/
public String getLineDelimiter() {
return System.getProperty("line.separator"); //$NON-NLS-1$
}
/**
* Installs <code>fControlListener</code>, which handles VerifyEvents and KeyEvents by
* passing them to <code>fVerifyKeyListeners</code> and <code>fKeyListeners</code>.
*/
private void installControlListener() {
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#installControlListener() -> k: " + fKeyListeners.size() + ", v: " + fVerifyKeyListeners.size()); //$NON-NLS-1$ //$NON-NLS-2$
if (fControlListener != null)
return;
fControlListener= new Listener() {
public void handleEvent(Event e) {
if (! getControl().isFocusControl())
return; //SWT.TRAVERSE_MNEMONIC events can also come in to inactive widgets
VerifyEvent verifyEvent= new VerifyEvent(e);
KeyEvent keyEvent= new KeyEvent(e);
switch (e.type) {
case SWT.Traverse :
if (DEBUG)
dump("before traverse", e, verifyEvent); //$NON-NLS-1$
verifyEvent.doit= true;
for (Iterator iter= fVerifyKeyListeners.iterator(); iter.hasNext(); ) {
((VerifyKeyListener) iter.next()).verifyKey(verifyEvent);
if (! verifyEvent.doit) {
e.detail= SWT.TRAVERSE_NONE;
e.doit= true;
if (DEBUG)
dump("traverse eaten by verify", e, verifyEvent); //$NON-NLS-1$
return;
}
if (DEBUG)
dump("traverse ok", e, verifyEvent); //$NON-NLS-1$
}
break;
case SWT.KeyDown:
for (Iterator iter= fVerifyKeyListeners.iterator(); iter.hasNext(); ) {
((VerifyKeyListener) iter.next()).verifyKey(verifyEvent);
if (! verifyEvent.doit) {
e.doit= verifyEvent.doit;
if (DEBUG)
dump("keyDown eaten by verify", e, verifyEvent); //$NON-NLS-1$
return;
}
}
if (DEBUG)
dump("keyDown ok", e, verifyEvent); //$NON-NLS-1$
for (Iterator iter= fKeyListeners.iterator(); iter.hasNext();) {
((KeyListener) iter.next()).keyPressed(keyEvent);
}
break;
default :
Assert.isTrue(false);
}
}
/**
* Dump the given events to "standard" output.
*
* @param who who dump's
* @param e the event
* @param ve the verify event
*/
private void dump(String who, Event e, VerifyEvent ve) {
StringBuffer sb= new StringBuffer("--- [AbstractControlContentAssistSubjectAdapter]\n"); //$NON-NLS-1$
sb.append(who);
sb.append(" - e: keyCode="+e.keyCode+hex(e.keyCode)); //$NON-NLS-1$
sb.append("; character="+e.character+hex(e.character)); //$NON-NLS-1$
sb.append("; stateMask="+e.stateMask+hex(e.stateMask)); //$NON-NLS-1$
sb.append("; doit="+e.doit); //$NON-NLS-1$
sb.append("; detail="+e.detail+hex(e.detail)); //$NON-NLS-1$
sb.append("; widget="+e.widget); //$NON-NLS-1$
sb.append("\n"); //$NON-NLS-1$
sb.append(" verifyEvent keyCode="+e.keyCode+hex(e.keyCode)); //$NON-NLS-1$
sb.append("; character="+e.character+hex(e.character)); //$NON-NLS-1$
sb.append("; stateMask="+e.stateMask+hex(e.stateMask)); //$NON-NLS-1$
sb.append("; doit="+ve.doit); //$NON-NLS-1$
sb.append("; widget="+e.widget); //$NON-NLS-1$
System.out.println(sb);
}
private String hex(int i) {
return "[0x" + Integer.toHexString(i) + ']'; //$NON-NLS-1$
}
};
getControl().addListener(SWT.Traverse, fControlListener);
getControl().addListener(SWT.KeyDown, fControlListener);
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#installControlListener() - installed"); //$NON-NLS-1$
}
/**
* Uninstalls <code>fControlListener</code> iff there are no <code>KeyListener</code>s and no
* <code>VerifyKeyListener</code>s registered.
* Otherwise does nothing.
*/
private void uninstallControlListener() {
if (fControlListener == null || fKeyListeners.size() + fVerifyKeyListeners.size() != 0) {
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#uninstallControlListener() -> k: " + fKeyListeners.size() + ", v: " + fVerifyKeyListeners.size()); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
getControl().removeListener(SWT.Traverse, fControlListener);
getControl().removeListener(SWT.KeyDown, fControlListener);
fControlListener= null;
if (DEBUG)
System.out.println("AbstractControlContentAssistSubjectAdapter#uninstallControlListener() - done"); //$NON-NLS-1$
}
/**
* Sets the visual affordance provider for content assist.
* The given {@link ILabelProvider} methods are called with
* {@link #getControl()} as argument.
*
* <ul>
* <li><code>getImage(Object)</code> provides the visual cue image.
* The image can maximally be 5 pixels wide and 8 pixels high.
* If <code>getImage(Object)</code> returns <code>null</code>, a default image is used.
* </li>
* <li><code>getText(Object)</code> provides the hover info text.
* It is shown when hovering over the cue image or the adapted {@link Control}.
* No info text is shown if <code>getText(Object)</code> returns <code>null</code>.
* </li>
* </ul>
* <p>
* The given {@link ILabelProvider} becomes owned by the {@link AbstractControlContentAssistSubjectAdapter},
* i.e. it gets disposed when the adapted {@link Control} is disposed
* or when another {@link ILabelProvider} is set.
* </p>
*
* @param labelProvider a {@link ILabelProvider}, or <code>null</code>
* if the affordance should not be shown
*/
public void setContentAssistCueProvider(ILabelProvider labelProvider) {
SmartFieldController.setSmartCue(getControl(), labelProvider);
}
/**
* The internal controller for cues and error messages on <code>Text</code> and
* <code>Combo</code> <code>Control</code>s.
*/
private static class SmartFieldController {
/**
* An info Hover to display a message next to a {@link Control}.
*/
class Hover {
/**
* Distance of info hover arrow from left side.
*/
private int HD= 10;
/**
* Width of info hover arrow.
*/
private int HW= 8;
/**
* Height of info hover arrow.
*/
private int HH= 10;
/**
* Margin around info hover text.
*/
private int LABEL_MARGIN= 2;
/**
* This info hover's shell.
*/
Shell fHoverShell;
/**
* The info hover text.
*/
String fText= ""; //$NON-NLS-1$
Hover(Shell parent) {
final Display display= parent.getDisplay();
fHoverShell= new Shell(parent, SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_FOCUS);
fHoverShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
fHoverShell.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
fHoverShell.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent pe) {
pe.gc.drawString(fText, LABEL_MARGIN, LABEL_MARGIN);
if (!fgCarbon)
pe.gc.drawPolygon(getPolygon(true));
}
});
fHoverShell.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
showHover(null, null);
}
});
}
int[] getPolygon(boolean border) {
Point e= getExtent();
if (border) {
return new int[] { 0,0, e.x-1,0, e.x-1,e.y-1, HD+HW,e.y-1, HD+HW/2,e.y+HH-1, HD,e.y-1, 0,e.y-1, 0,0 };
} else {
return new int[] { 0,0, e.x, 0, e.x, e.y, HD+HW,e.y, HD+HW/2,e.y+HH, HD,e.y, 0,e.y, 0,0 };
}
}
void dispose() {
if (!fHoverShell.isDisposed())
fHoverShell.dispose();
}
void setVisible(boolean visible) {
if (visible) {
if (!fHoverShell.isVisible())
fHoverShell.setVisible(true);
} else {
if (fHoverShell.isVisible())
fHoverShell.setVisible(false);
}
}
void setText(String t) {
if (t == null)
t= ""; //$NON-NLS-1$
if (! t.equals(fText)) {
Point oldSize= getExtent();
fText= t;
fHoverShell.redraw();
Point newSize= getExtent();
if (!oldSize.equals(newSize)) {
Region region= new Region();
region.add(getPolygon(false));
fHoverShell.setRegion(region);
}
}
}
boolean isVisible() {
return fHoverShell.isVisible();
}
void setLocation(Control control) {
if (control != null) {
int h= getExtent().y;
fHoverShell.setLocation(control.toDisplay(-HD+HW/2, -h-HH+1));
}
}
Point getExtent() {
GC gc= new GC(fHoverShell);
Point e= gc.textExtent(fText);
gc.dispose();
e.x+= LABEL_MARGIN*2;
e.y+= LABEL_MARGIN*2;
return e;
}
}
/**
* A single plain HoverHandler is registered for the content assist control.
* It handles mouse hover events to show/hide the info hover.
*/
class HoverHandler extends MouseTrackAdapter {
/**
* The managing FieldFocusListener.
*/
FieldFocusListener fFieldFocusListener;
/**
* Create a new HoverHandler.
*
* @param fieldFocusListener the field focus listener
*/
HoverHandler(FieldFocusListener fieldFocusListener) {
fFieldFocusListener= fieldFocusListener;
}
/**
* @inheritDoc
*/
public void mouseHover(MouseEvent e) {
handleMouseEvent(e);
}
/**
* @inheritDoc
*/
public void mouseExit(MouseEvent e) {
if (isHoverVisible())
fFieldFocusListener.doHideHover();
}
/**
* Subclasses may extend or reimplement this method.
* @param e
*/
void handleMouseEvent(MouseEvent e) {
fFieldFocusListener.doShowHover();
}
}
/**
* One CueHandler is registered per ancestor control of the content assist control.
* It paints the visual cue icon and handles mouse hover events to show/hide the info hover.
*/
class CueHandler extends HoverHandler implements PaintListener {
/**
* Create a new CueHandler.
*
* @param fieldFocusListener the field focus listener
*/
CueHandler(FieldFocusListener fieldFocusListener) {
super(fieldFocusListener);
}
/**
* @inheritDoc
*/
public void paintControl(PaintEvent e) {
fFieldFocusListener.paintControl(e);
}
/**
* Updates the hover.
*
* @param event the mouse event
*/
void handleMouseEvent(MouseEvent event) {
fFieldFocusListener.updateHoverOnCue(event);
}
}
class FieldFocusListener implements FocusListener {
/**
* Put icon relative to this control.
*/
private Control fControl;
/**
* The icon's horizontal screen distance from top-left corner of control (in pixels).
*/
private int fDx;
/**
* The icon's vertical screen distance from top-left corner of control (in pixels).
*/
private int fDy;
/**
* The HoverHandler (only when control has focus).
*/
private HoverHandler fHoverHandler;
/**
* Create a new FieldFocusListener
* @param control the target control
*/
FieldFocusListener(Control control) {
fControl= control;
fDx= -5;
fDy= 1;
if (fgCarbon) {
if (control instanceof Text) {
fDy+= 3;
} else if (control instanceof Combo) {
fDx-= 4;
}
} else if (fgWin32) {
if (control instanceof Text) {
fDx-= 2;
fDy-= 2;
}
}
}
/**
* Paint the cue image.
* @param e the PaintEvent
*/
void paintControl(PaintEvent e) {
if (fControl.isDisposed())
return;
Image image= getCueImage(fControl);
Point global= fControl.toDisplay(fDx, fDy);
Point local= ((Control) e.widget).toControl(global);
e.gc.drawImage(image, local.x, local.y);
}
/**
* Show/hide the hover.
* @param e the MouseEvent
*/
void updateHoverOnCue(MouseEvent e) {
Image image= getCueImage(fControl);
Rectangle r= image.getBounds();
Point global= fControl.toDisplay(fDx, fDy);
Point local= ((Control) e.widget).toControl(global);
r.x= local.x;
r.y= local.y;
if (r.contains(e.x, e.y))
doShowHover();
else
doHideHover();
}
/**
* Hide hover.
*/
private void doHideHover() {
showHover(fControl, null);
}
/**
* Show hover.
*/
public void doShowHover() {
showHover(fControl, fLabelProvider.getText(fControl));
}
/*
* @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
*/
public void focusGained(FocusEvent e) {
// install a CueHandler on every parent control
if (DEBUG)
System.out.println("Focus Gained: " + e.widget); //$NON-NLS-1$
if (fHoverHandler == null) {
fHoverHandler= new HoverHandler(this);
fControl.addMouseTrackListener(fHoverHandler);
}
Control c= fControl.getParent();
while (c != null) {
if (DEBUG)
System.out.println("install CueHandler: " + c.toString()); //$NON-NLS-1$
CueHandler cueHandler= new CueHandler(this);
Assert.isTrue(c.getData(ANNOTATION_HANDLER) == null, "parent control has CueHandler: " + c.toString()); //$NON-NLS-1$
c.setData(ANNOTATION_HANDLER, cueHandler);
c.addPaintListener(cueHandler);
c.addMouseTrackListener(cueHandler);
c.redraw();
if (c instanceof Shell)
break;
else
c= c.getParent();
}
}
/*
* @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
*/
public void focusLost(FocusEvent e) {
if (DEBUG) {
System.out.println("Focus Lost: " + e.widget + ", at:"); //$NON-NLS-1$ //$NON-NLS-2$
Thread.dumpStack();
}
if (fHoverHandler != null)
fControl.removeMouseTrackListener(fHoverHandler);
Control c= fControl.getParent();
while (c != null) {
if (DEBUG)
System.out.println("uninstall CueHandler: " + c.toString()); //$NON-NLS-1$
CueHandler cueHandler= (CueHandler) c.getData(ANNOTATION_HANDLER);
//workaround for bug 64052:
if (cueHandler != null) {
c.setData(ANNOTATION_HANDLER, null);
c.removePaintListener(cueHandler);
c.removeMouseTrackListener(cueHandler);
c.redraw();
}
if (c instanceof Shell)
break;
else
c= c.getParent();
}
}
}
private static final String SMART_FIELD_CONTROLLER= "org.eclipse.SmartFieldController"; //$NON-NLS-1$
private static final String SMART_FOCUS_LISTENER= "org.eclipse.SmartFieldController.smartFocusListener"; //$NON-NLS-1$
private static final String ANNOTATION_HANDLER= "org.eclipse.SmartFieldController.annotationHandler"; //$NON-NLS-1$
private static String fgPlatform= SWT.getPlatform();
private static boolean fgCarbon= "carbon".equals(fgPlatform); //$NON-NLS-1$
private static boolean fgWin32= "win32".equals(fgPlatform); //$NON-NLS-1$
private Shell fShell;
private ILabelProvider fLabelProvider;
private Image fCueImage;
private Hover fHover;
private Control fHoverControl;
/**
* Installs or deinstalls a visual cue indicating availability of content assist on the given control.
* At most one cue and one hover info is shown at any point in time.
*
* @param control the control on which to install or uninstall the cue
* @param labelProvider the label provider or <code>null</code> to uninstall the cue
*/
public static void setSmartCue(Control control, ILabelProvider labelProvider) {
getSmartFieldController(control).internalSetSmartCue(control, labelProvider);
}
//---- private implementation
private SmartFieldController(Shell shell) {
fShell= shell;
fShell.setData(SMART_FIELD_CONTROLLER, this);
Listener l= new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Resize:
case SWT.Move:
if (fHover != null)
fHover.setLocation(fHoverControl);
break;
case SWT.Dispose:
Object data= fShell.getData(SMART_FIELD_CONTROLLER);
if (data == SmartFieldController.this) {
fShell.setData(SMART_FIELD_CONTROLLER, null);
handleDispose();
}
break;
//case SWT.Activate:
case SWT.Deactivate:
case SWT.Close:
case SWT.Iconify:
//case SWT.Deiconify:
showHover(null, null);
break;
}
}
};
shell.addListener(SWT.Dispose, l);
shell.addListener(SWT.Resize, l);
shell.addListener(SWT.Move, l);
//shell.addListener(SWT.Activate, l);
shell.addListener(SWT.Close, l);
shell.addListener(SWT.Deactivate, l);
shell.addListener(SWT.Iconify, l);
//shell.addListener(SWT.Deiconify, l);
}
private void handleDispose() {
fShell= null;
fHoverControl= null;
if (fHover != null) {
fHover.dispose();
fHover= null;
}
if (fCueImage != null) {
fCueImage.dispose();
fCueImage= null;
}
if (fLabelProvider != null) {
fLabelProvider.dispose();
fLabelProvider= null;
}
}
/**
* Gets the smart field controller from the <code>control</code>'s Shell.
* @param control that target control
* @return <code>control</code>'s shell
*/
private static SmartFieldController getSmartFieldController(Control control) {
Shell shell= control.getShell();
Object data= shell.getData(SMART_FIELD_CONTROLLER);
if (! (data instanceof SmartFieldController))
data= new SmartFieldController(shell);
return (SmartFieldController) data;
}
private void internalSetSmartCue(final Control control, ILabelProvider labelProvider) {
if (fLabelProvider != null)
fLabelProvider.dispose();
fLabelProvider= labelProvider;
FieldFocusListener focuslistener= (FieldFocusListener) control.getData(SMART_FOCUS_LISTENER);
if (labelProvider != null) {
// add smart stuff
if (focuslistener == null) {
focuslistener= new FieldFocusListener(control);
control.setData(SMART_FOCUS_LISTENER, focuslistener);
control.addFocusListener(focuslistener);
}
} else {
// remove smart stuff
if (focuslistener != null) {
control.removeFocusListener(focuslistener);
control.setData(SMART_FOCUS_LISTENER, null);
}
if (fCueImage != null) {
fCueImage.dispose();
fCueImage= null;
}
}
}
/**
* Show or hide hover.
* @param control target control
* @param text a String to show in hover, or <code>null</code> to hide
*/
private void showHover(Control control, String text) {
if (text != null) {
fHoverControl= control;
if (fHover == null)
fHover= new Hover(fShell);
fHover.setText(text);
fHover.setLocation(fHoverControl);
fHover.setVisible(true);
} else {
fHoverControl= null;
if (fHover != null)
fHover.setVisible(false);
}
}
private boolean isHoverVisible() {
return fHover != null && fHover.isVisible();
}
private Image getCueImage(Control control) {
Image image= null;
if (fLabelProvider != null)
image= fLabelProvider.getImage(control);
return image != null ? image : getCueImage();
}
private Image getCueImage() {
if (fCueImage == null) {
ImageDescriptor cueID= ImageDescriptor.createFromFile(SmartFieldController.class, "images/content_assist_cue.gif"); //$NON-NLS-1$
fCueImage= cueID.createImage(fShell.getDisplay());
}
return fCueImage;
}
}
}