/******************************************************************************* * Copyright (c) 2012, 2013 Original authors 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: * Original authors and others - initial API and implementation ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.edit.editor; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; /** * This class adds support for adding a {@link ControlDecoration} to the editor * controls of a {@link ICellEditor}. It is currently only used by the * {@link TextCellEditor}. * <p> * The default location for the {@link ControlDecoration} is the top right of * the editor. If the editor is located such that the {@link ControlDecoration} * would not be visible here (i.e. cell is at/extends beyond the right edge of * the NatTable) then the decoration is placed at the top left of the editor. * <p> * The location can be overridden, in which case the above behaviour does not * get used. */ public class ControlDecorationProvider { /** * The String to determine the {@link FieldDecoration} to use by the * {@link ControlDecoration} that is provided by this * {@link ControlDecorationProvider}. */ private String fieldDecorationId; /** * Flag to determine whether this provider is enabled to add * {@link ControlDecoration}s or not. */ private boolean errorDecorationEnabled; /** * The created {@link ControlDecoration} if this provider created one. */ private ControlDecoration errorDecoration; /** * The text to be shown as a description for the decoration, or * <code>null</code> if none has been set. */ private String errorDecorationText; /** * The position configuration where the decoration should be rendered * relative to the control that should be decorated. */ private int decorationPositionOverride = SWT.DEFAULT; /** * Create a default {@link ControlDecorationProvider} for handling error * decorations. */ public ControlDecorationProvider() { this(FieldDecorationRegistry.DEC_ERROR); } /** * @param fieldDecorationId * The field decoration to use by this provider. * @see FieldDecorationRegistry */ public ControlDecorationProvider(String fieldDecorationId) { this.fieldDecorationId = fieldDecorationId; } /** * Enables/disables the error decoration. * * @param enabled * <code>true</code> if a decoration should be added, * <code>false</code> if not. */ public void setErrorDecorationEnabled(boolean enabled) { this.errorDecorationEnabled = enabled; } /** * @param errorText * the text to be shown as a description for the decoration, or * <code>null</code> if none has been set. * @see ControlDecoration#setDescriptionText(String) */ public void setErrorDecorationText(String errorText) { this.errorDecorationText = errorText; if (this.errorDecoration != null) { this.errorDecoration.setDescriptionText(errorText); } } /** * Will show the control decoration adding the given text as description * text. * * @param errorText * the text to be shown in the info hover, or <code>null</code> * if no text should be shown. * @see ControlDecoration#show() * @see ControlDecoration#showHoverText(String) */ public void showErrorDecorationHover(String errorText) { if (this.errorDecoration != null) { this.errorDecoration.show(); this.errorDecoration.showHoverText(errorText); } } /** * Configure the id that should be used to retrieve the * {@link FieldDecoration} to be used by this * {@link ControlDecorationProvider}. * * @param fieldDecorationId * The String to determine the {@link FieldDecoration} to use by * the {@link ControlDecoration} that is provided by this * {@link ControlDecorationProvider}. */ public void setFieldDecorationId(String fieldDecorationId) { this.fieldDecorationId = fieldDecorationId; } /** * Set the position configuration where the decoration should be rendered * relative to the control that should be decorated. * * @param decorationPositionOverride * bit-wise or of position constants (<code>SWT.TOP</code>, * <code>SWT.BOTTOM</code>, <code>SWT.LEFT</code>, * <code>SWT.RIGHT</code>, and <code>SWT.CENTER</code>). */ public void setDecorationPositionOverride(int decorationPositionOverride) { this.decorationPositionOverride = decorationPositionOverride; } /** * Will show the control decoration. * * @see ControlDecoration#show() */ public void showDecoration() { if (this.errorDecoration != null) { this.errorDecoration.show(); } } /** * Will hide the control decoration. * * @see ControlDecoration#hide() */ public void hideDecoration() { if (this.errorDecoration != null) { this.errorDecoration.hide(); } } /** * Ensure to hide the decoration and dispose any resources related to the * {@link ControlDecoration} */ public void dispose() { if (this.errorDecoration != null) { this.errorDecoration.hide(); this.errorDecoration.dispose(); this.errorDecoration = null; } } /** * If showing an error decoration is enabled, this method will create and * add a {@link ControlDecoration} for the given {@link Control} by using * the configured information. * * @param controlToDecorate * The {@link Control} to create the decoration for. */ public void createErrorDecorationIfRequired(final Control controlToDecorate) { if (this.errorDecorationEnabled) { final Image errorImage = FieldDecorationRegistry.getDefault() .getFieldDecoration(this.fieldDecorationId).getImage(); if (this.decorationPositionOverride == SWT.DEFAULT) { controlToDecorate.addPaintListener(new PaintListener() { // Using // a // PaintListener // as // bounds // are // only // set // AFTER // activateCell() @Override public void paintControl(PaintEvent e) { controlToDecorate.removePaintListener(this); int position = SWT.TOP; final Rectangle textBounds = controlToDecorate .getBounds(); final Rectangle parentClientArea = controlToDecorate .getParent().getClientArea(); if ((parentClientArea.x + parentClientArea.width) > (textBounds.x + textBounds.width + errorImage .getBounds().width)) { position |= SWT.RIGHT; } else { position |= SWT.LEFT; } ControlDecorationProvider.this.errorDecoration = newControlDecoration( controlToDecorate, errorImage, position); } }); } else { this.errorDecoration = newControlDecoration(controlToDecorate, errorImage, this.decorationPositionOverride); } } } /** * Will create a new {@link ControlDecoration} for the given {@link Control} * . Setting position, image and text to the decoration, hiding it * initially. * * @param controlToDecorate * The {@link Control} to create the decoration for. * @param errorImage * The image to be shown adjacent to the control. Should never be * <code>null</code>. * @param position * bit-wise or of position constants (<code>SWT.TOP</code>, * <code>SWT.BOTTOM</code>, <code>SWT.LEFT</code>, * <code>SWT.RIGHT</code>, and <code>SWT.CENTER</code>). * @return The created {@link ControlDecoration} */ private ControlDecoration newControlDecoration(Control controlToDecorate, Image errorImage, int position) { final ControlDecoration errorDecoration = new ControlDecoration( controlToDecorate, position); errorDecoration.setImage(errorImage); errorDecoration.setDescriptionText(this.errorDecorationText); errorDecoration.hide(); return errorDecoration; } }