Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur van Dorp2020-08-06 08:33:01 +0000
committerArthur van Dorp2020-08-06 09:23:16 +0000
commit153d50fcbfc95c6aa2ec3dd87f4f6e7a936d6b42 (patch)
tree345001b94c504e95b3965bb27298e9472ff85659
parent1a3324828d6443df9355479af5f4c4c8b2df7d76 (diff)
downloadorg.eclipse.scout.rt-releases/4.2.x.tar.gz
org.eclipse.scout.rt-releases/4.2.x.tar.xz
org.eclipse.scout.rt-releases/4.2.x.zip
Bug 453504 - SWT: Nullpointer when toggling a checkable4.2.0_R37releases/4.2.x
Manual cherry pick from 83ab7b7c921bd9531411c5cd6e2f6ad5e541e73e Mon Sep 17 00:00:00 2001 Daniel Wiehl <daniel.wiehl@bsiag.com> and Frank Ammeter Change-Id: If67a59d2ef4d767e543c3a82174960f145ff24ef Signed-off-by: Arthur van Dorp <Arthur.vanDorp@bsi-software.com> Reviewed-on: https://git.eclipse.org/r/c/scout/org.eclipse.scout.rt/+/167343
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/SwtScoutTable.java80
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java27
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java665
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableCellEditor.java427
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableEditingSupport.java126
5 files changed, 606 insertions, 719 deletions
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/SwtScoutTable.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/SwtScoutTable.java
index d4452f1105..d49c4380eb 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/SwtScoutTable.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/SwtScoutTable.java
@@ -23,8 +23,6 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.CellEditor;
-import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
@@ -59,7 +57,7 @@ import org.eclipse.scout.rt.ui.swt.ISwtEnvironment;
import org.eclipse.scout.rt.ui.swt.SwtMenuUtility;
import org.eclipse.scout.rt.ui.swt.action.menu.SwtScoutContextMenu;
import org.eclipse.scout.rt.ui.swt.basic.SwtScoutComposite;
-import org.eclipse.scout.rt.ui.swt.basic.table.celleditor.SwtScoutTableCellEditor;
+import org.eclipse.scout.rt.ui.swt.basic.table.celleditor.TableEditingSupport;
import org.eclipse.scout.rt.ui.swt.ext.table.TableEx;
import org.eclipse.scout.rt.ui.swt.ext.table.util.TableRolloverSupport;
import org.eclipse.scout.rt.ui.swt.extension.UiDecorationExtensionPoint;
@@ -113,7 +111,6 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
private Listener m_columnListener = new P_TableColumnListener();
private SelectionListener m_columnSortListener = new P_ColumnSortListener();
private TableColumnManager m_columnManager = new TableColumnManager();
- private SwtScoutTableCellEditor m_cellEditorComposite;
private int[] m_uiColumnOrder;
private Menu m_contextMenu;
private Menu m_headerMenu;
@@ -158,9 +155,6 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
setSwtTableViewer(viewer);
setSwtField(table);
- //cell editing support
- m_cellEditorComposite = new SwtScoutTableCellEditor(this);
-
// header menu
m_headerMenu = new Menu(viewer.getTable().getShell(), SWT.POP_UP);
table.addMenuDetectListener(new P_SwtHeaderMenuDetectListener());
@@ -238,10 +232,8 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
for (TableColumn col : getSwtField().getColumns()) {
col.dispose();
}
- /*
- * bug: swt table first column can not be aligned nor an image can be set.
- * see also SwtScoutTableCellEditor
- */
+
+ // SWT bug 43910: Create an invisible dummy column to omit SWT indention bug.
TableColumn dummyCol = new TableColumn(getSwtField(), SWT.LEFT);
dummyCol.setWidth(0);
dummyCol.setResizable(false);
@@ -260,35 +252,54 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
m_columnManager = new TableColumnManager();
}
m_columnManager.initialize(scoutColumnsOrdered);
+
+ boolean hasEditors = false;
for (IColumn<?> scoutColumn : scoutColumnsOrdered) {
IHeaderCell headerCell = scoutColumn.getHeaderCell();
+
int style = SwtUtility.getHorizontalAlignment(headerCell.getHorizontalAlignment());
- TableColumn swtCol = new TableColumn(getSwtField(), style);
- swtCol.setData(KEY_SCOUT_COLUMN, scoutColumn);
+ final TableViewerColumn viewerColumn = new TableViewerColumn(getSwtTableViewer(), style);
+ TableColumn swtColumn = viewerColumn.getColumn();
+ swtColumn.setData(KEY_SCOUT_COLUMN, scoutColumn);
- TableViewerColumn viewerColumn = new TableViewerColumn(getSwtTableViewer(), swtCol);
+ // Install the column's LabelProvider.
viewerColumn.setLabelProvider(new SwtScoutCellLabelProvider(scoutColumn, getEnvironment()));
- swtCol.setMoveable(true);
- swtCol.setToolTipText(headerCell.getTooltipText());
- updateHeaderText(swtCol, scoutColumn);
- swtCol.setWidth(scoutColumn.getWidth());
+ // Install editable support.
+ if (scoutColumn.isEditable()) {
+ viewerColumn.setEditingSupport(new TableEditingSupport(getSwtTableViewer(), swtColumn, getEnvironment()));
+ hasEditors = true;
+ }
+
+ swtColumn.setMoveable(true);
+ swtColumn.setToolTipText(headerCell.getTooltipText());
+ updateHeaderText(swtColumn, scoutColumn);
+ swtColumn.setWidth(scoutColumn.getWidth());
if (scoutColumn.isFixedWidth()) {
- swtCol.setResizable(false);
+ swtColumn.setResizable(false);
}
if (headerCell.isSortActive()) {
- getSwtField().setSortColumn(swtCol);
+ getSwtField().setSortColumn(swtColumn);
getSwtField().setSortDirection(headerCell.isSortAscending() ? SWT.UP : SWT.DOWN);
}
if (sortEnabled) {
- swtCol.addSelectionListener(m_columnSortListener);
+ swtColumn.addSelectionListener(m_columnSortListener);
}
- swtCol.addListener(SWT.Move, m_columnListener);
- swtCol.addListener(SWT.Resize, m_columnListener);
+ swtColumn.addListener(SWT.Move, m_columnListener);
+ swtColumn.addListener(SWT.Resize, m_columnListener);
+ }
+
+ // increase row height when editors are present.
+ if (hasEditors) {
+ getSwtTableViewer().getTable().addListener(SWT.MeasureItem, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ event.height = Math.max(event.height, UiDecorationExtensionPoint.getLookAndFeel().getLogicalGridLayoutRowHeight());
+ }
+ });
}
+
m_uiColumnOrder = getSwtField().getColumnOrder();
- //update cell editors
- m_cellEditorComposite.initialize();
}
finally {
m_redrawHandler.popControlChanging();
@@ -512,7 +523,7 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
break;
}
case TableEvent.TYPE_REQUEST_FOCUS_IN_CELL: {
- //start editing
+ // start edit-mode when entering editable cell by traversal key.
int swtCol = -1;
TableColumn[] swtColumns = getSwtField().getColumns();
for (int c = 0; c < swtColumns.length; c++) {
@@ -1006,18 +1017,7 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
}
@Override
- protected void triggerEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
- //Make sure editor is closed when clicking on another cell. Mainly necessary when using the second mouse button to open the context menu
- for (CellEditor editor : getCellEditors()) {
- if (editor != null && editor.isActivated()) {
- applyEditorValue();
- }
- }
- super.triggerEditorActivationEvent(event);
- }
-
- @Override
- public void applyEditorValue() {
+ public void applyEditorValue() { // public visibility to close editor in case of an empty row click.
super.applyEditorValue();
}
}
@@ -1092,8 +1092,8 @@ public class SwtScoutTable extends SwtScoutComposite<ITable> implements ISwtScou
TableViewer swtTableViewer = getSwtTableViewer();
switch (event.type) {
case SWT.MouseDown: {
- //Close cell editor on empty space click
- if (swtTableViewer.getTable().getItem(new Point(event.y, event.y)) == null && swtTableViewer instanceof P_TableViewerEx) {
+ // Close cell editor on empty space click.
+ if (swtTableViewer.isCellEditorActive() && swtTableViewer.getTable().getItem(new Point(event.y, event.y)) == null) {
((P_TableViewerEx) swtTableViewer).applyEditorValue();
}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java
index e62ec8a2bd..eb61a2a51c 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java
@@ -27,7 +27,6 @@ import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;
import org.eclipse.scout.rt.ui.swt.basic.SwtScoutComposite;
import org.eclipse.scout.rt.ui.swt.form.fields.ISwtScoutFormField;
-import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
import org.eclipse.scout.rt.ui.swt.window.popup.SwtScoutDropDownPopup;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
@@ -38,9 +37,18 @@ import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
/**
+ * <p>
* Wraps a {@link IFormField} to be displayed as popup cell editor.
+ * </p>
+ * Thereby, {@link SwtScoutComposite} is constructed as following:
+ * <ul>
+ * <li>{@link SwtScoutComposite#getSwtField()}: references the the UI representation of the FormField that is displayed
+ * within the popup {@link Shell}; is lazy bound the time the {@link Shell} is painted for the first time</li>
+ * <li>{@link SwtScoutComposite#getSwtContainer()}: references the owner control the Shell is bound to</li>
+ * </ul>
*/
public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
@@ -55,8 +63,6 @@ public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
private int m_prefHeight;
private int m_style;
- private Control m_swtFormField;
-
private final Set<IFormFieldPopupListener> m_listeners = Collections.synchronizedSet(new HashSet<IFormFieldPopupListener>());
public SwtScoutFormFieldPopup(Composite owner) {
@@ -127,10 +133,12 @@ public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
final IForm form = createForm();
if (form != null) {
m_swtScoutPopup.showForm(form);
- m_swtFormField = findSwtFormField(m_swtScoutPopup.getUiForm().getSwtField(), getScoutObject());
- if (m_swtFormField == null) {
+
+ final Control swtFormField = findSwtFormField(m_swtScoutPopup.getUiForm().getSwtField(), getScoutObject());
+ if (swtFormField == null) {
LOG.warn("UI-FormField could not be found in UI-Form");
}
+ setSwtField(swtFormField);
// Install listener to be notified about traversal events.
installTraverseListener(m_swtScoutPopup.getShell(), traverseListener);
@@ -167,15 +175,6 @@ public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
m_swtScoutPopup.closePart();
}
- /**
- * Touches the field to write its UI value back to the model.
- */
- public void touch() {
- if (m_swtFormField != null && !m_swtFormField.isDisposed()) {
- SwtUtility.runSwtInputVerifier(m_swtFormField);
- }
- }
-
public void addListener(IFormFieldPopupListener listener) {
m_listeners.add(listener);
}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java
deleted file mode 100644
index e9cf44603c..0000000000
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java
+++ /dev/null
@@ -1,665 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 BSI Business Systems Integration AG.
- * 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:
- * BSI Business Systems Integration AG - initial API and implementation
- ******************************************************************************/
-package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
-
-import org.eclipse.jface.viewers.CellEditor;
-import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
-import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
-import org.eclipse.jface.viewers.ICellModifier;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.ViewerCell;
-import org.eclipse.scout.commons.BooleanUtility;
-import org.eclipse.scout.commons.CompareUtility;
-import org.eclipse.scout.commons.holders.BooleanHolder;
-import org.eclipse.scout.commons.holders.Holder;
-import org.eclipse.scout.commons.logger.IScoutLogger;
-import org.eclipse.scout.commons.logger.ScoutLogManager;
-import org.eclipse.scout.rt.client.ui.basic.table.ITable;
-import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
-import org.eclipse.scout.rt.client.ui.basic.table.TableUtility;
-import org.eclipse.scout.rt.client.ui.basic.table.columns.IBooleanColumn;
-import org.eclipse.scout.rt.client.ui.basic.table.columns.IColumn;
-import org.eclipse.scout.rt.client.ui.form.fields.GridData;
-import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
-import org.eclipse.scout.rt.client.ui.form.fields.stringfield.IStringField;
-import org.eclipse.scout.rt.ui.swt.basic.ISwtScoutComposite;
-import org.eclipse.scout.rt.ui.swt.basic.table.ISwtScoutTable;
-import org.eclipse.scout.rt.ui.swt.basic.table.SwtScoutTable;
-import org.eclipse.scout.rt.ui.swt.extension.UiDecorationExtensionPoint;
-import org.eclipse.scout.rt.ui.swt.keystroke.SwtKeyStroke;
-import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.TraverseEvent;
-import org.eclipse.swt.events.TraverseListener;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Widget;
-
-/**
- * Editable support for {@link ITable} in SWT-UI.
- */
-public class SwtScoutTableCellEditor {
-
- private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwtScoutTableCellEditor.class);
-
- private static final String DUMMY_VALUE = "Dummy";
-
- private final ISwtScoutTable m_tableComposite;
- private final Listener m_rowHeightListener;
-
- private P_FocusLostListener m_focusLostListener;
-
- public SwtScoutTableCellEditor(final ISwtScoutTable tableComposite) {
- m_focusLostListener = new P_FocusLostListener();
- m_tableComposite = tableComposite;
- m_rowHeightListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- event.height = Math.max(event.height, UiDecorationExtensionPoint.getLookAndFeel().getLogicalGridLayoutRowHeight());
- }
- };
- }
-
- //(re)install cell editors
- public void initialize() {
- TableViewer viewer = m_tableComposite.getSwtTableViewer();
- String[] columnPropertyNames = new String[viewer.getTable().getColumnCount()];
- CellEditor[] oldEditors = viewer.getCellEditors();
- CellEditor[] newEditors = new CellEditor[columnPropertyNames.length];
- boolean hasEditors = false;
- for (int i = 0; i < columnPropertyNames.length; i++) {
- TableColumn swtCol = viewer.getTable().getColumn(i);
- IColumn<?> scoutCol = (IColumn<?>) swtCol.getData(SwtScoutTable.KEY_SCOUT_COLUMN);
- if (scoutCol != null) {
- columnPropertyNames[i] = "" + scoutCol.getColumnIndex();
- if (scoutCol.isEditable()) {
- hasEditors = true;
- newEditors[i] = new P_SwtCellEditor(viewer.getTable(), scoutCol);
- }
- }
- else {
- columnPropertyNames[i] = "";
- }
- }
- viewer.setCellModifier(new P_SwtCellModifier());
- viewer.setColumnProperties(columnPropertyNames);
- viewer.setCellEditors(newEditors);
- if (oldEditors != null && oldEditors.length > 0) {
- for (CellEditor editor : oldEditors) {
- if (editor != null) {
- editor.dispose();
- }
- }
- }
- //increase row height when editors are present
- if (hasEditors) {
- viewer.getTable().addListener(SWT.MeasureItem, m_rowHeightListener);
- }
- else {
- viewer.getTable().removeListener(SWT.MeasureItem, m_rowHeightListener);
- }
- }
-
- @SuppressWarnings("unchecked")
- protected Control createEditorControl(Composite parent, final ITableRow scoutRow, final IColumn<?> scoutCol) {
- IFormField formField = createFormField(scoutRow, scoutCol);
- if (formField == null) {
- return null;
- }
-
- ISwtScoutComposite swtScoutFormField;
- if (formField instanceof IStringField && ((IStringField) formField).isMultilineText()) {
- // open a separate Shell to edit the content.
- swtScoutFormField = createEditorCompositePopup(parent, formField, scoutRow, scoutCol);
- }
- else {
- swtScoutFormField = m_tableComposite.getEnvironment().createFormField(parent, formField);
- }
-
- if (swtScoutFormField != null) {
- decorateEditorComposite(swtScoutFormField, scoutRow, scoutCol);
- return swtScoutFormField.getSwtContainer();
- }
- else {
- return null;
- }
- }
-
- protected ISwtScoutComposite<? extends IFormField> createEditorCompositePopup(final Composite parent, IFormField formField, final ITableRow scoutRow, final IColumn<?> scoutCol) {
- // overwrite layout properties
- GridData gd = formField.getGridData();
- gd.h = 1;
- gd.w = IFormField.FULL_WIDTH;
- gd.weightY = 1;
- gd.weightX = 1;
- formField.setGridDataInternal(gd);
-
- TableColumn swtCol = getSwtColumn(scoutCol);
- final P_SwtCellEditor cellEditor = (P_SwtCellEditor) m_tableComposite.getSwtTableViewer().getCellEditors()[getSwtColumnIndex(swtCol)];
-
- int prefWidth = gd.widthInPixel;
- int minWidth = swtCol.getWidth();
- int prefHeight = gd.heightInPixel;
- int minHeight = Math.max(105, m_tableComposite.getSwtTableViewer().getTable().getItemHeight());
-
- prefHeight = Math.max(prefHeight, minHeight);
- prefWidth = Math.max(prefWidth, minWidth);
-
- // Create placeholder field to represent the cell editor
- final Composite cellEditorComposite = new Composite(parent, SWT.NONE);
-
- // Create popup dialog to wrap the form field
- final SwtScoutFormFieldPopup formFieldDialog = new SwtScoutFormFieldPopup(cellEditorComposite);
- formFieldDialog.setPrefHeight(prefHeight);
- formFieldDialog.setPrefWidth(prefWidth);
- formFieldDialog.setMinHeight(minHeight);
- formFieldDialog.setMinWidth(minWidth);
-
- // == ICellModifier ==
- // Replace default cell-modifier strategy to touch form-field to be written back to the model.
- final ICellModifier defaultCellModifier = m_tableComposite.getSwtTableViewer().getCellModifier();
- m_tableComposite.getSwtTableViewer().setCellModifier(new P_SwtCellModifier() {
-
- @Override
- public void modify(Object element, String property, Object value) {
- formFieldDialog.touch();
- super.modify(element, property, value);
- }
- });
-
- // == IFocusDelegate ==
- // Replace default focus handling strategy.
- final IFocusDelegate defaultFocusDelegate = cellEditor.getFocusDelegate();
- cellEditor.setFocusDelegate(new IFocusDelegate() {
-
- @Override
- public void doSetFocus() {
- // NOOP: Focus is set the time the Shell is opened.
- }
- });
-
- // == IFormFieldPopupListener ==
- // To receive events about the popup's state. The popup is not closed yet but the cell-editor closed.
- final IFormFieldPopupListener formFieldPopupListener = new IFormFieldPopupListener() {
-
- @Override
- public void handleEvent(int event) {
- if ((event & IFormFieldPopupListener.TYPE_OK) > 0) {
- cellEditor.stopCellEditing(); // save cell editor
- }
- else if ((event & IFormFieldPopupListener.TYPE_CANCEL) > 0) {
- cellEditor.cancelCellEditing(); // cancel cell editor
- }
-
- // traversal control
- if ((event & IFormFieldPopupListener.TYPE_FOCUS_BACK) > 0) {
- enqueueEditNextTableCell(scoutRow, scoutCol, false);
- }
- else if ((event & IFormFieldPopupListener.TYPE_FOCUS_NEXT) > 0) {
- enqueueEditNextTableCell(scoutRow, scoutCol, true);
- }
- }
- };
- formFieldDialog.addListener(formFieldPopupListener);
-
- // == DisposeListener ==
- // To close the Shell if the cell-editor is disposed.
- cellEditorComposite.addDisposeListener(new DisposeListener() {
-
- @Override
- public void widgetDisposed(DisposeEvent e) {
- formFieldDialog.removeListener(formFieldPopupListener); // ignore resulting popup events.
-
- // Restore default focus delegate and cell modifier.
- cellEditor.setFocusDelegate(defaultFocusDelegate);
- m_tableComposite.getSwtTableViewer().setCellModifier(defaultCellModifier);
-
- // Close the popup Shell.
- // The asyncExec is a workaround so that other cell-editors can be activated immediately.
- // Note: If being dirty, 'Viewer#refresh()' in TableEx prevents the cell from being activated immediately.
- e.display.asyncExec(new Runnable() {
-
- @Override
- public void run() {
- formFieldDialog.closePopup();
- }
- });
- }
- });
-
- // Open the popup for the form field.
- formFieldDialog.createField(parent, formField, m_tableComposite.getEnvironment());
-
- return formFieldDialog;
- }
-
- protected IFormField createFormField(final ITableRow scoutRow, final IColumn<?> scoutCol) {
- if (scoutRow == null || scoutCol == null) {
- return null;
- }
-
- final Holder<IFormField> result = new Holder<IFormField>();
- Runnable t = new Runnable() {
- @Override
- public void run() {
- result.setValue(m_tableComposite.getScoutObject().getUIFacade().prepareCellEditFromUI(scoutRow, scoutCol));
- }
- };
- try {
- m_tableComposite.getEnvironment().invokeScoutLater(t, 2345).join(2345);
- }
- catch (InterruptedException e) {
- LOG.warn("Interrupted while waiting for the Form-Field to be created.", e);
- }
- return result.getValue();
- }
-
- /**
- * Callback to be overwritten to customize the {@link IFormField}.
- */
- protected void decorateEditorComposite(ISwtScoutComposite<? extends IFormField> editorComposite, final ITableRow scoutRow, final IColumn<?> scoutCol) {
- }
-
- protected void saveEditorFromSwt() {
- Runnable t = new Runnable() {
- @Override
- public void run() {
- m_tableComposite.getScoutObject().getUIFacade().completeCellEditFromUI();
- }
- };
- m_tableComposite.getEnvironment().invokeScoutLater(t, 0);
- }
-
- protected void cancelEditorFromSwt() {
- Runnable t = new Runnable() {
- @Override
- public void run() {
- m_tableComposite.getScoutObject().getUIFacade().cancelCellEditFromUI();
- }
- };
- m_tableComposite.getEnvironment().invokeScoutLater(t, 0);
- }
-
- protected void enqueueEditNextTableCell(final ITableRow row, final IColumn<?> col, final boolean forward) {
- if (row == null || col == null) {
- return;
- }
- m_tableComposite.getEnvironment().invokeScoutLater(new Runnable() {
- @Override
- public void run() {
- if (m_tableComposite.getEnvironment() == null) {
- return;
- }
- ITable table = m_tableComposite.getScoutObject();
- TableUtility.editNextTableCell(table, row, col, forward, new TableUtility.ITableCellEditorFilter() {
- @Override
- public boolean accept(ITableRow rowx, IColumn<?> colx) {
- return true;
- }
- });
- }
- }, 0L);
- }
-
- protected IColumn<?> getScoutColumn(String property) {
- if (property != null && property.matches("[0-9]+")) {
- int colIndex = Integer.parseInt(property);
- return m_tableComposite.getScoutObject().getColumnSet().getColumn(colIndex);
- }
- return null;
- }
-
- private TableColumn getSwtColumn(IColumn<?> scoutCol) {
- for (TableColumn swtCol : m_tableComposite.getSwtTableViewer().getTable().getColumns()) {
- IColumn<?> candidate = (IColumn<?>) swtCol.getData(SwtScoutTable.KEY_SCOUT_COLUMN);
- if (candidate != null && CompareUtility.equals(candidate.getColumnId(), scoutCol.getColumnId())) {
- return swtCol;
- }
- }
- return null;
- }
-
- private int getSwtColumnIndex(TableColumn swtCol) {
- Table table = m_tableComposite.getSwtTableViewer().getTable();
- for (int i = 0; i < table.getColumnCount(); i++) {
- if (table.getColumn(i) == swtCol) {
- return i;
- }
- }
- return -1;
- }
-
- private class P_SwtCellModifier implements ICellModifier {
-
- @Override
- public void modify(Object element, String property, Object value) {
- saveEditorFromSwt();
- }
-
- @Override
- public Object getValue(Object element, String property) {
- //not used
- return DUMMY_VALUE;
- }
-
- @Override
- public boolean canModify(Object element, String property) {
- final ITable table = m_tableComposite.getScoutObject();
- final ITableRow row = (ITableRow) element;
- final IColumn<?> column = getScoutColumn(property);
-
- final BooleanHolder result = new BooleanHolder();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- if (table != null && row != null && column != null) {
- result.setValue(table.isCellEditable(row, column));
- }
- }
- };
- try {
- m_tableComposite.getEnvironment().invokeScoutLater(r, 2345).join(2345);
- }
- catch (InterruptedException e) {
- LOG.warn("Interrupted while waiting for the model to determine the cell's editability.", e);
- }
- return BooleanUtility.nvl(result.getValue(), false);
- }
- }
-
- /**
- * Statefull per-column cell-editor which is used for all cells of a column.
- */
- private class P_SwtCellEditor extends CellEditor {
- private Composite m_container;
- private Object m_value;
- private ITableRow m_editScoutRow;
- private IFocusDelegate m_focusDelegate;
- private IColumn<?> m_scoutCol;
- private ViewerCell m_cell;
- private Image m_image;
-
- /**
- * @param parent
- * the table.
- * @param scoutCol
- * the scout column this cell editor is used for.
- */
- protected P_SwtCellEditor(Composite parent, IColumn<?> scoutCol) {
- super(parent);
- m_scoutCol = scoutCol;
- m_focusDelegate = new P_FocusDelegate();
- }
-
- @Override
- protected Control createControl(Composite parent) {
- m_container = new Composite(parent, SWT.NONE) {
- /*
- * disable inner components preferred sizes
- */
- @Override
- public Point computeSize(int wHint, int hHint, boolean changed) {
- return new Point(wHint, hHint);
- }
- };
- m_container.setLayout(new FillLayout());
- m_tableComposite.getEnvironment().addKeyStroke(m_container, new SwtKeyStroke(SWT.ESC) {
- @Override
- public void handleSwtAction(Event e) {
- e.doit = false;
- fireCancelEditor();
- }
- });
- m_tableComposite.getEnvironment().addKeyStroke(m_container, new SwtKeyStroke(SWT.CR) {
- @Override
- public void handleSwtAction(Event e) {
- e.doit = false;
- fireApplyEditorValue();
- deactivate();
- }
- });
- m_tableComposite.getEnvironment().addKeyStroke(m_container, new SwtKeyStroke(SWT.KEYPAD_CR) {
- @Override
- public void handleSwtAction(Event e) {
- e.doit = false;
- fireApplyEditorValue();
- deactivate();
- }
- });
- return m_container;
- }
-
- @Override
- protected void doSetFocus() {
- m_focusDelegate.doSetFocus();
- }
-
- @Override
- protected Object doGetValue() {
- return m_value;
- }
-
- @Override
- protected void doSetValue(Object value) {
- m_value = value;
- }
-
- @Override
- public void activate(ColumnViewerEditorActivationEvent e) {
- // Install a focus-lost listener on the table widget to close an active cell-editor when the table looses the focus.
- m_focusLostListener.install();
-
- if (!(e.getSource() instanceof ViewerCell)) {
- return;
- }
-
- m_cell = (ViewerCell) e.getSource();
- m_editScoutRow = (ITableRow) m_cell.getElement();
-
- if (m_scoutCol instanceof IBooleanColumn) {
- if (e.sourceEvent instanceof MouseEvent) {
- return; // no edit-mode when a boolean cell was clicked by mouse.
- }
- else {
- // hide the checkbox image when editing a boolean value in traversal-mode.
- m_image = m_cell.getImage();
- m_cell.setImage(null);
- }
- }
-
- // create the cell editor widget.
- if (m_editScoutRow != null) {
- createEditorControl(m_container, m_editScoutRow, m_scoutCol);
- }
-
- m_container.layout(true, true);
- m_container.setVisible(true);
- }
-
- @Override
- protected void deactivate(ColumnViewerEditorDeactivationEvent e) {
- // restore the cell's image if being unset in CellEditor#activate.
- if (m_cell != null && m_image != null) {
- m_cell.setImage(m_image);
- }
-
- m_cell = null;
- m_image = null;
- m_editScoutRow = null;
-
- // Dispose the cell-editor; in turn, any Shell opened by the editor is closed as well.
- for (Control c : m_container.getChildren()) {
- c.dispose();
- }
- if (e.eventType == ColumnViewerEditorDeactivationEvent.EDITOR_CANCELED) {
- cancelEditorFromSwt();
- }
-
- super.deactivate(e);
-
- m_focusLostListener.uninstall();
- }
-
- @Override
- protected boolean dependsOnExternalFocusListener() {
- return false;
- }
-
- public void stopCellEditing() {
- fireApplyEditorValue();
- deactivate();
- }
-
- public void cancelCellEditing() {
- fireCancelEditor();
- deactivate();
- }
-
- public IFocusDelegate getFocusDelegate() {
- return m_focusDelegate;
- }
-
- public void setFocusDelegate(IFocusDelegate focusDelegate) {
- m_focusDelegate = focusDelegate;
- }
-
- private class P_FocusDelegate implements IFocusDelegate {
-
- @Override
- public void doSetFocus() {
- // traverse the focus to the cell editor's control so that the user can start editing immediately without having to click into the widget first.
- m_container.traverse(SWT.TRAVERSE_TAB_NEXT);
-
- Control focusControl = m_container.getDisplay().getFocusControl();
- if (focusControl != null && SwtUtility.isAncestorOf(m_container, focusControl)) {
- focusControl.addTraverseListener(new TraverseListener() {
- @Override
- public void keyTraversed(TraverseEvent e) {
- switch (e.detail) {
- case SWT.TRAVERSE_ESCAPE:
- case SWT.TRAVERSE_RETURN: {
- e.doit = false;
- break;
- }
- case SWT.TRAVERSE_TAB_NEXT: {
- e.doit = false;
- ITableRow currentScoutRow = m_editScoutRow; // memorize the current row because being set to null when the cell editor is deactivated.
- fireApplyEditorValue();
- deactivate();
- enqueueEditNextTableCell(currentScoutRow, m_scoutCol, true); // traverse the focus to the next editable cell.
- break;
- }
- case SWT.TRAVERSE_TAB_PREVIOUS: {
- e.doit = false;
- ITableRow currentScoutRow = m_editScoutRow; // memorize the current row because being set to null when the cell editor is deactivated.
- fireApplyEditorValue();
- deactivate();
- enqueueEditNextTableCell(currentScoutRow, m_scoutCol, false); // traverse the focus to the next editable cell.
- break;
- }
- }
- }
- });
- }
- }
- }
- }
-
- /**
- * Hysteresis listener that commits the cell editor when the table has first received focus and then lost it. That is
- * because cell editors in SWT are not closed automatically if the table looses the focus.
- */
- private class P_FocusLostListener implements Listener {
-
- /**
- * Installs listening for focus-lost events on the table widget.
- */
- public void install() {
- m_tableComposite.getEnvironment().getDisplay().addFilter(SWT.FocusIn, this);
- }
-
- /**
- * Uninstalls listening for focus-lost events on the table widget.
- */
- public void uninstall() {
- m_tableComposite.getEnvironment().getDisplay().removeFilter(SWT.FocusIn, this);
- }
-
- @Override
- public void handleEvent(Event event) {
- Widget w = event.widget;
- if (w == null || !(w instanceof Control) || w.isDisposed()) {
- return;
- }
-
- // Sanity check whether a cell-editor is active.
- TableViewer viewer = m_tableComposite.getSwtTableViewer();
- if (!viewer.isCellEditorActive()) {
- return;
- }
-
- Control focusOwner = (Control) w;
- Table table = m_tableComposite.getSwtTableViewer().getTable();
-
- // Check if the table is the focus owner.
- if (SwtUtility.isAncestorOf(table, focusOwner)) {
- return;
- }
-
- // Check if a Shell opened by the cell-editor is the focus owner.
- if (focusOwner.getShell() != table.getShell()) {
- Composite parentFocusOwner = focusOwner.getShell().getParent();
- while (parentFocusOwner != null) {
- if (parentFocusOwner.getShell() == table.getShell()) {
- return; // focus owner is a derrived Shell.
- }
- else {
- parentFocusOwner = parentFocusOwner.getShell().getParent();
- }
- }
- }
-
- // Close the cell-editor because a control other than the table is focus owner.
- for (CellEditor editor : viewer.getCellEditors()) {
- if (editor != null && editor.isActivated() && editor instanceof P_SwtCellEditor) {
- ((P_SwtCellEditor) editor).stopCellEditing();
- break;
- }
- }
- }
- }
-
- /**
- * Delegate to process focus events on cell editor.
- */
- private interface IFocusDelegate {
- void doSetFocus();
- }
-
- /**
- * Listener to get notified about deactivation events.
- */
- private interface IDeactivateListener {
- void canceled(ColumnViewerEditorDeactivationEvent event);
-
- void saved(ColumnViewerEditorDeactivationEvent event);
- }
-}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableCellEditor.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableCellEditor.java
new file mode 100644
index 0000000000..dcab3676a7
--- /dev/null
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableCellEditor.java
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * Copyright (c) 2014 BSI Business Systems Integration AG.
+ * 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:
+ * BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
+
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
+import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.scout.commons.holders.Holder;
+import org.eclipse.scout.commons.logger.IScoutLogger;
+import org.eclipse.scout.commons.logger.ScoutLogManager;
+import org.eclipse.scout.rt.client.ui.basic.table.ITable;
+import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
+import org.eclipse.scout.rt.client.ui.basic.table.TableUtility;
+import org.eclipse.scout.rt.client.ui.basic.table.columns.IBooleanColumn;
+import org.eclipse.scout.rt.client.ui.basic.table.columns.IColumn;
+import org.eclipse.scout.rt.client.ui.form.fields.GridData;
+import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
+import org.eclipse.scout.rt.client.ui.form.fields.stringfield.IStringField;
+import org.eclipse.scout.rt.ui.swt.ISwtEnvironment;
+import org.eclipse.scout.rt.ui.swt.basic.ISwtScoutComposite;
+import org.eclipse.scout.rt.ui.swt.basic.table.ISwtScoutTable;
+import org.eclipse.scout.rt.ui.swt.basic.table.SwtScoutTable;
+import org.eclipse.scout.rt.ui.swt.keystroke.SwtKeyStroke;
+import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * <p>
+ * {@link CellEditor} for {@link SwtScoutTable}.
+ * </p>
+ * Each editable cell has its own {@link CellEditor} instance.
+ */
+public class TableCellEditor extends CellEditor {
+
+ private static final IScoutLogger LOG = ScoutLogManager.getLogger(TableCellEditor.class);
+
+ private ISwtEnvironment m_environment;
+ private P_FocusLostListener m_focusLostListener;
+
+ private Composite m_container;
+ private Image m_image;
+
+ private IColumn<?> m_scoutColumn;
+ private ITableRow m_scoutRow;
+ private ITable m_scoutTable;
+ private TableColumn m_swtColumn;
+ private Table m_swtTable;
+
+ private TableViewer m_tableViewer;
+
+ private boolean m_requestFocus;
+
+ public TableCellEditor(TableViewer tableViewer, TableColumn swtColumn, ITableRow scoutRow, ISwtEnvironment environment) {
+ super(tableViewer.getTable());
+ m_scoutRow = scoutRow;
+ m_scoutColumn = (IColumn<?>) swtColumn.getData(ISwtScoutTable.KEY_SCOUT_COLUMN);
+ m_scoutTable = m_scoutColumn.getTable();
+ m_swtColumn = swtColumn;
+ m_tableViewer = tableViewer;
+ m_swtTable = tableViewer.getTable();
+
+ m_environment = environment;
+ m_focusLostListener = new P_FocusLostListener();
+ }
+
+ @Override
+ protected Control createControl(Composite parent) {
+ m_container = new Composite(parent, SWT.NONE) {
+ @Override
+ // disable inner components preferred sizes.
+ public Point computeSize(int wHint, int hHint, boolean changed) {
+ return new Point(wHint, hHint);
+ }
+ };
+ m_container.setLayout(new FillLayout());
+
+ return m_container;
+ }
+
+ @Override
+ protected Object doGetValue() {
+ // NOOP: The value is written back to the model by the widget's verify event.
+ return null;
+ }
+
+ @Override
+ protected void doSetValue(Object value) {
+ // NOOP: The value is set into the cell-editor when it is created.
+ }
+
+ @Override
+ public void activate(ColumnViewerEditorActivationEvent e) {
+ m_requestFocus = true;
+
+ // Install a focus-lost listener on the table widget to close an active cell-editor when the table looses the focus.
+ m_focusLostListener.install();
+
+ // Install keystrokes to exit editing mode.
+ m_environment.addKeyStroke(m_container, new SwtKeyStroke(SWT.ESC) {
+ @Override
+ public void handleSwtAction(Event event) {
+ event.doit = false;
+ fireCancelEditor();
+ }
+ });
+ m_environment.addKeyStroke(m_container, new SwtKeyStroke(SWT.CR) {
+ @Override
+ public void handleSwtAction(Event event) {
+ event.doit = false;
+ fireApplyEditorValue();
+ }
+ });
+ m_environment.addKeyStroke(m_container, new SwtKeyStroke(SWT.KEYPAD_CR) {
+ @Override
+ public void handleSwtAction(Event event) {
+ event.doit = false;
+ fireApplyEditorValue();
+ }
+ });
+
+ // Specific cell-editor for boolean values.
+ if (m_scoutColumn instanceof IBooleanColumn) {
+ if (e.sourceEvent instanceof MouseEvent) {
+ // no edit-mode when a boolean cell was clicked by mouse because being inverted and the editing mode closed in AbstractTable#interceptRowClickSingleObserver.
+ m_requestFocus = false;
+ return;
+ }
+ else {
+ // hide the checkbox image when editing a boolean value in traversal-mode.
+ ViewerCell cell = (ViewerCell) e.getSource();
+ m_image = cell.getImage();
+ cell.setImage(null);
+ }
+ }
+
+ // create the Scout model field.
+ IFormField formField = createFormField();
+ if (formField == null) {
+ LOG.warn("Failed to create FormField for cell-editor; editing mode canceled.");
+ m_requestFocus = false;
+ fireCancelEditor();
+ return;
+ }
+
+ // create the UI field.
+ ISwtScoutComposite swtScoutFormField;
+ if (formField instanceof IStringField && ((IStringField) formField).isMultilineText()) {
+ // open a separate Shell to edit the content.
+ swtScoutFormField = createPopupEditorControl(m_container, formField);
+ }
+ else {
+ swtScoutFormField = m_environment.createFormField(m_container, formField);
+ }
+ // hook to customize the form field.
+ decorateEditorComposite(swtScoutFormField, m_scoutRow, m_scoutColumn);
+
+ m_container.layout(true, true);
+ m_container.setVisible(true);
+ }
+
+ @Override
+ protected void doSetFocus() {
+ if (!m_requestFocus) {
+ return;
+ }
+
+ // traverse the focus to the cell editor's control so that the user can start editing immediately without having to click into the widget first.
+ m_container.traverse(SWT.TRAVERSE_TAB_NEXT);
+
+ Control focusControl = m_container.getDisplay().getFocusControl();
+ if (focusControl != null && SwtUtility.isAncestorOf(m_container, focusControl)) {
+ focusControl.addTraverseListener(new TraverseListener() {
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ switch (e.detail) {
+ case SWT.TRAVERSE_ESCAPE:
+ case SWT.TRAVERSE_RETURN: {
+ e.doit = false;
+ break;
+ }
+ case SWT.TRAVERSE_TAB_NEXT: {
+ e.doit = false;
+ fireApplyEditorValue();
+ enqueueEditNextTableCell(true); // traverse the focus to the next editable cell.
+ break;
+ }
+ case SWT.TRAVERSE_TAB_PREVIOUS: {
+ e.doit = false;
+ fireApplyEditorValue();
+ enqueueEditNextTableCell(false); // traverse the focus to the next editable cell.
+ break;
+ }
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void deactivate(ColumnViewerEditorDeactivationEvent e) {
+ // restore the cell's image if being unset in CellEditor#activate.
+ ViewerCell cell = (ViewerCell) e.getSource();
+ if (m_image != null) {
+ cell.setImage(m_image);
+ }
+
+ m_image = null;
+
+ // Dispose the cell-editor; in turn, any Shell opened by the editor is closed as well.
+ for (Control c : m_container.getChildren()) {
+ c.dispose();
+ }
+
+ super.deactivate(e);
+
+ m_focusLostListener.uninstall();
+ }
+
+ @Override
+ protected boolean dependsOnExternalFocusListener() {
+ return false;
+ }
+
+ protected void enqueueEditNextTableCell(final boolean forward) {
+ m_environment.invokeScoutLater(new Runnable() {
+ @Override
+ public void run() {
+ ITable table = m_scoutColumn.getTable();
+ TableUtility.editNextTableCell(table, m_scoutRow, m_scoutColumn, forward, new TableUtility.ITableCellEditorFilter() {
+ @Override
+ public boolean accept(ITableRow rowx, IColumn<?> colx) {
+ return true;
+ }
+ });
+ }
+ }, 0L);
+ }
+
+ protected ISwtScoutComposite<? extends IFormField> createPopupEditorControl(final Composite parent, IFormField formField) {
+ // overwrite layout properties
+ GridData gd = formField.getGridData();
+ gd.h = 1;
+ gd.w = IFormField.FULL_WIDTH;
+ gd.weightY = 1;
+ gd.weightX = 1;
+ formField.setGridDataInternal(gd);
+
+ int prefWidth = gd.widthInPixel;
+ int minWidth = m_swtColumn.getWidth();
+ int prefHeight = gd.heightInPixel;
+ int minHeight = Math.max(105, m_swtTable.getItemHeight());
+
+ prefHeight = Math.max(prefHeight, minHeight);
+ prefWidth = Math.max(prefWidth, minWidth);
+
+ // Create placeholder field to represent the cell editor
+ final Composite cellEditorComposite = new Composite(parent, SWT.NONE);
+
+ // Create popup dialog to wrap the form field
+ final SwtScoutFormFieldPopup popup = new SwtScoutFormFieldPopup(cellEditorComposite);
+ popup.setPrefHeight(prefHeight);
+ popup.setPrefWidth(prefWidth);
+ popup.setMinHeight(minHeight);
+ popup.setMinWidth(minWidth);
+
+ // Focus is set the time the Shell is opened.
+ m_requestFocus = false;
+
+ // == IFormFieldPopupListener ==
+ // To receive events about the popup's state. The popup is not closed yet but the cell-editor closed.
+ final IFormFieldPopupListener formFieldPopupListener = new IFormFieldPopupListener() {
+
+ @Override
+ public void handleEvent(int event) {
+ if ((event & IFormFieldPopupListener.TYPE_OK) > 0) {
+ SwtUtility.runSwtInputVerifier(popup.getSwtField()); // write the value back into the model.
+ fireApplyEditorValue();
+ }
+ else if ((event & IFormFieldPopupListener.TYPE_CANCEL) > 0) {
+ fireCancelEditor();
+ }
+
+ // traversal control
+ if ((event & IFormFieldPopupListener.TYPE_FOCUS_BACK) > 0) {
+ enqueueEditNextTableCell(false);
+ }
+ else if ((event & IFormFieldPopupListener.TYPE_FOCUS_NEXT) > 0) {
+ enqueueEditNextTableCell(true);
+ }
+ }
+ };
+ popup.addListener(formFieldPopupListener);
+
+ // == DisposeListener ==
+ // To close the Shell if the cell-editor is disposed.
+ cellEditorComposite.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ popup.removeListener(formFieldPopupListener); // ignore resulting popup events.
+
+ // Close the popup Shell.
+ // The asyncExec is a workaround so that other cell-editors can be activated immediately.
+ // Note: If being dirty, 'Viewer#refresh()' in TableEx prevents the cell from being activated immediately.
+ e.display.asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ popup.closePopup();
+ }
+ });
+ }
+ });
+
+ // Open the popup for the form field.
+ popup.createField(parent, formField, m_environment);
+
+ return popup;
+ }
+
+ protected IFormField createFormField() {
+ final Holder<IFormField> result = new Holder<IFormField>();
+ Runnable t = new Runnable() {
+ @Override
+ public void run() {
+ result.setValue(m_scoutTable.getUIFacade().prepareCellEditFromUI(m_scoutRow, m_scoutColumn));
+ }
+ };
+ try {
+ m_environment.invokeScoutLater(t, 2345).join(2345);
+ }
+ catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting for the Form-Field to be created.", e);
+ }
+ return result.getValue();
+ }
+
+ /**
+ * Callback to be overwritten to customize the {@link IFormField}.
+ */
+ protected void decorateEditorComposite(ISwtScoutComposite editorComposite, final ITableRow scoutRow, final IColumn<?> scoutCol) {
+ }
+
+ /**
+ * Hysteresis listener that commits the cell editor when the table has first received focus and then lost it. That is
+ * because cell editors in SWT are not closed automatically if the table looses the focus.
+ */
+ private class P_FocusLostListener implements Listener {
+
+ /**
+ * Installs listening for focus-lost events on the table widget.
+ */
+ public void install() {
+ m_environment.getDisplay().addFilter(SWT.FocusIn, this);
+ }
+
+ /**
+ * Uninstalls listening for focus-lost events on the table widget.
+ */
+ public void uninstall() {
+ m_environment.getDisplay().removeFilter(SWT.FocusIn, this);
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ Widget w = event.widget;
+ if (w == null || !(w instanceof Control) || w.isDisposed()) {
+ return;
+ }
+
+ // Sanity check whether a cell-editor is active.
+ TableViewer viewer = m_tableViewer;
+ if (!viewer.isCellEditorActive()) {
+ return;
+ }
+
+ Control focusOwner = (Control) w;
+ Table table = m_tableViewer.getTable();
+
+ // Check if the table is the focus owner.
+ if (SwtUtility.isAncestorOf(table, focusOwner)) {
+ return;
+ }
+
+ // Check if a Shell opened by the cell-editor is the focus owner.
+ if (focusOwner.getShell() != table.getShell()) {
+ Composite parentFocusOwner = focusOwner.getShell().getParent();
+ while (parentFocusOwner != null) {
+ if (parentFocusOwner.getShell() == table.getShell()) {
+ return; // focus owner is a derrived Shell.
+ }
+ else {
+ parentFocusOwner = parentFocusOwner.getShell().getParent();
+ }
+ }
+ }
+
+ // Close the cell-editor because a control other than the table is focus owner.
+ fireApplyEditorValue();
+ }
+ }
+}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableEditingSupport.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableEditingSupport.java
new file mode 100644
index 0000000000..f4dde5d68a
--- /dev/null
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/TableEditingSupport.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2014 BSI Business Systems Integration AG.
+ * 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:
+ * BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
+
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.ICellEditorListener;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.scout.commons.BooleanUtility;
+import org.eclipse.scout.commons.holders.BooleanHolder;
+import org.eclipse.scout.commons.logger.IScoutLogger;
+import org.eclipse.scout.commons.logger.ScoutLogManager;
+import org.eclipse.scout.rt.client.ui.basic.table.ITable;
+import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
+import org.eclipse.scout.rt.client.ui.basic.table.columns.IColumn;
+import org.eclipse.scout.rt.ui.swt.ISwtEnvironment;
+import org.eclipse.scout.rt.ui.swt.basic.table.ISwtScoutTable;
+import org.eclipse.scout.rt.ui.swt.basic.table.SwtScoutTable;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * <p>
+ * Editing Support for {@link SwtScoutTable}.
+ * </p>
+ * Each editable column has its own {@link EditingSupport} instance.
+ */
+public class TableEditingSupport extends EditingSupport implements ICellEditorListener {
+
+ private static final IScoutLogger LOG = ScoutLogManager.getLogger(TableEditingSupport.class);
+
+ private ISwtEnvironment m_environment;
+
+ private ITable m_scoutTable;
+ private IColumn<?> m_scoutColumn;
+ private TableColumn m_swtColumn;
+
+ public TableEditingSupport(TableViewer viewer, TableColumn swtColumn, ISwtEnvironment environment) {
+ super(viewer);
+
+ m_scoutColumn = (IColumn<?>) swtColumn.getData(ISwtScoutTable.KEY_SCOUT_COLUMN);
+ m_swtColumn = swtColumn;
+ m_scoutTable = m_scoutColumn.getTable();
+
+ m_environment = environment;
+ }
+
+ @Override
+ public TableViewer getViewer() {
+ return (TableViewer) super.getViewer();
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ final ITableRow row = (ITableRow) element;
+
+ final BooleanHolder editable = new BooleanHolder();
+ try {
+ m_environment.invokeScoutLater(new Runnable() {
+ @Override
+ public void run() {
+ editable.setValue(m_scoutTable.isCellEditable(row, m_scoutColumn));
+ }
+ }, 2345).join(2345);
+ }
+ catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting for the model to determine the cell's editability.", e);
+ }
+ return BooleanUtility.nvl(editable.getValue(), false);
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ CellEditor cellEditor = new TableCellEditor(getViewer(), m_swtColumn, (ITableRow) element, m_environment);
+ cellEditor.addListener(this);
+ return cellEditor;
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ // NOOP: The value is set into the cell-editor when it is created.
+ return null;
+ }
+
+ @Override
+ protected void setValue(Object element, Object value) {
+ // NOOP: Only notify the model about completing the editing mode.
+ // The value itself is written back into the model by the widget's verify event.
+ m_environment.invokeScoutLater(new Runnable() {
+ @Override
+ public void run() {
+ m_scoutTable.getUIFacade().completeCellEditFromUI();
+ }
+ }, 0);
+ }
+
+ // == ICellEditorListener ==
+ // To notify Scout about canceling editing.
+
+ @Override
+ public void cancelEditor() {
+ m_environment.invokeScoutLater(new Runnable() {
+ @Override
+ public void run() {
+ m_scoutTable.getUIFacade().cancelCellEditFromUI();
+ }
+ }, 0);
+ }
+
+ @Override
+ public void applyEditorValue() {
+ // NOOP: is done in #setValue.
+ }
+
+ @Override
+ public void editorValueChanged(boolean oldValidState, boolean newValidState) {
+ // NOOP
+ }
+}

Back to the top