Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TreeViewer: auto expansion for elements with single children #1072

Merged

Conversation

Wittmaxi
Copy link

@Wittmaxi Wittmaxi commented Aug 29, 2023

As implementation of #1063, This PR addresses the need to automatically expand paths which consist of chained singular nodes, eg:

com.wittmaxi.plugin
 └─src
    └─org.foo.com
       └─Bar.java

It introduces two new API-Methods into TreeViewer:

-setAutoExpandTrivialPathsLevel
-getAutoExpandTrivialPathsLevel

The PR also uses the new features in the Project Explorer, thus resolving #1063

@Wittmaxi Wittmaxi marked this pull request as draft August 29, 2023 09:32
@Wittmaxi
Copy link
Author

Wittmaxi commented Aug 29, 2023

I still need to address a few points as part of this PR

  • When double-clicking on an item, the TreeListener-hook is not called
  • There are no Unit-Tests yet
  • The behaviour should be off by default
  • What should be the default value for expandTrivialPathsLevel?

@merks
Copy link
Contributor

merks commented Aug 29, 2023

For auto expand there are only getAutoExpandLevel/setAutoExpandLevel with 0 and -1 having special meaning so it's seems a little strange/confusing four methods for this new feature...

@github-actions
Copy link
Contributor

github-actions bot commented Aug 29, 2023

Test Results

   917 files   -     1     917 suites   - 1   36m 44s ⏱️ - 12m 44s
 7 507 tests +   55   7 355 ✅ +   57  151 💤 ±  0  1 ❌  - 2 
22 097 runs   - 1 408  21 710 ✅  - 1 285  386 💤  - 119  1 ❌  - 4 

For more details on these failures, see this check.

Results for commit 8e0452b. ± Comparison against base commit 7572bd4.

This pull request removes 7 and adds 62 tests. Note that renamed tests count towards both.
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.MultipleEqualElementsTreeViewerTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.TreeViewerColumnTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.TreeViewerTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.TreeViewerWithLimitCompatibilityTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.VirtualLazyTreeViewerTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.VirtualTreeViewerTest ‑ testFilterExpanded
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChild
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildDeeperDownPath
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildFromRoot
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildFromRootWithSensibleTrivialPath
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildInfiniteExpand
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildManualDisable
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildSmallerThanAutoExpandDepth
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testAutoExpandOnSingleChildThroughEvent
org.eclipse.jface.tests.viewers.CheckboxTreeViewerTest ‑ testSetAutoExpandOnSingleChildLevels
org.eclipse.jface.tests.viewers.MultipleEqualElementsTreeViewerTest ‑ testAutoExpandOnSingleChild
…

♻️ This comment has been updated with latest results.

@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch from edc9dd8 to 82fb58e Compare August 29, 2023 11:04
@Wittmaxi
Copy link
Author

Good catch, I changed my proposal to be more consistent with the existing behaviour @merks

@merks
Copy link
Contributor

merks commented Aug 29, 2023

I think this will be a cool feature!

@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch 4 times, most recently from ade0788 to 4f7651d Compare August 30, 2023 09:52
@Wittmaxi Wittmaxi marked this pull request as ready for review August 30, 2023 09:53
@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch 2 times, most recently from 2486211 to 1a49af7 Compare August 30, 2023 15:16
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the proposed change in general, still I have two major remarks (and some fine-grained ones made as code comments):

