/******************************************************************************* * Copyright (c) 2012, 2013, 2014 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 java.util.List; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.validate.IDataValidator; import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; import org.eclipse.nebula.widgets.nattable.edit.EditController; import org.eclipse.nebula.widgets.nattable.edit.ICellEditHandler; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; import org.eclipse.nebula.widgets.nattable.ui.matcher.IMouseEventMatcher; import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; /** * Interface for implementing editors that can be used in a NatTable. Such an * editor is mainly a wrapper for a native SWT control, providing additional * functionality to support NatTable specific handling, e.g. conversion, * validation, model updates. * * Implementations are responsible for capturing new cell value during cell * edit. */ public interface ICellEditor { /** * This method will be called by the framework to activate this cell editor. * It initializes the the values needed for further processing of the editor * and will add listeners for general behavior of the editor control. * * @param parent * The parent Composite, needed for the creation of the editor * control. * @param originalCanonicalValue * The value that should be put to the activated editor control. * @param editMode * The {@link EditModeEnum} which is used to activate special * behavior and styling. This is needed because activating an * editor inline will have different behavior (e.g. moving the * selection after commit) and styling than rendering the editor * on a subdialog. * @param editHandler * The {@link ICellEditHandler} that will be used on commit. * @param cell * The cell whose corresponding editor should be activated. * @param configRegistry * The {@link IConfigRegistry} containing the configuration of * the current NatTable instance. This is necessary because the * editors in the current architecture are not aware of the * NatTable instance they are running in. * @return The SWT {@link Control} to be used for capturing the new cell * value. */ public Control activateCell(Composite parent, Object originalCanonicalValue, EditModeEnum editMode, ICellEditHandler editHandler, ILayerCell cell, IConfigRegistry configRegistry); /** * @return The column index of the cell to which this editor is attached. */ int getColumnIndex(); /** * @return The row index of the cell to which this editor is attached. */ int getRowIndex(); /** * @return The column position of the cell to which this editor is attached. */ int getColumnPosition(); /** * @return The row position of the cell to which this editor is attached. */ int getRowPosition(); /** * Returns the current value in this editor prior to conversion. For a text * editor that is used to edit integer values, this would mean it returns * the text value instead of the converted integer value. This method is * only intended to be used internally . * * @return The current value in this editor prior to conversion. */ Object getEditorValue(); /** * Sets the given value to editor control. This method is used to put the * display values to the wrapped editor. * * @param value * The display value to set to the wrapped editor control. */ void setEditorValue(Object value); /** * Converts the current value in this editor using the configured * {@link IDisplayConverter}. If there is no {@link IDisplayConverter} * registered for this editor, the value itself will be returned. * * @return The canonical value after converting the current value or the * value itself if no {@link IDisplayConverter} is configured. * @throws RuntimeException * for conversion failures. As the {@link IDisplayConverter} * interface does not specify throwing checked Exceptions on * converting data, only unchecked Exceptions can occur. This is * needed to stop further commit processing if the conversion * failed. * @see IDisplayConverter */ Object getCanonicalValue(); /** * Converts the current value in this editor using the configured * {@link IDisplayConverter}. If there is no {@link IDisplayConverter} * registered for this editor, the value itself will be returned. Will use * the specified {@link IEditErrorHandler} for handling conversion errors. * * @param conversionErrorHandler * The error handler that will be activated in case of conversion * errors. * @return The canonical value after converting the current value or the * value itself if no {@link IDisplayConverter} is configured. * @throws RuntimeException * for conversion failures. As the {@link IDisplayConverter} * interface does not specify throwing checked Exceptions on * converting data, only unchecked Exceptions can occur. This is * needed to stop further commit processing if the conversion * failed. * @see IDisplayConverter */ Object getCanonicalValue(IEditErrorHandler conversionErrorHandler); /** * Sets the given canonical value to the wrapped editor control. Prior to * setting the value it needs to be converted to the display value, using * the configured {@link IDisplayConverter}. * * @param canonicalValue * The canonical value to be set to the wrapped editor control. */ void setCanonicalValue(Object canonicalValue); /** * Validates the given value using the configured {@link IDataValidator}. * This method should be called with the value converted before by using * {@link ICellEditor#getCanonicalValue()}. * * @param canonicalValue * The canonical value to validate. * @return <code>true</code> if the current value in this editor is valid or * no {@link IDataValidator} is registered, <code>false</code> if * the value is not valid. */ boolean validateCanonicalValue(Object canonicalValue); /** * Validates the current value in this editor using the configured * {@link IDataValidator}. Validates the given value using the configured * {@link IDataValidator}. This method should be called with the value * converted before by using {@link ICellEditor#getCanonicalValue()}. Will * use the specified {@link IEditErrorHandler} for handling validation * errors. * * @param canonicalValue * The canonical value to validate. * @param validationErrorHandler * The error handler that will be activated in case of validation * errors. * @return <code>true</code> if the current value in this editor is valid or * no {@link IDataValidator} is registered, <code>false</code> if * the value is not valid. */ public boolean validateCanonicalValue(Object canonicalValue, IEditErrorHandler validationErrorHandler); /** * Commits the current value of this editor. Will first try to convert and * validate the current value, and if that succeeds and the value can be * committed to the data model, the editor will be closed afterwards. * * @param direction * The direction the selection within the NatTable should move * after commit has finished. * @return <code>true</code> if the commit operation succeeded, * <code>false</code> if the current value could not be committed. A * value might not be committed for example if the conversion or the * validation failed. */ boolean commit(MoveDirectionEnum direction); /** * Commits the current value of this editor. Will first try to convert the * current value. Then it is checked if the validation should be executed * which can be specified via parameter. If that succeeds and the value can * be committed to the data model, the editor will be closed afterwards. * * @param direction * The direction the selection within the NatTable should move * after commit has finished. * @param closeAfterCommit * flag to tell whether this editor needs to closed after the * commit or if it should stay open. * @return <code>true</code> if the commit operation succeeded, * <code>false</code> if the current value could not be committed. A * value might not be committed for example if the conversion or the * validation failed. */ boolean commit(MoveDirectionEnum direction, boolean closeAfterCommit); /** * Commits the current value of this editor. * * @param direction * The direction the selection within the NatTable should move * after commit has finished. * @param closeAfterCommit * flag to tell whether this editor needs to closed after the * commit or if it should stay open. * @param skipValidation * Flag to specify whether the current value in this editor * should be validated or not. * @return <code>true</code> if the commit operation succeeded, * <code>false</code> if the current value could not be committed. A * value might not be committed for example if the conversion or the * validation failed. */ boolean commit(MoveDirectionEnum direction, boolean closeAfterCommit, boolean skipValidation); /** * Close/dispose the contained {@link Control} */ void close(); /** * @return <code>true</code> if this editor has been closed already, * <code>false</code> if it is still open */ boolean isClosed(); /** * @return The editor control that is wrapped by this ICellEditor. */ Control getEditorControl(); /** * Creates the editor control that is wrapped by this ICellEditor. Will use * the style configurations in ConfigRegistry for styling the control. * * @param parent * The Composite that will be the parent of the new editor * control. Can not be <code>null</code> * @return The created editor control that is wrapped by this ICellEditor. */ Control createEditorControl(Composite parent); /** * Determines whether the editor should be opened inline or using a dialog. * By default it will check this by configuration attribute * {@link EditConfigAttributes#OPEN_IN_DIALOG}. If there is no configuration * found for this, <code>true</code> will be returned for backwards * compatibility. * <p> * If this method returns <code>true</code>, the editor will be opened * inline (default). * </p> * <p> * There might be editors that are only able to be opened in a dialog. These * implementations need to override this method to always return * <code>false</code>, so the editor never gets opened inline. * </p> * * @param configRegistry * The {@link IConfigRegistry} to retrieve the configuration for * inline/dialog editing out of. Needed here because the instance * {@link IConfigRegistry} might not be set on calling this * method. * @param configLabels * The labels out of the LabelStack of the cell whose editor * should be activated. Needed here because this method needs to * be called prior to activation to determine where to activate * it. * @return <code>true</code> if the editor should opened inline, * <code>false</code> if not. * @see EditConfigAttributes#OPEN_IN_DIALOG */ boolean openInline(IConfigRegistry configRegistry, List<String> configLabels); /** * Determines whether this editor supports multi edit behavior or not. If * this method returns <code>true</code>, on selecting and pressing F2 on * several cells that are editable, having the same editor type and * converter registered, a multi edit dialog will open. By default this * method will return <code>true</code>. You can change this behavior by * setting the configuration attribute * {@link EditConfigAttributes#SUPPORT_MULTI_EDIT}. * <p> * You should consider returning <code>false</code> e.g. if the update * operation is complex or you use conditional validation, where a value is * validated against another value in the data model. * * @param configRegistry * The {@link IConfigRegistry} to retrieve the configuration for * multi edit support out of. Needed here because the instance * {@link IConfigRegistry} might not be set on calling this * method. * @param configLabels * The labels out of the LabelStack of the cell whose editor * should be activated. Needed here because this method needs to * be called prior to activation to determine where to activate * it. * @return <code>true</code> if this editor will open in a subdialog for * multi editing, <code>false</code> if the multi editing of this * kind of cell editor is not supported. * @see EditConfigAttributes#SUPPORT_MULTI_EDIT */ boolean supportMultiEdit(IConfigRegistry configRegistry, List<String> configLabels); /** * This is a very special configuration to tell whether an ICellEditor * should open a multi edit dialog for multi editing or not. Usually for * multi editing there should be always a multi edit dialog be opened. There * are only special cases where this doesn't make sense. The only types of * ICellEditors that shouldn't open multi edit dialogs are editors that * change their values directly and there is no interactively editor control * opened, e.g. checkboxes. * * @return <code>true</code> if for multi editing a multi edit dialog should * be opened, <code>false</code> if the multi editing should be * performed directly without opening a multi edit dialog. Note: * <code>true</code> is the default value and changing it to * <code>false</code> for a custom editor might cause issues if not * dealed correctly. */ boolean openMultiEditDialog(); /** * Determines behavior after committing the value of this editor in * combination with selection movement. If this method return * <code>true</code> and the selection is moved after committing, the editor * for the newly selected cell will be activated immediately. If this method * returns <code>false</code> or the selection is not moved after commit, no * action should be executed. * <p> * The behavior previous to this configuration was to not open the adjacent * editor. So if there is no configuration registered for this, * <code>false</code> will be returned by default. * </p> * <p> * Note: It only makes sense to call this method if the editor is already * activated. Calling this method on an editor that has not been activated * already will lead to exceptions. * </p> * * @return <code>true</code> if the adjacent editor should be opened if the * selection moves after commit, <code>false</code> if not. * @see EditConfigAttributes#OPEN_ADJACENT_EDITOR */ boolean openAdjacentEditor(); /** * This method is intended to be used by {@link IMouseEventMatcher} * implementations that need to check for the editor and the click position * to determine whether an editor should be activated or not. By default * this method will return <code>true</code>. Special implementations that * need a different behavior need to return <code>false</code> instead. E.g. * checkbox editors should only be activated in case the icon that * represents the checkbox is clicked. * * @return <code>true</code> if this {@link ICellEditor} should be activated * by clicking at any position in the corresponding cell, * <code>false</code> if there need to be a special position * clicked. */ boolean activateAtAnyPosition(); /** * This method is asked on tab traversal whether this {@link ICellEditor} * should be automatically activated or not. This is necessary to avoid * automatically changing the value of a checkbox or opening a dialog editor * on traversal. * * @param configRegistry * The {@link IConfigRegistry} to retrieve the configuration out * of. Needed here because the instance {@link IConfigRegistry} * might not be set on calling this method. * @param configLabels * The labels out of the LabelStack of the cell whose editor * should be activated. * @return <code>true</code> if this {@link ICellEditor} should be activated * in case of tab traversal, <code>false</code> if not. * @see EditConfigAttributes#ACTIVATE_EDITOR_ON_TRAVERSAL */ boolean activateOnTraversal(IConfigRegistry configRegistry, List<String> configLabels); /** * This method is intended to add listeners to the wrapped editor control to * add context related behavior. For example, in {@link EditModeEnum#INLINE} * by default this should add a FocusListener that commits the current value * if the editor control loses focus. * <p> * This method was introduced mainly because of two issues: * <ol> * <li>On Mac OS calling setBounds() on a Control will cause losing focus. * So listeners need to be added after this method is called by the * EditController, otherwise on activating the editor it will be closed * immediately after the correct size is calculated.</li> * <li>The main concept for cell editor activation is, that the editor * control is disposed on closing the editor. This way everytime the cell * editor is activated, a new editor control will be created. If an editor * is implemented that needs to keep the editor control after closing the * editor, it needs to be ensured that the listeners are removed again. * Otherwise the listeners would be added again everytime the editor is * activated.</li> * </ol> * This method will be called automatically by * {@link EditController#editCell(ILayerCell, Composite, Object, IConfigRegistry)}. */ void addEditorControlListeners(); /** * This method is intended to remove listeners from the wrapped editor * control that was added by {@link ICellEditor#addEditorControlListeners()} * before to add context related behavior. * <p> * This method was introduced to add the possibility to create an * {@link ICellEditor} whose wrapped editor control should not be disposed * on closing the editor. * </p> * <p> * The main concept for cell editor activation is, that the editor control * is disposed on closing the editor. This way everytime the cell editor is * activated, a new editor control will be created. If an editor is * implemented that needs to keep the editor control after closing the * editor, it needs to be ensured that the listeners are removed again. * Otherwise the listeners would be added again everytime the editor is * activated. * </p> * This method needs to be called on {@link ICellEditor#close()}. There is * no automatical call by the framework if you are not using the abstract * implementation of {@link ICellEditor}. */ void removeEditorControlListeners(); /** * This method is used to calculate the bounds of the edit control when * opened inline. By default it should return the given cell bounds to match * the cell structure in NatTable. For several cases it might be useful to * return the preferred size to show all content rather than trimming the * control to the cell size. * <p> * Note: By changing the bounds you should ensure to only modify width and * height attributes and not x and y coordinate, otherwise the editor * control will show up somewhere else and not in place of the cell that is * edited. * * @param cellBounds * The bounds of the cell for which the editor is opened. * @return The bounds of the editor control that should be applied. By * default the cell bounds for several cases bigger. */ Rectangle calculateControlBounds(Rectangle cellBounds); }