Skip to content

Commit

Permalink
Limit based table and tree viewer implementation (eclipse-platform#818)
Browse files Browse the repository at this point in the history
TODO: provide proper commit message

Fixes eclipse-platform#818
  • Loading branch information
raghucssit authored and iloveeclipse committed Jun 27, 2023
1 parent 3f9aeb1 commit 1ae1179
Show file tree
Hide file tree
Showing 23 changed files with 1,214 additions and 21 deletions.
2 changes: 1 addition & 1 deletion bundles/org.eclipse.jface/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jface;singleton:=true
Bundle-Version: 3.30.100.qualifier
Bundle-Version: 3.31.0.qualifier
Bundle-ClassPath: .
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,17 @@ public void add(Object[] elements) {
return;
Object[] filtered = filter(elements);

// if limit is set and still some elements are not
// populated. Assumption that user has already updated the model and needs
// addition of an item.
if (getItemsLimit() > 0 && filtered.length > 0) {
Item[] items = doGetItems();
if (getLastElement(items) instanceof IExpandableNode) {
internalRefreshAll(false);
return;
}
}

for (Object element : filtered) {
int index = indexForElement(element);
createItem(element, index);
Expand All @@ -281,9 +292,9 @@ public void add(Object[] elements) {
* @param element
* @param index
*
* @since 3.1
* @since 3.31
*/
private void createItem(Object element, int index) {
protected void createItem(Object element, int index) {
if (virtualManager == null) {
updateItem(internalCreateNewRowPart(SWT.NONE, index).getItem(),
element);
Expand Down Expand Up @@ -384,6 +395,12 @@ protected void doUpdateItem(Widget widget, Object element, boolean fullMap) {
// Also enter loop if no columns added. See 1G9WWGZ: JFUIF:WINNT -
// TableViewer with 0 columns does not work
for (int column = 0; column < columnCount || column == 0; column++) {

// No need to update any labels in any other columns for this element?
if (element instanceof IExpandableNode && column != 0) {
continue;
}

ViewerColumn columnViewer = getViewerColumn(column);
ViewerCell cellToUpdate = updateCell(viewerRowFromItem,
column, element);
Expand Down Expand Up @@ -597,6 +614,19 @@ public void insert(Object element, int position) {
add(element);
return;
}

if (getItemsLimit() > 0) {
// if it has limit based content provider and still some elements are not
// populated.Assumption that user has already updated the model and needs
// addition of item.
Item[] items = doGetItems();
if (element != null && getLastElement(items) instanceof IExpandableNode) {
internalRefreshAll(false);
return;
}
return;
}

if (position == -1) {
position = doGetItemCount();
}
Expand Down Expand Up @@ -666,9 +696,18 @@ private void internalRefreshAll(boolean updateLabels) {
// e.g. if (a, b) is replaced by (b, a), the disassociate of b to
// item 1 could undo
// the associate of b to item 0.

Object[] children = getSortedChildren(getRoot());
Object[] children = null;
Item[] items = doGetItems();
if (getItemsLimit() > 0) {
if (items.length == 0) {
children = getSortedChildren(getRoot());
}
if (items.length > 0) {
children = getVisibleLimitBasedChildren(getRoot(), items);
}
} else {
children = getSortedChildren(getRoot());
}
int min = Math.min(children.length, items.length);
for (int i = 0; i < min; ++i) {

Expand Down Expand Up @@ -747,6 +786,18 @@ private void internalRemove(final Object[] elements) {
return;
}
}

// if it has limit based content provider and still some elements are not populated.
// Assumption that user has already updated the model and needs removal of an
// item.
if (getItemsLimit() > 0) {
Item[] items = doGetItems();
if (getLastElement(items) instanceof IExpandableNode) {
internalRefreshAll(false);
return;
}
}

// use remove(int[]) rather than repeated TableItem.dispose() calls
// to allow SWT to optimize multiple removals
int[] indices = new int[elements.length];
Expand Down Expand Up @@ -779,6 +830,18 @@ private void internalRemove(final Object[] elements) {
}
}

/**
* @param items
* @return may return null
*/
private Object getLastElement(Item[] items) {
int length = items.length;
if (length == 0) {
return null;
}
return items[length - 1].getData();
}

/**
* Removes the given elements from this table viewer. The selection is
* updated if required.
Expand Down Expand Up @@ -825,6 +888,20 @@ public void remove(Object element) {
public void reveal(Object element) {
Assert.isNotNull(element);
Widget w = findItem(element);

if (w == null) {
Item[] items = doGetItems();
if (getLastElement(items) instanceof IExpandableNode node) {
Object[] remEles = node.getRemainingElements();
for (Object object : remEles) {
if (equals(object, element)) {
w = items[items.length - 1];
break;
}
}
}
}

if (w instanceof Item) {
doShowItem((Item) w);
}
Expand Down Expand Up @@ -885,6 +962,27 @@ protected void setSelectionToWidget(@SuppressWarnings("rawtypes") List list, boo
System.arraycopy(indices, 0, indices = new int[count], 0, count);
}

// item to select may be hidden inside expandable node.
if (indices.length < list.size() && getLastElement(items) instanceof IExpandableNode expNode) {
Object[] remEles = expNode.getRemainingElements();
boolean breakOuter = false;
for (Object seachItem : list) {
for (Object remEle : remEles) {
if (equals(remEle, seachItem)) {
int[] placeHolder = new int[indices.length + 1];
System.arraycopy(indices, 0, placeHolder, 0, indices.length);
placeHolder[placeHolder.length - 1] = items.length - 1;
indices = placeHolder;
breakOuter = true;
break;
}
}
if (breakOuter) {
break;
}
}
}

doSelect(indices);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

Expand All @@ -43,6 +44,7 @@
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;

/**
Expand Down Expand Up @@ -286,6 +288,18 @@ protected void internalAdd(Widget widget, Object parentElementOrTreePath,
comparator.sort(this, filtered);
}
}
// there are elements to be shown and viewer is showing limited items.
// newly added element can be inside expandable node or can be visible item.
// Assumption that user has already updated the model and needs addition of
// item.
if (getItemsLimit() > 0) {
Item[] items = getChildren(widget);
if (items.length > 0 && items[items.length - 1].getData() instanceof IExpandableNode) {
internalRefreshStruct(widget, parent, false);
return;
}
}

createAddedElements(widget, filtered);
if (InternalPolicy.DEBUG_LOG_EQUAL_VIEWER_ELEMENTS) {
Item[] children = getChildren(widget);
Expand Down Expand Up @@ -635,10 +649,11 @@ private int internalCompare(ViewerComparator comparator,

@Override
protected Object[] getSortedChildren(Object parentElementOrTreePath) {
Object[] result = getFilteredChildren(parentElementOrTreePath);
Object[] result = null;
ViewerComparator comparator = getComparator();
if (parentElementOrTreePath != null
&& comparator instanceof TreePathViewerSorter) {
result = getFilteredChildren(parentElementOrTreePath);
TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;

// be sure we're not modifying the original array from the model
Expand All @@ -655,10 +670,9 @@ protected Object[] getSortedChildren(Object parentElementOrTreePath) {
}
}
tpvs.sort(this, path, result);
} else if (comparator != null) {
// be sure we're not modifying the original array from the model
result = result.clone();
comparator.sort(this, result);
result = applyItemsLimit(parentElementOrTreePath, result);
} else {
return super.getSortedChildren(parentElementOrTreePath);
}
return result;
}
Expand Down Expand Up @@ -958,6 +972,10 @@ protected void doUpdateItem(final Item item, Object element) {
}

for (int column = 0; column < columnCount; column++) {
// No need to update any labels in any other columns for this element?
if (element instanceof IExpandableNode && column != 0) {
continue;
}
ViewerColumn columnViewer = getViewerColumn(column);
ViewerCell cellToUpdate = updateCell(viewerRowFromItem, column,
element);
Expand Down Expand Up @@ -1422,6 +1440,9 @@ protected Object[] getRawChildren(Object parentElementOrTreePath) {
return super.getRawChildren(parent);
}
IContentProvider cp = getContentProvider();
if (getItemsLimit() > 0 && parent instanceof IExpandableNode expNode) {
return expNode.getRemainingElements();
}
if (cp instanceof ITreePathContentProvider) {
ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
if (path == null) {
Expand Down Expand Up @@ -1968,7 +1989,15 @@ protected void internalRefresh(Widget widget, Object element,
*/
/* package */void internalRefreshStruct(Widget widget, Object element,
boolean updateLabels) {
updateChildren(widget, element, null, updateLabels);
Object[] updatedChildren = null;
// always return limited list of elements for a given
// parent. Doesn't matter what was already expanded in the tree. This will
// destroy all the populated elements on refresh.
if (getItemsLimit() > 0) {
Item[] visibleChildren = getChildren(widget);
updatedChildren = getVisibleLimitBasedChildren(element, visibleChildren);
}
updateChildren(widget, element, updatedChildren, updateLabels);
Item[] children = getChildren(widget);
if (children != null) {
for (Item item : children) {
Expand Down Expand Up @@ -2000,6 +2029,27 @@ protected void internalRemove(Object[] elementsOrPaths) {
setInput(null);
return;
}

boolean continueOuter = false;
if (getItemsLimit() > 0) {
Widget[] itemsOfElement = internalFindItems(element);
for (Widget item : itemsOfElement) {
if (item instanceof TreeItem) {
TreeItem parentItem = ((TreeItem) item).getParentItem();
if (parentItem == null) {
internalRefreshStruct(((TreeItem) item).getParent(), getInput(), false);
continueOuter = true;
break;
}
// refresh parent item with the latest model.
internalRefreshStruct(parentItem, parentItem.getData(), false);
continueOuter = true;
}
}
}
if (continueOuter) {
continue;
}
Widget[] childItems = internalFindItems(element);
if (childItems.length > 0) {
for (Widget childItem : childItems) {
Expand Down Expand Up @@ -2053,6 +2103,17 @@ protected void internalRemove(Object parent, Object[] elements) {
// Iterate over the child items and remove each one
Item[] children = getChildren(parentItem);

// there are elements to be shown and viewer is showing limited items.
// newly added element can be inside expandable node or can be visible item.
// Assumption that user has already updated the model and needs removal of
// an item.
if (getItemsLimit() > 0) {
if (children.length > 0 && children[children.length - 1].getData() instanceof IExpandableNode) {
internalRefreshStruct(parentItem, parentItem.getData(), false);
continue;
}
}

if (children.length == 1 && children[0].getData() == null &&
parentItem instanceof Item) { // dummy node
// Remove plus if parent element has no children
Expand Down Expand Up @@ -2579,6 +2640,41 @@ protected void setSelectionToWidget(@SuppressWarnings("rawtypes") List v, boolea
}
}
}

// there can be some items inside expandable node and not populated yet. In this
// case try to find the item to select inside all the visible expandable nodes.
if (newSelection.size() < v.size() && getItemsLimit() > 0) {
// make out still not found items
List<Object> notFound = new ArrayList<>();
for (Object toSelect : v) {
boolean bFound = false;
for (Item found : newSelection) {
if (equals(toSelect, found.getData())) {
bFound = true;
break;
}
}
if (!bFound) {
notFound.add(toSelect);
}
}

// find out all visible expandable nodes
Collection<IExpandableNode> expandItems = getExpandableNodes();

// search for still missing items inside expandable nodes
for (Object nFound : notFound) {
for (IExpandableNode expNode : expandItems) {
if (findElementInExpandableNode(expNode, nFound)) {
Widget w = findItem(expNode);
if (w instanceof Item item) {
newSelection.add(item);
}
}
}
}
}

setSelection(newSelection);

// Although setting the selection in the control should reveal it,
Expand All @@ -2594,6 +2690,20 @@ protected void setSelectionToWidget(@SuppressWarnings("rawtypes") List v, boolea
}
}

private boolean findElementInExpandableNode(IExpandableNode expNode, Object toFind) {
if (equals(expNode, toFind)) {
return true;
}

Object[] remEles = getFilteredChildren(expNode);
for (Object element : remEles) {
if (equals(element, toFind)) {
return true;
}
}
return false;
}

/**
* Shows the given item.
*
Expand Down
Loading

0 comments on commit 1ae1179

Please sign in to comment.