Functionality:
The changes to AbstractTreeViewer are currently API breaking: the new methods for setting the auto expansion (such as setAutoExpandTrivialPathsLevel) claim that when setting the expansion level, the instance will perform auto-expansion. The current implementation does, however, not guarantee that but relies on implementations of that class (such as TreeViewer) to provide the according behavior. I would propose to change the implementation such that AbstractTreeViewer already provides the claimed functionality by changing the according methods handling changes of the expansion state of a node and adding a listener that reacts to expansion state changes (like now done in the TreeViewer.

Naming:
I am not in favor of the current naming, as I don't think that there is a common understanding of what "trivial paths" are. This requires every method related to the functionality to explain what is meant. I would suggest to change the naming to something more self-explaning. This could be something like autoExpandOnSingleChild or the like (better proposals are welcome).

Comment on lines 166 to 168
setExpanded((Item) w, true);
createChildren(w);
return getChildren(w);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to reimplement the essential expansion functionality as already implemented in setExpandedState. Is there a necessity for this additional method?

if (expanded) {
createChildren(item);
if (expandAndCreateChildren(item).length == 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect the additional extension to happen after the "ordinary" extension has happended completely, i.e., after creating childen and setting the expand state has happened. First performing the recusive extension and then setting the expand state does not look to be the right order to me.

Copy link
Author

@Wittmaxi Wittmaxi Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the order in which both operations happen, I suspect that this does not correctly reflect what you actually intended by your comment. If that is the case, can you please specify what exactly you have in mind?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recursive expansion should happen by completely expanding an items before starting the expansion of a child. The state change of an auto expansion should be equal to manually extending levels one-by-one, i.e., before expanding a child, the parent expansion should be finished in terms of creating all its children, settings it expanded state (and maybe further state changes I am not aware of). Currently, the logic is quite convoluted, as this method sets the expanded state and then calls expandAndCreateChildren, which sets the state again.

Copy link
Author

@Wittmaxi Wittmaxi Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (item instanceof Item) {
	setExpanded((Item) item, expanded);
	if (expanded) {
		if (expandAndCreateChildren(item).length == 1) {
			expandPathOfSingleChildren(getChildren(item)[0], getAutoExpandOnSingleChildLevel());
		}
	}
}

What currently happens:

  1. set the expanded state (calls the winapi, doesn't add the children)
    if the expanded state is expanded:
  2. set the expanded state again (doesn't do anything new)
  3. create the children
  4. return the amount of children
  5. check: does my parent only have one child? If so, start the recursive routine that expands trivial paths and keeps track of how many levels it has recursed

Steps 1-4 expand the node and do not yet add any behaviour. Step 5 is the actual expansion of paths of singular children - just as you had described in your comment, I first perform the existing behaviour and then simulatie "clicking" through the children to consecutively open them.
From what I understood in your comment, your issue boils down to 1) and 2) being duplicates of eachother. A rather obvious solution would be to check for the expanded state so that I only set it once

if (!expanded) {
  setExpanded((Item) item, false);
} else {
  if (expandAndCreateChildren(item).length == 1) {
    expandPathOfSingleChildren(getChildren(item)[0], getAutoExpandOnSingleChildLevel());
  }
}

I am a bit hesitant about making this change as it introduces additional control flow and complexity. However, setExpanded performs a call to winapi (... and probably to cocoa and gtk too), hence I can understand why we would want to limit it's use.

@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch from 1a49af7 to c049882 Compare September 13, 2023 10:15
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you were able to move functionality completely into AbstractTreeViewer. That makes my previous concerns with respect to API compatibility obsolete.

Please consider my unanswered comment from last review.

if (expanded) {
createChildren(item);
if (expandAndCreateChildren(item).length == 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recursive expansion should happen by completely expanding an items before starting the expansion of a child. The state change of an auto expansion should be equal to manually extending levels one-by-one, i.e., before expanding a child, the parent expansion should be finished in terms of creating all its children, settings it expanded state (and maybe further state changes I am not aware of). Currently, the logic is quite convoluted, as this method sets the expanded state and then calls expandAndCreateChildren, which sets the state again.

@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch from c049882 to ced49bd Compare September 18, 2023 08:07
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have taken a deeper look into the overall design of the expand mechanism in the AbstractTreeViewer. I would like to make some proposals to improve this PR by reusing existing functionality and the insights behind.

  1. internalExpandToLevel already has a sophisticated implementation for expanding a certain amount of levels, including some performance improvements. I would propose to let the recursive expansion when only having a single child use this functionality by generalizing it to some kind of internalConditionalExpandToLevel that additionally accepts a shouldExpand function (Widget -> boolean) that is used to calculate whether the next recursion of expansion shall be performed. Then the existing internalExpandToLevel method can use this method with a function always returning true, while the expand on single child functionality will pass a condition based on the number of childs of the widget.
  2. The expandToLevel(...) methods disable the redraw of the tree viewer while expanding (to avoid flickering). That may not be a severe problem with recursive expansion when only having one child, as this should be quite fast, still the functionality is already there and I would thus propose to reuse it. You could, for example, encapsulate the transaction that ensures proper disablement and re-enablement of redraw into a functional that can be used by both the existing expandToLevel as well as the expandOnSingleChild. It could look something like this:
private void excuteWithRedrawDisabled(Runnable toExecute) {
	Control control = getControl();
	try {
		control.setRedraw(false);
		toExecute.run();
	} finally {
		control.setRedraw(true);
	}
}

Wittmaxi pushed a commit to Wittmaxi/eclipse.platform.ui that referenced this pull request Oct 2, 2023
After Review by @HeikoKlare in eclipse-platform#1072, this method
allows for other methods to perform costly operations on
an undrawn tree without manually dis- and re-enabling the tree.
@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch from ced49bd to 87a47e2 Compare October 2, 2023 11:36
HeikoKlare pushed a commit to Wittmaxi/eclipse.platform.ui that referenced this pull request Oct 2, 2023
After Review by @HeikoKlare in eclipse-platform#1072, this method
allows for other methods to perform costly operations on
an undrawn tree without manually dis- and re-enabling the tree.
@HeikoKlare HeikoKlare force-pushed the MW_treeviewer_autoexpand branch from 87a47e2 to 5c61e61 Compare October 2, 2023 12:46
Wittmaxi pushed a commit to Wittmaxi/eclipse.platform.ui that referenced this pull request Oct 2, 2023
After Review by @HeikoKlare in eclipse-platform#1072, this method
allows for other methods to perform costly operations on
an undrawn tree without manually dis- and re-enabling the tree.
@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch from 5c61e61 to 8af421c Compare October 2, 2023 13:05
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that the refactoring of the temporary redraw disablement would be rather local and thus proposed to do it in this PR or extract it to another that is merged before. Since a reasonable refactoring will probably be a bit larger (see #1191) and should not prevent this PR from being merged, So feel free to change the code back to the original sequence of manual setRedraw(false) and setRedraw(true), which will then be refactored together with all other analogous places in the code in an according refactoring. Sorry for the back and forth, but I was not aware that the issue is a more general one when proposing the refactoring.

@Wittmaxi Wittmaxi force-pushed the MW_treeviewer_autoexpand branch 2 times, most recently from 99adede to 393e4ce Compare October 12, 2023 09:22
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have two major remarks (and requests for change) and some minor detailed comments:

  1. The current changes break public API (setExpandedState). This needs to be adapted.
  2. The tests should cover all different usage scenarios of the different methods. In particular, they should cover the different ways in which auto-expansion can happen, i.e., not only via setExpandedState but also via SWT events. I'd propose to relate the tests to the different added or changed methods. For example, there should also be trivial tests, such as get...Level returning what has been set by set...Level to easy debugging in case only the setter is broken, as currently the tests for the expand behavior would break although it's state may simply not be represented as expected after calling the setter.

@HeikoKlare HeikoKlare force-pushed the MW_treeviewer_autoexpand branch 3 times, most recently from 924e16b to f1f2c47 Compare January 29, 2024 07:25
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes work and look good now.

I propose to target the merge for 2024-06 M1. The change affects the TreeViewer as a rather central component, so I would propose to not risk a potentially undetected regression now that we are already quite late in 2024-03 development.

@HeikoKlare HeikoKlare force-pushed the MW_treeviewer_autoexpand branch from f1f2c47 to f02caaa Compare March 5, 2024 12:27
@HeikoKlare HeikoKlare changed the title TreeViewer: AutoExpandTrivialPaths TreeViewer: auto expansion for elements with single children Mar 5, 2024
@HeikoKlare HeikoKlare force-pushed the MW_treeviewer_autoexpand branch 8 times, most recently from 0eab3bd to c4040b2 Compare March 7, 2024 15:28
Maximilian Wittmer and others added 4 commits March 8, 2024 13:45
This commit addresses the need to automatically expand paths which
consist of chained singular nodes, eg:

com.wittmaxi.plugin
 └─src
    └─org.foo.com
       └─Bar.java

It introduces two new methods to the API of TreeViewer

-setAutoExpandOnSingleChildLevel
-getAutoExpandOnSingleChildLevel

Also includes a version bump for AbstractTreeViewer Autoexpand
Tests for virtual lazy tree viewers that access the data of a tree items
have been disabled because of some bug in according Mac implementation.
This also disables a test case for the auto-expand on single child
functionality that relies on accessing the item data.

Also removes unused API problem filters.
@HeikoKlare HeikoKlare force-pushed the MW_treeviewer_autoexpand branch from c4040b2 to 8e0452b Compare March 8, 2024 12:45
@HeikoKlare
Copy link
Contributor

Failing test is pre-existing and already documented: #1005.

@HeikoKlare HeikoKlare merged commit 5bd3301 into eclipse-platform:master Mar 8, 2024
14 of 16 checks passed
HeikoKlare added a commit to HeikoKlare/www.eclipse.org-eclipse that referenced this pull request May 23, 2024
HeikoKlare added a commit to HeikoKlare/www.eclipse.org-eclipse that referenced this pull request May 23, 2024
HeikoKlare added a commit to HeikoKlare/www.eclipse.org-eclipse that referenced this pull request May 27, 2024
HeikoKlare added a commit to eclipse-platform/www.eclipse.org-eclipse that referenced this pull request May 27, 2024
HeikoKlare added a commit to HeikoKlare/eclipse.platform.ui that referenced this pull request Jun 5, 2024
The API filter added for the AbstractTreeViewer for the 4.32 release
became obsolete when moving to the 4.33 stream. This change removes the
now obsolete filter.

See eclipse-platform#1072
HeikoKlare added a commit that referenced this pull request Jun 6, 2024
The API filter added for the AbstractTreeViewer for the 4.32 release
became obsolete when moving to the 4.33 stream. This change removes the
now obsolete filter.

See #1072
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants