| /******************************************************************************* |
| * Copyright (c) 2012, 2020 Original 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 authors and others - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.nebula.widgets.nattable.edit.config; |
| |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.nebula.widgets.nattable.Messages; |
| import org.eclipse.nebula.widgets.nattable.data.convert.ConversionFailedException; |
| import org.eclipse.nebula.widgets.nattable.data.validate.ValidationFailedException; |
| import org.eclipse.nebula.widgets.nattable.edit.editor.AbstractEditErrorHandler; |
| import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor; |
| import org.eclipse.nebula.widgets.nattable.edit.editor.IEditErrorHandler; |
| import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| |
| /** |
| * Strategy class for conversion/validation failures. If the entered value is |
| * not valid, a warning dialog with the corresponding error message will show |
| * up. The warning dialog gives the opportunity to discard the invalid input or |
| * change it, which will cause the editor to stay open. Only handles errors on |
| * commit. |
| */ |
| public class DialogErrorHandling extends AbstractEditErrorHandler { |
| |
| /** |
| * The {@link ICellEditor} for which this {@link DialogErrorHandling} is |
| * activated. Needed so it is possible to operate on it dependent on the |
| * users choice. |
| */ |
| protected ICellEditor editor; |
| /** |
| * Flag to configure if this dialog allows to commit invalid data. This is |
| * necessary to implement cross validation in NatTable by using dialogs to |
| * tell the user what is wrong. By default this value is set to |
| * <code>false</code> as cross validation is not the default validation use |
| * case. |
| */ |
| protected boolean allowCommit = false; |
| /** |
| * The shell title that will be used if there is no conversion or validation |
| * shell title configured. |
| */ |
| private String failureShellTitle = "%DialogErrorHandlingStrategy.failureTitle"; //$NON-NLS-1$ |
| /** |
| * The shell title that will be used in case this |
| * {@link DialogErrorHandling} is called to handle a |
| * {@link ConversionFailedException}. |
| */ |
| private String conversionFailureShellTitle = "%DialogErrorHandlingStrategy.conversionFailureTitle"; //$NON-NLS-1$ |
| /** |
| * The shell title that will be used in case this |
| * {@link DialogErrorHandling} is called to handle a |
| * {@link ValidationFailedException}. |
| */ |
| private String validationFailureShellTitle = "%DialogErrorHandlingStrategy.validationFailureTitle"; //$NON-NLS-1$ |
| /** |
| * The text on the button for changing the entered value. |
| */ |
| private String changeButtonLabel = "%DialogErrorHandlingStrategy.warningDialog.changeButton"; //$NON-NLS-1$ |
| /** |
| * The text on the button to discard the entered value. |
| */ |
| private String discardButtonLabel = "%DialogErrorHandlingStrategy.warningDialog.discardButton"; //$NON-NLS-1$ |
| /** |
| * The text on the button to commit the entered invalid value. Needed to |
| * support cross validation. |
| */ |
| private String commitButtonLabel = "%DialogErrorHandlingStrategy.warningDialog.commitButton"; //$NON-NLS-1$ |
| |
| /** |
| * Create a new {@link DialogErrorHandling} with no underlying |
| * {@link IEditErrorHandler} that does not support cross validation. |
| */ |
| public DialogErrorHandling() { |
| this(null, false); |
| } |
| |
| /** |
| * Create a new {@link DialogErrorHandling} with no underlying |
| * {@link IEditErrorHandler} that gives the opportunity to configure the |
| * error handling for cross validation. |
| * |
| * @param allowCommit |
| * Flag to configure if this dialog allows to commit invalid |
| * data. If this parameter is set to <code>true</code>, an |
| * additional button for committing the invalid data will be |
| * provided within the dialog. |
| */ |
| public DialogErrorHandling(boolean allowCommit) { |
| this(null, allowCommit); |
| |
| } |
| |
| /** |
| * Create a new {@link DialogErrorHandling} using the given |
| * {@link IEditErrorHandler} as the underlying to allow chaining of error |
| * handling. Using this constructor there is no cross validation support. |
| * |
| * @param underlyingErrorHandler |
| * The underlying {@link IEditErrorHandler} |
| */ |
| public DialogErrorHandling(IEditErrorHandler underlyingErrorHandler) { |
| this(underlyingErrorHandler, false); |
| } |
| |
| /** |
| * Create a new {@link DialogErrorHandling} using the given |
| * {@link IEditErrorHandler} as the underlying to allow chaining of error |
| * handling. |
| * |
| * @param underlyingErrorHandler |
| * The underlying {@link IEditErrorHandler} |
| * @param allowCommit |
| * Flag to configure if this dialog allows to commit invalid |
| * data. If this parameter is set to <code>true</code>, an |
| * additional button for committing the invalid data will be |
| * provided within the dialog. |
| */ |
| public DialogErrorHandling(IEditErrorHandler underlyingErrorHandler, boolean allowCommit) { |
| super(underlyingErrorHandler); |
| this.allowCommit = allowCommit; |
| } |
| |
| /** |
| * {@inheritDoc} After the error is handled by its underlying |
| * {@link IEditErrorHandler}, a dialog will be opened showing the error |
| * message to the user, giving the opportunity to decide if the entered |
| * value should be discarded or if the editor should stay open so the value |
| * can be modified. |
| */ |
| @Override |
| public void displayError(ICellEditor cellEditor, Exception e) { |
| super.displayError(cellEditor, e); |
| this.editor = cellEditor; |
| |
| String shellTitle = getFailureShellTitle(); |
| if (e instanceof ConversionFailedException |
| && !getConversionFailureShellTitle().isEmpty()) { |
| shellTitle = getConversionFailureShellTitle(); |
| } else if (e instanceof ValidationFailedException |
| && !getValidationFailureShellTitle().isEmpty()) { |
| shellTitle = getValidationFailureShellTitle(); |
| } |
| showWarningDialog(e.getLocalizedMessage(), shellTitle); |
| } |
| |
| /** |
| * Shows a warning dialog if the conversion or the validation returned an |
| * error message. Otherwise nothing happens. |
| * |
| * @param dialogMessage |
| * the dialog message |
| * @param dialogTitle |
| * the dialog title |
| */ |
| protected void showWarningDialog(String dialogMessage, String dialogTitle) { |
| if (!isWarningDialogActive() && dialogMessage != null) { |
| // conversion/validation failed - so open dialog with error message |
| |
| String[] buttonLabels = this.allowCommit ? new String[] { getChangeButtonLabel(), getDiscardButtonLabel(), getCommitButtonLabel() } |
| : new String[] { getChangeButtonLabel(), getDiscardButtonLabel() }; |
| |
| MessageDialog warningDialog = new MessageDialog( |
| Display.getDefault().getActiveShell(), |
| dialogTitle, |
| null, |
| dialogMessage, |
| MessageDialog.WARNING, |
| buttonLabels, |
| 0); |
| |
| // if discard was selected close the editor |
| int returnCode = warningDialog.open(); |
| if (returnCode == 1) { |
| this.editor.close(); |
| } |
| // if commit was selected, commit the value by skipping the |
| // validation |
| else if (returnCode == 2) { |
| this.editor.commit(MoveDirectionEnum.NONE, true, true); |
| } |
| } |
| } |
| |
| /** |
| * Checks if the current active Shell is a conversion/validation failure |
| * warning dialog. As a Shell has not id it is checked if the Shell title is |
| * for conversion or validation failure in localized format. |
| * |
| * @return <code>true</code> if a warning dialog is active |
| */ |
| protected boolean isWarningDialogActive() { |
| // check if the current active shell is a conversion or validation |
| // failure warning dialog |
| Shell control = Display.getDefault().getActiveShell(); |
| return (control != null |
| && (getConversionFailureShellTitle().equals(control.getText()) |
| || getValidationFailureShellTitle().equals(control.getText()) |
| || getFailureShellTitle().equals(control.getText()))); |
| } |
| |
| /** |
| * @return The shell title that will be used if there is no conversion or |
| * validation shell title configured. |
| */ |
| public String getFailureShellTitle() { |
| return getLocalized(this.failureShellTitle); |
| } |
| |
| /** |
| * @param failureShellTitle |
| * The shell title that should be used if there is no conversion |
| * or validation shell title configured. |
| */ |
| public void setFailureShellTitle(String failureShellTitle) { |
| this.failureShellTitle = failureShellTitle; |
| } |
| |
| /** |
| * @return The shell title that will be used in case this |
| * {@link DialogErrorHandling} is called to handle a |
| * {@link ConversionFailedException}. |
| */ |
| public String getConversionFailureShellTitle() { |
| return getLocalized(this.conversionFailureShellTitle); |
| } |
| |
| /** |
| * @param conversionFailureShellTitle |
| * The shell title that should be used in case this |
| * {@link DialogErrorHandling} is called to handle a |
| * {@link ConversionFailedException}. |
| */ |
| public void setConversionFailureShellTitle(String conversionFailureShellTitle) { |
| this.conversionFailureShellTitle = conversionFailureShellTitle; |
| } |
| |
| /** |
| * @return The shell title that will be used in case this |
| * {@link DialogErrorHandling} is called to handle a |
| * {@link ValidationFailedException}. |
| */ |
| public String getValidationFailureShellTitle() { |
| return getLocalized(this.validationFailureShellTitle); |
| } |
| |
| /** |
| * @param validationFailureShellTitle |
| * The shell title that should be used in case this |
| * {@link DialogErrorHandling} is called to handle a |
| * {@link ValidationFailedException}. |
| */ |
| public void setValidationFailureShellTitle(String validationFailureShellTitle) { |
| this.validationFailureShellTitle = validationFailureShellTitle; |
| } |
| |
| /** |
| * @return The text on the button for changing the entered value. |
| */ |
| public String getChangeButtonLabel() { |
| return getLocalized(this.changeButtonLabel); |
| } |
| |
| /** |
| * @param changeButtonLabel |
| * The text on the button for changing the entered value. |
| */ |
| public void setChangeButtonLabel(String changeButtonLabel) { |
| this.changeButtonLabel = changeButtonLabel; |
| } |
| |
| /** |
| * @return The text on the button to discard the entered value. |
| */ |
| public String getDiscardButtonLabel() { |
| return getLocalized(this.discardButtonLabel); |
| } |
| |
| /** |
| * @param discardButtonLabel |
| * The text on the button to discard the entered value. |
| */ |
| public void setDiscardButtonLabel(String discardButtonLabel) { |
| this.discardButtonLabel = discardButtonLabel; |
| } |
| |
| /** |
| * @return The text on the button to commit the entered value. |
| * @since 1.4 |
| */ |
| public String getCommitButtonLabel() { |
| return getLocalized(this.commitButtonLabel); |
| } |
| |
| /** |
| * @param commitButtonLabel |
| * The text on the button to commit the entered value. |
| * @since 1.4 |
| */ |
| public void setCommitButtonLabel(String commitButtonLabel) { |
| this.commitButtonLabel = commitButtonLabel; |
| } |
| |
| private String getLocalized(String text) { |
| return (text != null) ? Messages.getLocalizedMessage(text) : ""; //$NON-NLS-1$ |
| } |
| |
| } |