Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2025 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -50,9 +50,8 @@ public void testCorrectRowOrderAfterAddRows() {
}

/**
* Table expect always to have all parent rows
* Table ignores rows with non-existing parent.
*/
@Test(expected = IllegalArgumentException.class)
public void testAddRowsWithInvalidRowList() {
P_SinglePrimaryKeyColumnTable table = new P_SinglePrimaryKeyColumnTable();
table.init();
Expand All @@ -61,21 +60,27 @@ public void testAddRowsWithInvalidRowList() {
rows.add(table.createRow(new Object[]{2, null}));
rows.add(table.createRow(new Object[]{3, 4}));
table.addRows(rows);

assertEquals(3, table.getRowCount());
assertEquals(2, table.getFilteredRowCount());
}

/**
* Table expect always to have all parent rows
* Table ignores rows with non-existing parent.
*/
@Test(expected = IllegalArgumentException.class)
public void testAddRowWithUnresolvedParentRow() {
P_SinglePrimaryKeyColumnTable table = new P_SinglePrimaryKeyColumnTable();
table.init();
List<ITableRow> rows = new ArrayList<>();
rows.add(table.createRow(new Object[]{1, null}));
rows.add(table.createRow(new Object[]{2, null}));
table.addRows(rows);
assertEquals(2, table.getRowCount());
assertEquals(2, table.getFilteredRowCount());

table.addRow(table.createRow(new Object[]{3, 4}));
assertEquals(3, table.getRowCount());
assertEquals(2, table.getFilteredRowCount());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2025 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -649,10 +649,10 @@ protected CheckableStyle getConfiguredCheckableStyle() {
* Subclasses can override this method. Default is {@link TriState#UNDEFINED}
*
* @return <ul>
* <li>{@link TriState#TRUE} if the tooltip should always be shown if the cell content is truncated</li>
* <li>{@link TriState#FALSE} if the tooltip should never be shown</li>
* <li>{@link TriState#UNDEFINED} cell tooltip is only shown if it is not possible to resize the column</li>
* </ul>
* <li>{@link TriState#TRUE} if the tooltip should always be shown if the cell content is truncated</li>
* <li>{@link TriState#FALSE} if the tooltip should never be shown</li>
* <li>{@link TriState#UNDEFINED} cell tooltip is only shown if it is not possible to resize the column</li>
* </ul>
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(270)
Expand Down Expand Up @@ -3250,13 +3250,18 @@ private void rebuildTreeStructure() {

private void rebuildTreeStructureInternal() {
List<ITableRow> rootNodes = new ArrayList<>();
Set<ITableRow> orphanRows = new HashSet<>();
Map<ITableRow/*parent*/, List<ITableRow> /*child rows*/> parentToChildren = new HashMap<>();
m_rows.forEach(row -> {
List<Object> parentRowKeys = getParentRowKeys(row);
if (parentRowKeys.stream().filter(Objects::nonNull).findAny().orElse(null) != null) {
ITableRow parentRow = getRowByKey(parentRowKeys);
if (parentRow == null) {
throw new IllegalArgumentException("Could not find the parent row of '" + row + "'. parent keys are defined.");
LOG.warn("Ignoring row with key {} because its parent key {} could not be found. {}", row.getKeyValues(), row.getParentKeyValues(), row);
row.setParentRowInternal(null);
rootNodes.add(row);
orphanRows.add(row);
return;
}
parentToChildren.computeIfAbsent(parentRow, children -> new ArrayList<>())
.add(row);
Expand All @@ -3266,6 +3271,10 @@ private void rebuildTreeStructureInternal() {
rootNodes.add(row);
}
});
getRowFilters().stream().filter(f -> f instanceof P_OrphanRowFilter).forEach(this::removeRowFilter);
if (!orphanRows.isEmpty()) {
addRowFilter(new P_OrphanRowFilter(orphanRows));
}

m_rootRows = Collections.synchronizedList(rootNodes);
boolean hierarchical = !parentToChildren.isEmpty();
Expand Down Expand Up @@ -5117,6 +5126,32 @@ public IFormField getFormField() {
}
}

/**
* Filter that hides orphaned rows, i.e. rows that have a non-null {@link ITableRow#getParentKeyValues() parent key},
* but no such parent row exists. This can happen for example due to a row limit.
*/
protected static class P_OrphanRowFilter implements ITableRowFilter {

protected final Set<ITableRow> m_orphanRows;

/**
* @param orphanRows
* set of orphaned rows (rows with non-existing parent) that are to be filtered by this filter
*/
public P_OrphanRowFilter(Set<ITableRow> orphanRows) {
m_orphanRows = Assertions.assertNotNull(orphanRows);
}

public Set<ITableRow> getOrphanRows() {
return m_orphanRows;
}

@Override
public boolean accept(ITableRow row) {
return !m_orphanRows.contains(row);
}
}

protected static class LocalTableExtension<TABLE extends AbstractTable> extends AbstractExtension<TABLE> implements ITableExtension<TABLE> {

public LocalTableExtension(TABLE owner) {
Expand Down