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

Add support for a method of expanding/collapsing all tree nodes from a given node down #1644

Merged
merged 18 commits into from
Jan 30, 2023

Conversation

davep
Copy link
Contributor

@davep davep commented Jan 23, 2023

Adds optional expand_all, collapse_all and toggle_all parameters to the expand, collapse and toggle methods of TreeNode. In doing so I move the bulk of the work of those methods inside "private" methods that do the setting of the expanded status (and in turn calling on any children to do the same) without ever invalidating the display of the owning Tree. The "public" methods then simply call on those "private" methods and then invalidate the Tree (the intention being that there's no need to get the tree to redraw until after all the nodes have done their thing_.

See #1430.

This commit moves the bulk of the work of each action into an internal
method that does everything *apart* from invalidating the tree. The idea
being that all of the expanded states get updated, all of the update counts
get updated, and then finally one single tree invalidation takes place (the
latter taking place in the public method, which calls the related internal
method).

See Textualize#1430.
@davep davep added the enhancement New feature or request label Jan 23, 2023
@davep davep self-assigned this Jan 23, 2023
@davep davep linked an issue Jan 23, 2023 that may be closed by this pull request
davep added 6 commits January 23, 2023 19:57
It might seem excessive for just a single argument, but I feel it's
worthwhile doing it here. It's a single boolean parameter on each of the
methods that, left bare, will always end up reading badly. Consider:

    tree.toggle( True )

vs:

    tree.toggle( toggle_all=True )

the former looks awkward at best and ugly at worst; toggle True? What does
that even mean? The latter, while a touch more verbose, makes it really
clear what's going on.

Trying this on for size.
No need to set the keyword to True when I can just pass the parameter's
value in anyway. This reads a bit nicer.
@davep davep marked this pull request as ready for review January 23, 2023 21:29
This got added while I was experimenting with something earlier, and I
forgot to remove it and didn't notice it slip in with a commit.
Copy link
Contributor

@rodrigogiraoserrao rodrigogiraoserrao left a comment

Choose a reason for hiding this comment

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

The changes look good to me.
I have two questions, though:

  1. I'd expect the collapse_all default value to also be False so that, by default, collapsing a node will not mess with the collapsed/expanded state of children. E.g., like VS Code does in the built-in file explorer.
  2. What's the self._tree._invalidate()? Is there a "local" version of that that we can call when we only change the state of a single node, i.e. when the recursive calls are skipped?

@davep
Copy link
Contributor Author

davep commented Jan 24, 2023

  1. I'd expect the collapse_all default value to also be False so that, by default, collapsing a node will not mess with the collapsed/expanded state of children. E.g., like VS Code does in the built-in file explorer.

Not sure that's a question. :-P

But, yes, you're right, that (and toggle) is a typo, so good catch.

  1. What's the self._tree._invalidate()? Is there a "local" version of that that we can call when we only change the state of a single node, i.e. when the recursive calls are skipped?

I'm not sure I understand this question though, could you elaborate?

@rodrigogiraoserrao
Copy link
Contributor

Not sure that's a question. :-P

It's not, I started typing with one formulation in mind and ended up writing something different 😆

I'm not sure I understand this question though, could you elaborate?

I'm assuming the call to invalidate is to invalidate some cache or to flag the need for redrawing the tree, or something of the sorts. When there are no recursive updates, can you not make a similar call that just says "hey, invalidate just this node"? Do you need to have the same invalidate call regardless of whether you updated one node or 1000 nodes?

@darrenburns
Copy link
Member

The "toggle children" behaviour seems weird to me - if I have some children open those will be closed, and the children that are closed will be open?

Would it make more sense to just toggle the parent, then walk the children and make sure their state matches that of the parent?

@davep
Copy link
Contributor Author

davep commented Jan 24, 2023

When there are no recursive updates, can you not make a similar call that just says "hey, invalidate just this node"? Do you need to have the same invalidate call regardless of whether you updated one node or 1000 nodes?

Sorry, I'm still not sure I'm following the question. self._tree._invalidate invalidates the tree, not the node, so it only needs to be done the once no matter if you change the expanded state of a single node or 1000s of nodes.

Somehow I'd managed to typo them as True when they obviously should be False
to maintain backward-compatibility (and generally this is the only sensible
default).
@davep davep marked this pull request as draft January 24, 2023 10:56
@davep
Copy link
Contributor Author

davep commented Jan 24, 2023

Taking this back to a draft PR for a wee while as I can see there's questions about user experience and expectation to address.

See Textualize#1644 (comment)
where Darren raises the excellent point that while the "technically correct"
approach that I had was... well, technically correct I guess (it toggled all
the nodes from the target node down), it didn't have what was likely the
desired effect.

So this commit does away with the previous logic for doing the toggle and
instead simply calls on expand or collapse depending on the state of the
source node.
@davep
Copy link
Contributor Author

davep commented Jan 24, 2023

Right, a365836 takes the toggle from being "technically correct" to, erm... actually useful? 😄

@davep davep marked this pull request as ready for review January 24, 2023 11:11
Copy link
Contributor

@rodrigogiraoserrao rodrigogiraoserrao left a comment

Choose a reason for hiding this comment

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

Nice adding the * to force the x_all parameters to be keyword only.

See Textualize#1644 (comment)
-- not exactly my preference but it's been decided it makes for a nicer
interface.
@davep
Copy link
Contributor Author

davep commented Jan 25, 2023

Todo: we've decided to break these out into different methods; expand vs expand_all, etc.

davep added 3 commits January 25, 2023 20:39
While descriptive keywords tend to be a preference within the Textual
codebase for many things, this was one of those times where a developer's
code using the library was likely going to read better if there's a switch
to using dedicated methods; this approach means we can just go with "all"
rather than "{action}_all" without needing to shadow a Python builtin.

This also does mirror mount/mount_all too.
Nowt optional about the new methods!
Copy link
Collaborator

@willmcgugan willmcgugan left a comment

Choose a reason for hiding this comment

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

Looks great. Could use tests.

@davep
Copy link
Contributor Author

davep commented Jan 27, 2023

Cool, now we're happy with this I'll add them.

@davep
Copy link
Contributor Author

davep commented Jan 27, 2023

Tests for all the TreeNode expand/collapse/toggle methods now added.

@davep davep requested a review from willmcgugan January 27, 2023 13:31
@willmcgugan willmcgugan merged commit 475cd4f into Textualize:main Jan 30, 2023
@davep davep deleted the tree-deeply branch January 31, 2023 10:41
davep added a commit to davep/textual that referenced this pull request May 10, 2023
Until now the Tree.NodeExpanded and Tree.NodeCollapsed messages were only
sent out when changes were made to the tree by user interaction. This meant
that if any changes were made with the TreeNode expand, expand_all,
collapse, collapse_all, toggle or toggle_all API calls no messages would be
sent.

This PR corrects this.

The work here is, in part, required for Textualize#2456 (DirectoryTree lazy-loads
directory information on node expansion so if someone is expanding nodes
under code control the DirectoryTree never gets to know that it should load
a directory's content) and will build on Textualize#1644, essentially adding a missing
aspect to the latter PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Tree] Provide some sort of expand/collapse_all facility for TreeNode
4 participants