This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 436fa6f1ed fix grid height on previews in linux, fixes #8155 (#8171)
436fa6f1ed is described below
commit 436fa6f1ed8a1f036f44223a78346088c9991cba
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Sat Aug 29 20:27:35 2026 +0200
fix grid height on previews in linux, fixes #8155 (#8171)
---
.../org/apache/hop/ui/testing/EditRowsDialog.java | 5 +-
.../transforms/datagrid/DataGridDialog.java | 5 +-
.../dialog/PreviewRowsDialogRowHeightTest.java | 137 ++++++++++++++++++++
.../dialog/ShowRowsDialogCellSelectionTest.java | 27 +++-
.../widget/TableViewDataGridRowHeightTest.java | 142 +++++++++++++++++++++
.../apache/hop/ui/core/dialog/EditRowsDialog.java | 5 +-
.../hop/ui/core/dialog/PreviewRowsDialog.java | 6 +-
.../apache/hop/ui/core/dialog/ShowRowsDialog.java | 6 +-
.../org/apache/hop/ui/core/widget/TableView.java | 113 +++++++++++++---
.../execution/PipelineExecutionViewer.java | 6 +-
.../execution/WorkflowExecutionViewer.java | 6 +-
11 files changed, 418 insertions(+), 40 deletions(-)
diff --git
a/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/EditRowsDialog.java
b/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/EditRowsDialog.java
index 9c08df6e2c..e13ef20e67 100644
---
a/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/EditRowsDialog.java
+++
b/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/EditRowsDialog.java
@@ -279,7 +279,7 @@ public class EditRowsDialog {
}
if (show != null) {
- item.setText(c + 1, show);
+ wFields.setCellValue(item, c + 1, show);
item.setForeground(c + 1, GuiResource.getInstance().getColorBlack());
} else {
// Set null value
@@ -302,7 +302,8 @@ public class EditRowsDialog {
if
(GuiResource.getInstance().getColorBlue().equals(item.getForeground(colnr))) {
row[i] = null; // <null> value
} else {
- String string = item.getText(colnr);
+ // The cell is drawn shortened; the value itself comes back out of
the grid.
+ String string = TableView.getCellValue(item, colnr);
row[i] =
valueMeta.convertDataFromString(
string, stringValueMeta, null, null,
IValueMeta.TRIM_TYPE_NONE);
diff --git
a/plugins/transforms/datagrid/src/main/java/org/apache/hop/pipeline/transforms/datagrid/DataGridDialog.java
b/plugins/transforms/datagrid/src/main/java/org/apache/hop/pipeline/transforms/datagrid/DataGridDialog.java
index 5a9fedf5cf..d45b84e511 100644
---
a/plugins/transforms/datagrid/src/main/java/org/apache/hop/pipeline/transforms/datagrid/DataGridDialog.java
+++
b/plugins/transforms/datagrid/src/main/java/org/apache/hop/pipeline/transforms/datagrid/DataGridDialog.java
@@ -271,7 +271,7 @@ public class DataGridDialog extends BaseTransformDialog {
TableItem item = wData.table.getItem(i);
for (int f = 0; f < line.getDatalines().size(); f++) {
- item.setText(f + 1, Const.NVL(line.getDatalines().get(f), ""));
+ wData.setCellValue(item, f + 1, Const.NVL(line.getDatalines().get(f),
""));
}
}
@@ -413,7 +413,8 @@ public class DataGridDialog extends BaseTransformDialog {
DataGridDataMeta line = new DataGridDataMeta();
TableItem item = wData.table.getItem(i);
for (int f = 0; f < nrFields; f++) {
- line.getDatalines().add(item.getText(f + 1));
+ // The cell is drawn shortened; the value itself comes back out of the
grid.
+ line.getDatalines().add(TableView.getCellValue(item, f + 1));
}
data.add(line);
}
diff --git
a/rcp/src/test/java/org/apache/hop/ui/core/dialog/PreviewRowsDialogRowHeightTest.java
b/rcp/src/test/java/org/apache/hop/ui/core/dialog/PreviewRowsDialogRowHeightTest.java
new file mode 100644
index 0000000000..23cf9b645c
--- /dev/null
+++
b/rcp/src/test/java/org/apache/hop/ui/core/dialog/PreviewRowsDialogRowHeightTest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.core.dialog;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.ui.core.widget.TableView;
+import org.apache.hop.ui.testing.SwtBotTestBase;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swtbot.swt.finder.SWTBot;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Guards the row height of the transform preview grid.
+ *
+ * <p>Row geometry is not uniform on every platform: GTK measures each row
from the text its cells
+ * hold, so a line break that reaches the cell grows that row to as many lines
as the value has
+ * (issue #8155). macOS gives every row the same height, so this can only ever
fail on GTK — run it
+ * there, e.g. through {@code tools/with-isolated-display.sh}.
+ */
+@Tag("uitest")
+class PreviewRowsDialogRowHeightTest extends SwtBotTestBase {
+
+ private static final String MULTI_LINE = "first line\nsecond line\nthird
line\nfourth line";
+
+ @Test
+ void aMultiLineValueDoesNotGrowItsRow() {
+ IRowMeta rowMeta = new RowMeta();
+ rowMeta.addValueMeta(new ValueMetaString("text"));
+ List<Object[]> rows = new ArrayList<>();
+ rows.add(new Object[] {"single line"});
+ rows.add(new Object[] {MULTI_LINE});
+ rows.add(new Object[] {"another single line"});
+
+ withDialog(
+ parent ->
+ new PreviewRowsDialog(parent, new Variables(), SWT.NONE,
"transform", rowMeta, rows)
+ .open(),
+ bot -> {
+ Table table = awaitTable(bot);
+ assertNotNull(table, "the PreviewRowsDialog table should open");
+
+ int singleLineHeight = onUi(() ->
table.getItem(0).getBounds(1).height);
+ int multiLineHeight = onUi(() ->
table.getItem(1).getBounds(1).height);
+ assertEquals(
+ singleLineHeight,
+ multiLineHeight,
+ "a multi-line value must not make its row taller than a
single-line one");
+ assertEquals(
+ MULTI_LINE,
+ onUi(() -> TableView.getCellValue(table.getItem(1), 1)),
+ "the grid must still hand back the value with all of its lines");
+ });
+ }
+
+ private Table awaitTable(SWTBot bot) {
+ for (int i = 0; i < 50; i++) {
+ Table found = onUi(PreviewRowsDialogRowHeightTest::findTableOnUi);
+ if (found != null && onUi(() -> found.getItemCount() >= 3)) {
+ return found;
+ }
+ bot.sleep(100);
+ }
+ return null;
+ }
+
+ private static Table findTableOnUi() {
+ for (Shell shell : display.getShells()) {
+ Table table = findTable(shell);
+ if (table != null) {
+ return table;
+ }
+ }
+ return null;
+ }
+
+ private static Table findTable(Composite composite) {
+ for (Control child : composite.getChildren()) {
+ if (child instanceof Table foundTable) {
+ return foundTable;
+ }
+ if (child instanceof Composite childComposite) {
+ Table found = findTable(childComposite);
+ if (found != null) {
+ return found;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static <T> T onUi(Supplier<T> supplier) {
+ AtomicReference<T> result = new AtomicReference<>();
+ AtomicReference<RuntimeException> failure = new AtomicReference<>();
+ display.syncExec(
+ () -> {
+ try {
+ result.set(supplier.get());
+ } catch (RuntimeException e) {
+ failure.set(e);
+ }
+ });
+ if (failure.get() != null) {
+ throw failure.get();
+ }
+ return result.get();
+ }
+}
diff --git
a/rcp/src/test/java/org/apache/hop/ui/core/dialog/ShowRowsDialogCellSelectionTest.java
b/rcp/src/test/java/org/apache/hop/ui/core/dialog/ShowRowsDialogCellSelectionTest.java
index 9ed71ba4bb..11715a5bec 100644
---
a/rcp/src/test/java/org/apache/hop/ui/core/dialog/ShowRowsDialogCellSelectionTest.java
+++
b/rcp/src/test/java/org/apache/hop/ui/core/dialog/ShowRowsDialogCellSelectionTest.java
@@ -18,6 +18,7 @@
package org.apache.hop.ui.core.dialog;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -30,6 +31,7 @@ import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.core.row.RowMeta;
import org.apache.hop.core.row.value.ValueMetaString;
import org.apache.hop.core.variables.Variables;
+import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.testing.SwtBotTestBase;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
@@ -102,11 +104,15 @@ class ShowRowsDialogCellSelectionTest extends
SwtBotTestBase {
}
/**
- * Copy to clipboard, export to Excel/CSV and save-to-data-set all read the
cell straight off the
- * table item, so the item has to hold the complete value: the grid only
shortens it when drawing.
+ * A data grid puts the shortened, single-line text in the cell and keeps
the value itself aside.
+ * Native tables take their geometry from the text a cell holds, and GTK
grows a row to as many
+ * lines as its value has, so a stored line break makes the whole row tall
no matter how short we
+ * draw it (issue #8155; invisible on macOS, whose rows are all the same
height). The complete
+ * value stays available through {@link TableView#getCellValue(TableItem,
int)}, which is what the
+ * in-place editor and the clipboard read.
*/
@Test
- void gridCellsHoldTheFullValueEvenThoughTheyAreDrawnShortened() {
+ void gridCellsHoldTheShortenedTextWhileTheGridKeepsTheFullValue() {
String multiLine = "first line\nsecond line\nthird line";
IRowMeta rowMeta = new RowMeta();
@@ -123,14 +129,21 @@ class ShowRowsDialogCellSelectionTest extends
SwtBotTestBase {
Table table = awaitTable(bot);
assertNotNull(table, "the ShowRowsDialog table should open");
+ assertTrue(
+ onUi(() -> table.getItem(0).getText(1)).length() <
LONG_VALUE.length(),
+ "a long value must be shortened in the cell, not stored at its
full length");
+ assertFalse(
+ onUi(() -> table.getItem(0).getText(2)).contains("\n"),
+ "a multi-line value must be single-lined in the cell, or the row
grows on GTK");
+
assertEquals(
LONG_VALUE,
- onUi(() -> table.getItem(0).getText(1)),
- "a long cell value must be stored in full, not truncated with an
ellipsis");
+ onUi(() -> TableView.getCellValue(table.getItem(0), 1)),
+ "the grid must still hand back the long value in full");
assertEquals(
multiLine,
- onUi(() -> table.getItem(0).getText(2)),
- "a multi-line cell value must keep all of its lines");
+ onUi(() -> TableView.getCellValue(table.getItem(0), 2)),
+ "the grid must still hand back the multi-line value with all of
its lines");
});
}
diff --git
a/rcp/src/test/java/org/apache/hop/ui/core/widget/TableViewDataGridRowHeightTest.java
b/rcp/src/test/java/org/apache/hop/ui/core/widget/TableViewDataGridRowHeightTest.java
new file mode 100644
index 0000000000..08f3b6ea02
--- /dev/null
+++
b/rcp/src/test/java/org/apache/hop/ui/core/widget/TableViewDataGridRowHeightTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.core.widget;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.testing.SwtBotTestBase;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.TableItem;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Guards the row height of an <em>editable</em> data grid — the Data tab of
the Data grid
+ * transform, and the edit-rows dialogs.
+ *
+ * <p>Row geometry is not uniform on every platform: GTK measures each row
from the text its cells
+ * hold, so a line break that reaches the cell grows that row to as many lines
as the value has
+ * (issue #8155). macOS gives every row the same height, so these can only
fail on GTK.
+ */
+@Tag("uitest")
+class TableViewDataGridRowHeightTest extends SwtBotTestBase {
+
+ private static final String MULTI_LINE = "first line\nsecond line\nthird
line\nfourth line";
+ private static final int VALUE_COLUMN = 1;
+
+ @Test
+ void aMultiLineValueDoesNotGrowItsRow() {
+ AtomicReference<TableView> gridRef = new AtomicReference<>();
+ withScene(
+ shell -> gridRef.set(buildGrid(shell)),
+ bot -> {
+ TableView grid = gridRef.get();
+ int singleLine = onUi(() ->
grid.table.getItem(0).getBounds(VALUE_COLUMN).height);
+ int multiLine = onUi(() ->
grid.table.getItem(1).getBounds(VALUE_COLUMN).height);
+
+ assertEquals(
+ singleLine,
+ multiLine,
+ "a multi-line value must not make its row taller than a
single-line one");
+ });
+ }
+
+ @Test
+ void theGridHandsBackTheCompleteValue() {
+ AtomicReference<TableView> gridRef = new AtomicReference<>();
+ withScene(
+ shell -> gridRef.set(buildGrid(shell)),
+ bot ->
+ assertEquals(
+ MULTI_LINE,
+ onUi(() ->
TableView.getCellValue(gridRef.get().table.getItem(1), VALUE_COLUMN)),
+ "the value must survive being drawn shortened, every line of
it"));
+ }
+
+ /**
+ * The value kept aside is only good while the cell still shows the text it
was derived from. A
+ * write that goes straight to the item — any path that does not know about
the grid's own value
+ * accessors — has to win, so that the worst such a path can cause is a
value drawn in full again,
+ * never a stale one handed back and saved.
+ */
+ @Test
+ void aValueWrittenStraightToTheCellTakesOver() {
+ AtomicReference<TableView> gridRef = new AtomicReference<>();
+ withScene(
+ shell -> gridRef.set(buildGrid(shell)),
+ bot -> {
+ TableItem item = onUi(() -> gridRef.get().table.getItem(1));
+ onUi(
+ () -> {
+ item.setText(VALUE_COLUMN, "written around the grid");
+ return null;
+ });
+
+ assertEquals(
+ "written around the grid",
+ onUi(() -> TableView.getCellValue(item, VALUE_COLUMN)),
+ "a cell written directly must be read back as it stands, not as
it was");
+ });
+ }
+
+ private TableView buildGrid(org.eclipse.swt.widgets.Shell shell) {
+ shell.setLayout(new FillLayout());
+ shell.setSize(900, 320);
+ ColumnInfo[] columns = {
+ new ColumnInfo("Value", ColumnInfo.COLUMN_TYPE_TEXT, false, false),
+ };
+ TableView grid =
+ new TableView(
+ new Variables(),
+ shell,
+ SWT.BORDER | SWT.FULL_SELECTION,
+ columns,
+ 3,
+ null,
+ PropsUi.getInstance());
+ // What the Data grid's Data tab and the edit-rows dialogs do: data rows,
drawn shortened.
+ grid.setShortenDisplayedValues(true);
+ grid.setCellValue(grid.table.getItem(0), VALUE_COLUMN, "single line");
+ grid.setCellValue(grid.table.getItem(1), VALUE_COLUMN, MULTI_LINE);
+ grid.setCellValue(grid.table.getItem(2), VALUE_COLUMN, "another single
line");
+ grid.optWidth(true);
+ return grid;
+ }
+
+ private static <T> T onUi(Supplier<T> supplier) {
+ AtomicReference<T> result = new AtomicReference<>();
+ AtomicReference<RuntimeException> failure = new AtomicReference<>();
+ display.syncExec(
+ () -> {
+ try {
+ result.set(supplier.get());
+ } catch (RuntimeException e) {
+ failure.set(e);
+ }
+ });
+ if (failure.get() != null) {
+ throw failure.get();
+ }
+ return result.get();
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/core/dialog/EditRowsDialog.java
b/ui/src/main/java/org/apache/hop/ui/core/dialog/EditRowsDialog.java
index 70d202d09c..0cf01cb0b7 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/dialog/EditRowsDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/dialog/EditRowsDialog.java
@@ -279,7 +279,7 @@ public class EditRowsDialog {
}
if (show != null) {
- item.setText(c + 1, show);
+ wFields.setCellValue(item, c + 1, show);
item.setForeground(c + 1, GuiResource.getInstance().getColorBlack());
} else {
// Set null value
@@ -303,7 +303,8 @@ public class EditRowsDialog {
if (isDisplayingNullValue(item, colnr)) {
row[i] = null; // <null> value
} else {
- String string = item.getText(colnr);
+ // The cell is drawn shortened; the value itself comes back out of
the grid.
+ String string = TableView.getCellValue(item, colnr);
if (stringValueMeta.isNull(string)) {
string = null;
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/core/dialog/PreviewRowsDialog.java
b/ui/src/main/java/org/apache/hop/ui/core/dialog/PreviewRowsDialog.java
index 4e5db37a60..1e06a314f6 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/dialog/PreviewRowsDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/dialog/PreviewRowsDialog.java
@@ -411,9 +411,9 @@ public class PreviewRowsDialog {
}
if (show != null) {
- // Store the full value: the grid shortens long / multi-line text at
paint time, so what is
- // copied, exported or read back out of the table stays complete.
- item.setText(c + 1, show);
+ // The cell holds the shortened, single-line text while the grid keeps
the full value
+ // aside, so what is copied, expanded or read back out of the table
stays complete.
+ wFields.setCellValue(item, c + 1, show);
item.setForeground(c + 1, GuiResource.getInstance().getColorBlack());
} else {
// Set null value
diff --git a/ui/src/main/java/org/apache/hop/ui/core/dialog/ShowRowsDialog.java
b/ui/src/main/java/org/apache/hop/ui/core/dialog/ShowRowsDialog.java
index 455d42d0b4..b0a80ff4ac 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/dialog/ShowRowsDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/dialog/ShowRowsDialog.java
@@ -228,9 +228,9 @@ public final class ShowRowsDialog {
}
if (displayValue != null) {
- // Store the full value: the grid shortens long / multi-line text at
paint time, so what is
- // copied, exported or read back out of the table stays complete.
- item.setText(column + 1, displayValue);
+ // The cell holds the shortened, single-line text while the grid keeps
the full value
+ // aside, so what is copied, expanded or read back out of the table
stays complete.
+ tableView.setCellValue(item, column + 1, displayValue);
item.setForeground(column + 1,
GuiResource.getInstance().getColorBlack());
} else {
item.setText(column + 1, "<null>");
diff --git a/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java
b/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java
index 05cfadb5e3..9acd521206 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java
@@ -116,6 +116,17 @@ public class TableView extends Composite {
private static final int EXTRA_COLUMN_WIDTH_MARGIN =
Const.toInt(HopConfig.readStringVariable(Const.HOP_TABLE_VIEW_EXTRA_COLUMN_MARGIN,
""), 0);
+ /**
+ * Key of the {@link TableItem} data holding a row's values as {@code
[full][displayed]}, both
+ * indexed by column. See {@link #setCellValue(TableItem, int, String)}.
+ */
+ private static final String CELL_VALUES_KEY = "TableView.CellValues";
+
+ /** Index of the complete value, and of the shortened text put in the cell,
in that data. */
+ private static final int FULL = 0;
+
+ private static final int DISPLAYED = 1;
+
/** Default minimum height hint in pixels for all TableView instances. */
public static final int HEIGHT_HINT_PX = 200;
@@ -859,7 +870,7 @@ public class TableView extends Composite {
final String[] fBeforeEdit = beforeEdit;
String[] afterEdit = getItemText(row);
checkChanged(new String[][] {fBeforeEdit}, new String[][] {afterEdit},
new int[] {rowNr});
- row.setText(colNr, value);
+ setCellValue(row, colNr, value);
};
}
@@ -1745,8 +1756,12 @@ public class TableView extends Composite {
// Keep TableItem#getData() across the rebuild so callers that tag their
rows can still map a
// visual row back to their own data after the user sorts a column.
final Object[] preservedData = new Object[items.length];
+ final String[][][] preservedCellValues = new String[items.length][][];
for (int i = 0; i < items.length; i++) {
preservedData[i] = items[i].getData();
+ // A sort rebuilds every item from its text, so the values kept aside
by setCellValue have
+ // to travel with the row or the grid would be left holding only the
shortened text.
+ preservedCellValues[i] = (String[][])
items[i].getData(CELL_VALUES_KEY);
}
final int[] sortIndex = new int[] {sortField + 2};
@@ -1802,6 +1817,9 @@ public class TableView extends Composite {
if (preservedData[origIdx] != null) {
item.setData(preservedData[origIdx]);
}
+ if (preservedCellValues[origIdx] != null) {
+ item.setData(CELL_VALUES_KEY, preservedCellValues[origIdx]);
+ }
}
table.setSortColumn(table.getColumn(this.sortField));
table.setSortDirection(sortingDescending ? SWT.DOWN : SWT.UP);
@@ -1972,7 +1990,7 @@ public class TableView extends Composite {
}
String textData = getTextWidgetValue(colNr);
- row.setText(colNr, textData);
+ setCellValue(row, colNr, textData);
disposeInlineEditor();
table.setFocus();
@@ -2118,7 +2136,7 @@ public class TableView extends Composite {
seed = getTextWidgetValue(colNr);
disposeInlineEditor();
} else {
- seed = row.getText(colNr);
+ seed = getCellValue(row, colNr);
}
setPosition(rowNr, colNr);
@@ -2127,15 +2145,19 @@ public class TableView extends Composite {
if (!viewOnly) {
beforeEdit = getItemText(row);
// An edit is already in progress when the carried-over text differs
from the stored value.
- fieldChanged = !seed.equals(row.getText(colNr));
+ fieldChanged = !seed.equals(getCellValue(row, colNr));
}
Rectangle cellBounds = row.getBounds(colNr);
Point location = table.toDisplay(cellBounds.x, cellBounds.y);
// Resizable (but title-less) floating shell so the user can drag its
edges to make a long value
- // bigger, matching the read-only value viewer.
- final Shell popup = new Shell(getShell(), SWT.RESIZE);
+ // bigger, matching the read-only value viewer. SWT.RESIZE on its own is
only title-less on
+ // macOS: it is part of SWT.SHELL_TRIM, so GTK leaves the window decorated
and the window
+ // manager puts a full title bar with minimize and maximize on a pop-out
that has no use for
+ // either. Adding SWT.ON_TOP makes a child shell a GTK popup window, which
SWT undecorates,
+ // and keeps the drag-to-resize border by way of SWT's own custom resize.
+ final Shell popup = new Shell(getShell(), SWT.ON_TOP | SWT.RESIZE);
multilineShell = popup;
popup.addListener(
SWT.Dispose,
@@ -2196,8 +2218,8 @@ public class TableView extends Composite {
// A value viewer only closes: nothing to store, nothing changed.
return;
}
- if (!newValue.equals(row.getText(colNr))) {
- row.setText(colNr, newValue);
+ if (!newValue.equals(getCellValue(row, colNr))) {
+ setCellValue(row, colNr, newValue);
}
String[] afterEdit = getItemText(row);
checkChanged(new String[][] {beforeEdit}, new String[][]
{afterEdit}, new int[] {rowNr});
@@ -2370,10 +2392,64 @@ public class TableView extends Composite {
return "\n".equals(Text.DELIMITER) ? unix : unix.replace("\n",
Text.DELIMITER);
}
+ /**
+ * Fill a data-grid cell: the untruncated value is kept on the item and the
cell itself only gets
+ * the shortened, single-line text.
+ *
+ * <p>Native tables take their geometry from the text a cell holds, and not
every platform stops
+ * at the first line: GTK measures every row from its cell renderers, so a
stored line break makes
+ * the whole row grow to as many lines as the value has (macOS keeps a
uniform row height, which
+ * is why this stays invisible there). Drawing the value shortened is
therefore not enough — the
+ * text we do not want drawn must not be in the cell to begin with.
+ *
+ * <p>Use it for the grids that show data rather than configuration.
Everything in this widget
+ * that needs the real value reads it with {@link #getCellValue(TableItem,
int)}; a grid that
+ * hands its rows out to a caller has to do the same.
+ */
+ public void setCellValue(TableItem item, int colNr, String value) {
+ if (!shortenDisplayedValues) {
+ item.setText(colNr, value);
+ return;
+ }
+ String[][] cells = (String[][]) item.getData(CELL_VALUES_KEY);
+ if (cells == null) {
+ int columnCount = table.getColumnCount();
+ cells = new String[][] {new String[columnCount], new
String[columnCount]};
+ item.setData(CELL_VALUES_KEY, cells);
+ }
+ String display = formatCellValueForDisplay(value);
+ display = display == null ? "" : display;
+ if (colNr < cells[FULL].length) {
+ cells[FULL][colNr] = value;
+ cells[DISPLAYED][colNr] = display;
+ }
+ item.setText(colNr, display);
+ }
+
+ /**
+ * The complete value of a cell: the one kept aside by {@link
#setCellValue(TableItem, int,
+ * String)}, or the cell text itself for the grids that hold their values in
full.
+ *
+ * <p>The value is only used while the cell still shows the text it was
derived from. Anything
+ * that writes the cell some other way therefore takes over cleanly: the
worst a write path that
+ * does not know about this can cause is a value drawn in full again, never
a stale one saved.
+ */
+ public static String getCellValue(TableItem item, int colNr) {
+ String[][] cells = (String[][]) item.getData(CELL_VALUES_KEY);
+ if (cells != null
+ && colNr < cells[FULL].length
+ && cells[FULL][colNr] != null
+ && cells[DISPLAYED][colNr].equals(item.getText(colNr))) {
+ return cells[FULL][colNr];
+ }
+ return item.getText(colNr);
+ }
+
/**
* The shortened display string for a text cell whose stored value is longer
/ multi-line, or null
- * when the cell should be drawn natively (non-text column, or nothing to
shorten). Used by the
- * desktop owner-draw so {@link TableItem#getText(int)} keeps returning the
full, saved value.
+ * when the cell should be drawn natively (nothing to shorten, or the cell
already holds the
+ * shortened text because the grid stores its values with {@link
#setCellValue(TableItem, int,
+ * String)}).
*/
private String customCellText(TableItem item, int columnIndex) {
if (!shortenDisplayedValues
@@ -2388,9 +2464,8 @@ public class TableView extends Composite {
&& colinfo.getType() != ColumnInfo.COLUMN_TYPE_TEXT_BUTTON)) {
return null;
}
- String full = item.getText(columnIndex);
- String display = formatCellValueForDisplay(full);
- return display != null && !display.equals(full) ? display : null;
+ String display = formatCellValueForDisplay(getCellValue(item,
columnIndex));
+ return display != null && !display.equals(item.getText(columnIndex)) ?
display : null;
}
private void eraseCell(Event event) {
@@ -2765,11 +2840,11 @@ public class TableView extends Composite {
if (c > 1) {
selection.append(CLIPBOARD_DELIMITER);
}
- String value = ti.getText(c);
+ String value = getCellValue(ti, c);
if (StringUtils.isNotEmpty(value)) {
Color textColor = ti.getForeground(c);
if (!nullTextColor.equals(textColor) || !"<null>".equals(value)) {
- selection.append(ti.getText(c));
+ selection.append(value);
}
}
}
@@ -3086,7 +3161,7 @@ public class TableView extends Composite {
String[] retval = new String[table.getColumnCount() - 1];
for (int i = 0; i < retval.length; i++) {
- retval[i] = row.getText(i + 1);
+ retval[i] = getCellValue(row, i + 1);
}
return retval;
@@ -3137,12 +3212,12 @@ public class TableView extends Composite {
// edit values that contain a line break in the multi-line pop-out editor
instead.
if ((colinfo.getType() == ColumnInfo.COLUMN_TYPE_TEXT
|| colinfo.getType() == ColumnInfo.COLUMN_TYPE_TEXT_BUTTON)
- && indexOfLineBreak(row.getText(colNr)) >= 0) {
+ && indexOfLineBreak(getCellValue(row, colNr)) >= 0) {
editMultiline(row, rowNr, colNr, colinfo);
return;
}
- String content = row.getText(colNr) + (!viewOnly && extra != 0 ? "" +
extra : "");
+ String content = getCellValue(row, colNr) + (!viewOnly && extra != 0 ? ""
+ extra : "");
String tooltip = columns[colNr - 1].getToolTip();
final boolean useVariables = !viewOnly && columns[colNr -
1].isUsingVariables();
@@ -4680,7 +4755,7 @@ public class TableView extends Composite {
String[] retval = new String[table.getItemCount()];
for (int i = 0; i < retval.length; i++) {
TableItem item = table.getItem(i);
- retval[i] = item.getText(colNr + 1);
+ retval[i] = getCellValue(item, colNr + 1);
}
return retval;
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
index d5e915dd1d..4ccb36ff59 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
@@ -629,6 +629,10 @@ public class PipelineExecutionViewer extends
BaseExecutionViewer
null,
props);
+ // Data rows, not configuration: draw long / multi-line values
shortened. The value
+ // itself stays on the item, out of the cell, so the row keeps to
a single line.
+ dataView.setShortenDisplayedValues(true);
+
for (int r = 0; r < rowBuffer.size(); r++) {
Object[] row = rowBuffer.getBuffer().get(r);
TableItem item = dataView.table.getItem(r);
@@ -638,7 +642,7 @@ public class PipelineExecutionViewer extends
BaseExecutionViewer
if (value == null) {
value = "";
}
- item.setText(c + 1, value);
+ dataView.setCellValue(item, c + 1, value);
}
}
dataView.optWidth(true);
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
index 5e2b41cb79..3ab912c293 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
@@ -441,6 +441,10 @@ public class WorkflowExecutionViewer extends
BaseExecutionViewer
null,
props);
+ // Data rows, not configuration: draw long / multi-line values
shortened. The value
+ // itself stays on the item, out of the cell, so the row keeps to a
single line.
+ dataView.setShortenDisplayedValues(true);
+
for (int r = 0; r < rowBuffer.size(); r++) {
Object[] row = rowBuffer.getBuffer().get(r);
TableItem item = dataView.table.getItem(r);
@@ -450,7 +454,7 @@ public class WorkflowExecutionViewer extends
BaseExecutionViewer
if (value == null) {
value = "";
}
- item.setText(c + 1, value);
+ dataView.setCellValue(item, c + 1, value);
}
}
dataView.optWidth(true);