blob: 98cdcb2f2838ff038e8d1536c8866065f66e6852 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2021 Original NatTable authors and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Original NatTable authors and others - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.waltable.edit.editor;
import java.util.List;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.statet.ecommons.waltable.config.IConfigRegistry;
import org.eclipse.statet.ecommons.waltable.coordinate.Direction;
import org.eclipse.statet.ecommons.waltable.data.convert.IDisplayConverter;
import org.eclipse.statet.ecommons.waltable.data.validate.IDataValidator;
import org.eclipse.statet.ecommons.waltable.edit.EditConfigAttributes;
import org.eclipse.statet.ecommons.waltable.edit.EditController;
import org.eclipse.statet.ecommons.waltable.edit.EditMode;
import org.eclipse.statet.ecommons.waltable.edit.ICellEditHandler;
import org.eclipse.statet.ecommons.waltable.layer.cell.ILayerCell;
import org.eclipse.statet.ecommons.waltable.ui.matcher.IMouseEventMatcher;
/**
* 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 behaviour 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 EditMode} which is used to activate special behaviour
* and styling. This is needed because activating an editor inline will have
* different behaviour (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,
EditMode editMode,
ICellEditHandler editHandler,
ILayerCell cell,
IConfigRegistry configRegistry
);
/**
* @return The column position of the cell to which this editor is attached.
*/
long getColumnPosition();
/**
* @return The row position of the cell to which this editor is attached.
*/
long 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(Direction 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(Direction 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(Direction 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 behaviour 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 behaviour 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 behaviour 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 behaviour 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 behaviour 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 intended to add listeners to the wrapped editor control to add context related
* behaviour. For example, in {@link EditMode#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 behaviour.
* <p>
* This method was introduced to add the possibilty 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);
}