Skip to content

Commit

Permalink
Expand an expandable node once it is visible.
Browse files Browse the repository at this point in the history
It will calculate the location of expandable node, once it enters
visible area of Viewer expand it.
Install resize listener for control when limit is set and remove limit
is reset.Do the same thing for Vertical Scroll bar control.
Honor the entire drag event as one selection at the end of the drag.

see eclipse-platform#818
  • Loading branch information
raghucssit committed Aug 24, 2023
1 parent ffb0cdc commit f7980cf
Show file tree
Hide file tree
Showing 4 changed files with 321 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,7 @@ protected List getSelectionFromWidget() {
protected void handleDoubleSelect(SelectionEvent event) {
// expand ExpandableNode for default selection.
if (event.item != null && event.item.getData() instanceof ExpandableNode node) {
handleExpandableNodeClicked(event.item);
handleExpandableNodeClicked(event.item, true);
// do not notify client listeners for this item.
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ private void handleMouseDown(MouseEvent e) {

if (cell != null) {
if (cell.getElement() instanceof ExpandableNode) {
handleExpandableNodeClicked(cell.getItem());
handleExpandableNodeClicked(cell.getItem(), true);
} else {
triggerEditorActivationEvent(new ColumnViewerEditorActivationEvent(cell, e));
}
Expand Down Expand Up @@ -903,9 +903,10 @@ final Object[] applyItemsLimit(Object parent, Object[] sorted) {
* <p>
* Default implementation does nothing.
*
* @param cell selected on click
* @param cell selected on click
* @param setSelection
*/
void handleExpandableNodeClicked(Widget cell) {
void handleExpandableNodeClicked(Widget cell, boolean setSelection) {
// default implementation does nothing. Actual viewers can decide how to
// populate remaining elements.
}
Expand Down Expand Up @@ -935,12 +936,15 @@ Object[] getChildrenWithLimitApplied(final Object parent, Item[] visibleChildren
}

// fetch entire sorted children we need them in any of next cases.
boolean oldBusy = isBusy();
setBusy(true);
setDisplayIncrementally(0);
Object[] sortedAll;
try {
sortedAll = getSortedChildren(parent);
} finally {
setDisplayIncrementally(limit);
setBusy(oldBusy);
}

// model has lost some elements and length is less then visible items.
Expand Down Expand Up @@ -1049,7 +1053,7 @@ Set<ExpandableNode> getExpandableNodes() {
@Override
protected void handleDoubleSelect(SelectionEvent event) {
if (event.item != null && event.item.getData() instanceof ExpandableNode) {
handleExpandableNodeClicked(event.item);
handleExpandableNodeClicked(event.item, true);
// we do not want client listeners to be notified for this item.
return;
}
Expand Down
188 changes: 151 additions & 37 deletions bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TableViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.internal.ExpandableNode;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
Expand Down Expand Up @@ -78,6 +83,16 @@ public class TableViewer extends AbstractTableViewer {
*/
private TableViewerRow cachedRow;

/**
* listen to tree resize and expand expandable node once it is visible.
*/
private ControlListener controlListener = null;

/**
* listen to scroll bar selection and expand expandable node once it is visible.
*/
private Listener vScrollListener = null;

/**
* Creates a table viewer on a newly-created table control under the given
* parent. The table control is created using the SWT style bits
Expand Down Expand Up @@ -458,51 +473,150 @@ protected Widget doFindItem(Object element) {
}

@Override
void handleExpandableNodeClicked(Widget w) {
if (!(w instanceof Item item)) {
return;
}
void handleExpandableNodeClicked(Widget w, boolean setSelection) {
BusyIndicator.showWhile(table.getDisplay(), () -> {

if (!(w instanceof Item item)) {
return;
}

Object data = item.getData();

if (!(data instanceof ExpandableNode expNode)) {
return;
}
boolean oldBusy = isBusy();
Table table = getTable();
try {
setBusy(true);
table.setRedraw(false);

Object[] sortedChildren = expNode.getRemainingElements();
Object[] nextChildren = applyItemsLimit(data, sortedChildren);

if (nextChildren.length > 0) {
disassociate(item);
int index = doIndexOf(item);
// will also call item.dispose()
doRemove(new int[] { index });

for (int i = 0; i < nextChildren.length; i++) {
createItem(nextChildren[i], index++);
}

if (!setSelection) {
return;
}

// If we've expanded but still have not reached the limit
// select new expandable node, so user can click through
// to the end
if (getLastElement() instanceof ExpandableNode node) {
setSelection(new StructuredSelection(node), true);
} else {
// reset the selection. client's selection listener should not be triggered.
// there was only one selection on Expandable Node.
int[] curSel = table.getSelectionIndices();
if (curSel.length == 1) {
table.deselect(curSel[0]);
}
}
}
} finally {
setBusy(oldBusy);
table.setRedraw(true);
}

Object data = item.getData();
});
}

@Override
public void setDisplayIncrementally(int incrementSize) {
super.setDisplayIncrementally(incrementSize);

if (!(data instanceof ExpandableNode expNode)) {
if (isBusy()) {
return;
}
boolean oldBusy = isBusy();
Table table = getTable();
try {
setBusy(true);
table.setRedraw(false);

Object[] sortedChildren = expNode.getRemainingElements();
Object[] nextChildren = applyItemsLimit(data, sortedChildren);

if (nextChildren.length > 0) {
disassociate(item);
int index = doIndexOf(item);
// will also call item.dispose()
doRemove(new int[] { index });

for (int i = 0; i < nextChildren.length; i++) {
createItem(nextChildren[i], index++);

// trying to reset the viewer limit.
if (incrementSize <= 0) {
if (controlListener != null) {
table.removeControlListener(controlListener);
controlListener = null;
}
if (vScrollListener != null) {
ScrollBar vScrol = table.getVerticalBar();
if (vScrol != null) {
vScrol.removeListener(SWT.Selection, vScrollListener);
vScrollListener = null;
}
// If we've expanded but still have not reached the limit
// select new expandable node, so user can click through
// to the end
if (getLastElement() instanceof ExpandableNode node) {
setSelection(new StructuredSelection(node), true);
} else {
// reset the selection. client's selection listener should not be triggered.
// there was only one selection on Expandable Node.
int[] curSel = table.getSelectionIndices();
if (curSel.length == 1) {
table.deselect(curSel[0]);
}
return;
}

// trying to set/change viewer limit.
if (controlListener == null) {
controlListener = new ControlListener() {
@Override
public void controlResized(ControlEvent e) {
if (table.getItemCount() > 0) {
TableItem lastItem = table.getItems()[table.getItemCount() - 1];
if (isExpandableNode(lastItem.getData())) {
int treeHeight = table.getBounds().height;
int itemsHeight = lastItem.getBounds().height * table.getItemCount();
int origHeight = itemsHeight;
// there are few items shown than tree height.
while (itemsHeight < treeHeight) {
// expand last node.
handleExpandableNodeClicked(lastItem, false);
// check if if have no more expandable node.
lastItem = table.getItems()[table.getItemCount() - 1];
if (!isExpandableNode(lastItem.getData())) {
break;
}
// each expansion should increase the height by original height.
itemsHeight = itemsHeight + origHeight;
}
}
}
}

@Override
public void controlMoved(ControlEvent e) {
}
};
// listen to tree resizes.
table.addControlListener(controlListener);
}

if (vScrollListener == null) {
// listen to vertical scroll bar selection
ScrollBar vScrol = table.getVerticalBar();
if (vScrol != null) {
vScrollListener = event -> {
// A series events from drag triggers multiple expansions. This results in
// behavior of Virtual viewer.
// Entire drag ends with single selection and if the Expandable node is visible
// we can expand.
if (event.detail == 1) {
return;
}
if (table.getItemCount() > 0) {
TableItem lastItem = table.getItems()[table.getItemCount() - 1];
if (isExpandableNode(lastItem.getData())) {
int treeHeight = table.getBounds().height;
int startOfLast = lastItem.getBounds().y;
// last element became visible.
if (startOfLast < treeHeight) {
handleExpandableNodeClicked(lastItem, false);
}
}
}

};
vScrol.addListener(SWT.Selection, vScrollListener);
}
} finally {
setBusy(oldBusy);
table.setRedraw(true);

}
}

Expand Down

0 comments on commit f7980cf

Please sign in to comment.