Skip to content

feat(ui): add class tree filter - #2941

Merged
skylot merged 5 commits into
skylot:masterfrom
tim21-f0:class-tree-filter
Sep 12, 2026
Merged

skylot merged 5 commits into
skylot:masterfrom
tim21-f0:class-tree-filter

Conversation

@tim21-f0

@tim21-f0 tim21-f0 commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This change augments the existing resource tree pane on the left with a filter box at the top. Typing a string into the box will restrict the display of the tree to classes that match the given string, and fully expand the tree to show all such classes. Additionally there is a 'clear filter button' to the right which when clicked clears the filter and resets the tree to have no expanded results.

There are some caveats:

  • Only top level classes are supported (no inner classes)
  • Filters matching a lot of results can affect UI performance so there is a new Preference in the Other section to cap the number of filtered results that will be expanded named Class tree filter expansion limit

Design

A new FilterableTreeModel class subclasses DefaultTreeModel which is used as the tree model in the MainWindow. When the user types or removes a character from the filter box a task delayed by 400ms is created. If a new task is created any previous created task will be cancelled to ensure that the filter logic only fires once the user has stopped typing for 400ms. This task computes the filtered tree nodes in a background task which then issues a nodeStructuredChanged event on the tree model. Subsequently, processing this event in the UI thread expands all of the filtered tree nodes. Access to the FilterableTreeModel nodes, filtered nodes and filter are protected by a ReentrantLock. Testing thus far has not shown any drastic performance hit with Class tree filter expansion limit set to 500 but this can be reduced.

@tim21-f0
tim21-f0 marked this pull request as ready for review August 26, 2026 09:05
@skylot

skylot commented Aug 30, 2026

Copy link
Copy Markdown
Owner

I commit several changes to this PR:

  1. Perform filtering only once and without recursion (using exist method for node traversing), results saved as HashSet holding all nodes needs to show, so other methods build tree using only that set.
  2. Change filtering only for shown short name, because keeping classes matching in package name feels not right. We might add an option to keep packages. Feel free to suggest other options.
  3. Use rxjava approach to debounce user input into filter field (same as in search dialog)
  4. Reduce default filtered expand limit to 100, because for me, UI stutter slightly for big APKs.
  5. Use FlatLaf clear text button, and apply field outline to show search state (error if nothing found, warn if auto expand limit reached).

@tim21-f0 and @jpstotz it will be nice if someone test and maybe review this PR, I may miss something 🙂

@jpstotz

jpstotz commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

From a user perspective the tree filter is really nice. I think most users will use it instead of the Class filter from the search dialog. And searching for resources like AndroidManifest is also easy and fast.

I have tested it using a very large APK file with next to 40k entries and experienced no speed issues.

I only see some minor improvements that could be implemented:

  1. At the moment the "Class tree filter expansion limit" is invisible to the user. When a filter is set but capped then this should be shown to the user in some way. The simplest way would be a tooltip may be on the tree filter edit field itself or the root node of the tree? Or may be changing the node text of the root node like "xyz.apk - filtered to x of y entries"

  2. Placing the "Class tree filter expansion limit" in section "Other" isn't easy to find. May be we should add a section for the main tree view. Into that section also the "Excluded packages" settings would fit, as from a user perspective it is similar to the tree filter.

  3. When the focus is on the Tree filter edit field and the user presses ESC that may be we should remove the filter? That would allow to do this fast via keyboard.

@skylot

skylot commented Sep 5, 2026

Copy link
Copy Markdown
Owner

I commit a lazy expand only for visible nodes (updates on scroll).
Such approach don't require any limit settings and I removed it 😄
I will continue testing this through.

When the focus is on the Tree filter edit field and the user presses ESC that may be we should remove the filter?

Sure, nice suggestion 👍
Actually, there are a lot of possible improvements to allow users to navigate and use jadx-gui only with keyboard.

@jpstotz

jpstotz commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

@skylot The lazy implementation seem to work in general but if there are too many results I managed to freeze Jadx-gui UI for multiple minutes. I loaded an older Snapchat version which has 8 dex files and a lot of resources and then searched for a.
Then I scrolled down to the end of the list and when I reached it the UI was frozen for 1-2 minutes.

May be this was caused by the classes below the defpackage node. According to the old search dialog there are ~67k classes that contains a in that package...

@skylot

skylot commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Another batch of changes:

  • use Rx to drop scroll events if user scrolls too fast and expands can't keep up.
  • cache children for one last node: getChild method very often iterate over all children after call to getChildCount and even hash set struggle to filter too many nodes (expand of 20K children took 3 seconds for me 😢), so save these children to list for later fast return by index.
  • clear filter field on escape key

@jpstotz thanks for help in testing 👍
Hope this is last update 🤣

@skylot
skylot merged commit f0a1e9e into skylot:master Sep 12, 2026
2 checks passed
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.

3 participants