11package jadx .gui .treemodel ;
22
3- import java .util .ArrayList ;
3+ import java .util .Collections ;
44import java .util .Comparator ;
55import java .util .List ;
66import java .util .Map ;
1414import jadx .api .ICodeInfo ;
1515import jadx .api .ICodeWriter ;
1616import jadx .api .ResourceFile ;
17- import jadx .api .ResourceFileContent ;
1817import jadx .api .ResourceType ;
1918import jadx .api .ResourcesLoader ;
2019import jadx .api .impl .SimpleCodeInfo ;
20+ import jadx .core .utils .ListUtils ;
2121import jadx .core .utils .Utils ;
2222import jadx .core .xmlgen .ResContainer ;
2323import jadx .gui .ui .TabbedPane ;
2626import jadx .gui .ui .panel .ImagePanel ;
2727import jadx .gui .utils .NLS ;
2828import jadx .gui .utils .UiUtils ;
29+ import jadx .gui .utils .res .ResTableHelper ;
2930
3031public class JResource extends JLoadableNode {
3132 private static final long serialVersionUID = -201018424302612434L ;
@@ -41,6 +42,10 @@ public class JResource extends JLoadableNode {
4142 private static final ImageIcon JAVA_ICON = UiUtils .openSvgIcon ("nodes/java" );
4243 private static final ImageIcon UNKNOWN_ICON = UiUtils .openSvgIcon ("nodes/unknown" );
4344
45+ public static final Comparator <JResource > RESOURCES_COMPARATOR =
46+ Comparator .<JResource >comparingInt (r -> r .type .ordinal ())
47+ .thenComparing (JResource ::getName , String .CASE_INSENSITIVE_ORDER );
48+
4449 public enum JResType {
4550 ROOT ,
4651 DIR ,
@@ -49,11 +54,11 @@ public enum JResType {
4954
5055 private final transient String name ;
5156 private final transient String shortName ;
52- private final transient List <JResource > files = new ArrayList <>(1 );
5357 private final transient JResType type ;
5458 private final transient ResourceFile resFile ;
5559
56- private transient boolean loaded ;
60+ private transient volatile boolean loaded ;
61+ private transient List <JResource > subNodes = Collections .emptyList ();
5762 private transient ICodeInfo content ;
5863
5964 public JResource (ResourceFile resFile , String name , JResType type ) {
@@ -69,22 +74,16 @@ public JResource(ResourceFile resFile, String name, String shortName, JResType t
6974 }
7075
7176 public final void update () {
72- if (files .isEmpty ()) {
77+ removeAllChildren ();
78+ if (Utils .isEmpty (subNodes )) {
7379 if (type == JResType .DIR || type == JResType .ROOT
7480 || resFile .getType () == ResourceType .ARSC ) {
7581 // fake leaf to force show expand button
7682 // real sub nodes will load on expand in loadNode() method
7783 add (new TextNode (NLS .str ("tree.loading" )));
7884 }
7985 } else {
80- removeAllChildren ();
81-
82- Comparator <JResource > typeComparator = Comparator .comparingInt (r -> r .type .ordinal ());
83- Comparator <JResource > nameComparator = Comparator .comparing (JResource ::getName , String .CASE_INSENSITIVE_ORDER );
84-
85- files .sort (typeComparator .thenComparing (nameComparator ));
86-
87- for (JResource res : files ) {
86+ for (JResource res : subNodes ) {
8887 res .update ();
8988 add (res );
9089 }
@@ -106,8 +105,23 @@ public JResType getType() {
106105 return type ;
107106 }
108107
109- public List <JResource > getFiles () {
110- return files ;
108+ public List <JResource > getSubNodes () {
109+ return subNodes ;
110+ }
111+
112+ public void addSubNode (JResource node ) {
113+ subNodes = ListUtils .safeAdd (subNodes , node );
114+ }
115+
116+ public void sortSubNodes () {
117+ sortResNodes (subNodes );
118+ }
119+
120+ private static void sortResNodes (List <JResource > nodes ) {
121+ if (Utils .notEmpty (nodes )) {
122+ nodes .forEach (JResource ::sortSubNodes );
123+ nodes .sort (RESOURCES_COMPARATOR );
124+ }
111125 }
112126
113127 @ Override
@@ -145,9 +159,9 @@ private ICodeInfo loadContent() {
145159 }
146160 if (rc .getDataType () == ResContainer .DataType .RES_TABLE ) {
147161 ICodeInfo codeInfo = loadCurrentSingleRes (rc );
148- for ( ResContainer subFile : rc . getSubFiles ()) {
149- loadSubNodes ( this , subFile , 1 );
150- }
162+ List < JResource > nodes = ResTableHelper . buildTree ( rc );
163+ sortResNodes ( nodes );
164+ subNodes = nodes ;
151165 return codeInfo ;
152166 }
153167 // single node
@@ -178,47 +192,6 @@ private ICodeInfo loadCurrentSingleRes(ResContainer rc) {
178192 }
179193 }
180194
181- private void loadSubNodes (JResource root , ResContainer rc , int depth ) {
182- String resName = rc .getName ();
183- String [] path = resName .split ("/" );
184- String resShortName = path .length == 0 ? resName : path [path .length - 1 ];
185- ICodeInfo code = rc .getText ();
186- ResourceFileContent fileContent = new ResourceFileContent (resShortName , ResourceType .XML , code );
187- addPath (path , root , new JResource (fileContent , resName , resShortName , JResType .FILE ));
188-
189- for (ResContainer subFile : rc .getSubFiles ()) {
190- loadSubNodes (root , subFile , depth + 1 );
191- }
192- }
193-
194- private static void addPath (String [] path , JResource root , JResource jResource ) {
195- if (path .length == 1 ) {
196- root .getFiles ().add (jResource );
197- return ;
198- }
199- JResource currentRoot = root ;
200- int last = path .length - 1 ;
201- for (int i = 0 ; i <= last ; i ++) {
202- String f = path [i ];
203- if (i == last ) {
204- currentRoot .getFiles ().add (jResource );
205- } else {
206- currentRoot = getResDir (currentRoot , f );
207- }
208- }
209- }
210-
211- private static JResource getResDir (JResource root , String dirName ) {
212- for (JResource file : root .getFiles ()) {
213- if (file .getName ().equals (dirName )) {
214- return file ;
215- }
216- }
217- JResource resDir = new JResource (null , dirName , JResType .DIR );
218- root .getFiles ().add (resDir );
219- return resDir ;
220- }
221-
222195 @ Override
223196 public String getSyntaxName () {
224197 if (resFile == null ) {
0 commit comments