Codebase list jd-gui / 0af4a626-0b34-4685-a8a4-c18e8bd66f2d/upstream
Import upstream version 1.6.6 Kali Janitor 3 years ago
336 changed file(s) with 25511 addition(s) and 765 deletion(s). Raw diff Collapse all Expand all
0 # Set the default behavior, in case people don't have core.autocrlf set.
1 * text=auto
2
3 # Declare OSX files that will always have LF line endings on checkout.
4 Info.plist text eol=lf
5
6 # Declare script files that will always have LF line endings on checkout.
7 *.sh text eol=lf
8
9 # Declare script files that will always have CR/LF line endings on checkout.
10 *.bat text eol=crlf
11
12 # Denote all files that are truly binary and should not be modified.
13 *.png binary
14 *.jpg binary
15 *.gif binary
16 *.icns binary
0 # Java
1 *.class
2
3 # JD
4 debug*
5
6 # JD-GUI
7 src-generated/
8 jd-gui.cfg
9
10 # Idea
11 .idea/
12 out/
13 *.ipr
14 *.iml
15 *.iws
16
17 # Eclipse
18 .settings/
19 classes/
20 .classpath
21 .project
22
23 # Mac
24 .DS_Store
25
26 #Windows
27 Thumbs.db
28
29 # Maven
30 log/
31 target/
32
33 # Gradle
34 .gradle/
35 build/
36 !gradle/wrapper/*
37
38 # WinMerge
39 *.bak
+676
-676
LICENSE less more
0 GNU GENERAL PUBLIC LICENSE
1
2 Version 3, 29 June 2007
3
4 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5 Everyone is permitted to copy and distribute verbatim copies
6 of this license document, but changing it is not allowed.
7
8 Preamble
9
10 The GNU General Public License is a free, copyleft license for
11 software and other kinds of works.
12
13 The licenses for most software and other practical works are designed
14 to take away your freedom to share and change the works. By contrast,
15 the GNU General Public License is intended to guarantee your freedom to
16 share and change all versions of a program--to make sure it remains free
17 software for all its users. We, the Free Software Foundation, use the
18 GNU General Public License for most of our software; it applies also to
19 any other work released this way by its authors. You can apply it to
20 your programs, too.
21
22 When we speak of free software, we are referring to freedom, not
23 price. Our General Public Licenses are designed to make sure that you
24 have the freedom to distribute copies of free software (and charge for
25 them if you wish), that you receive source code or can get it if you
26 want it, that you can change the software or use pieces of it in new
27 free programs, and that you know you can do these things.
28
29 To protect your rights, we need to prevent others from denying you
30 these rights or asking you to surrender the rights. Therefore, you have
31 certain responsibilities if you distribute copies of the software, or if
32 you modify it: responsibilities to respect the freedom of others.
33
34 For example, if you distribute copies of such a program, whether
35 gratis or for a fee, you must pass on to the recipients the same
36 freedoms that you received. You must make sure that they, too, receive
37 or can get the source code. And you must show them these terms so they
38 know their rights.
39
40 Developers that use the GNU GPL protect your rights with two steps:
41 (1) assert copyright on the software, and (2) offer you this License
42 giving you legal permission to copy, distribute and/or modify it.
43
44 For the developers' and authors' protection, the GPL clearly explains
45 that there is no warranty for this free software. For both users' and
46 authors' sake, the GPL requires that modified versions be marked as
47 changed, so that their problems will not be attributed erroneously to
48 authors of previous versions.
49
50 Some devices are designed to deny users access to install or run
51 modified versions of the software inside them, although the manufacturer
52 can do so. This is fundamentally incompatible with the aim of
53 protecting users' freedom to change the software. The systematic
54 pattern of such abuse occurs in the area of products for individuals to
55 use, which is precisely where it is most unacceptable. Therefore, we
56 have designed this version of the GPL to prohibit the practice for those
57 products. If such problems arise substantially in other domains, we
58 stand ready to extend this provision to those domains in future versions
59 of the GPL, as needed to protect the freedom of users.
60
61 Finally, every program is threatened constantly by software patents.
62 States should not allow patents to restrict development and use of
63 software on general-purpose computers, but in those that do, we wish to
64 avoid the special danger that patents applied to a free program could
65 make it effectively proprietary. To prevent this, the GPL assures that
66 patents cannot be used to render the program non-free.
67
68 The precise terms and conditions for copying, distribution and
69 modification follow.
70
71 TERMS AND CONDITIONS
72
73 0. Definitions.
74
75 "This License" refers to version 3 of the GNU General Public License.
76
77 "Copyright" also means copyright-like laws that apply to other kinds of
78 works, such as semiconductor masks.
79
80 "The Program" refers to any copyrightable work licensed under this
81 License. Each licensee is addressed as "you". "Licensees" and
82 "recipients" may be individuals or organizations.
83
84 To "modify" a work means to copy from or adapt all or part of the work
85 in a fashion requiring copyright permission, other than the making of an
86 exact copy. The resulting work is called a "modified version" of the
87 earlier work or a work "based on" the earlier work.
88
89 A "covered work" means either the unmodified Program or a work based
90 on the Program.
91
92 To "propagate" a work means to do anything with it that, without
93 permission, would make you directly or secondarily liable for
94 infringement under applicable copyright law, except executing it on a
95 computer or modifying a private copy. Propagation includes copying,
96 distribution (with or without modification), making available to the
97 public, and in some countries other activities as well.
98
99 To "convey" a work means any kind of propagation that enables other
100 parties to make or receive copies. Mere interaction with a user through
101 a computer network, with no transfer of a copy, is not conveying.
102
103 An interactive user interface displays "Appropriate Legal Notices"
104 to the extent that it includes a convenient and prominently visible
105 feature that (1) displays an appropriate copyright notice, and (2)
106 tells the user that there is no warranty for the work (except to the
107 extent that warranties are provided), that licensees may convey the
108 work under this License, and how to view a copy of this License. If
109 the interface presents a list of user commands or options, such as a
110 menu, a prominent item in the list meets this criterion.
111
112 1. Source Code.
113
114 The "source code" for a work means the preferred form of the work
115 for making modifications to it. "Object code" means any non-source
116 form of a work.
117
118 A "Standard Interface" means an interface that either is an official
119 standard defined by a recognized standards body, or, in the case of
120 interfaces specified for a particular programming language, one that
121 is widely used among developers working in that language.
122
123 The "System Libraries" of an executable work include anything, other
124 than the work as a whole, that (a) is included in the normal form of
125 packaging a Major Component, but which is not part of that Major
126 Component, and (b) serves only to enable use of the work with that
127 Major Component, or to implement a Standard Interface for which an
128 implementation is available to the public in source code form. A
129 "Major Component", in this context, means a major essential component
130 (kernel, window system, and so on) of the specific operating system
131 (if any) on which the executable work runs, or a compiler used to
132 produce the work, or an object code interpreter used to run it.
133
134 The "Corresponding Source" for a work in object code form means all
135 the source code needed to generate, install, and (for an executable
136 work) run the object code and to modify the work, including scripts to
137 control those activities. However, it does not include the work's
138 System Libraries, or general-purpose tools or generally available free
139 programs which are used unmodified in performing those activities but
140 which are not part of the work. For example, Corresponding Source
141 includes interface definition files associated with source files for
142 the work, and the source code for shared libraries and dynamically
143 linked subprograms that the work is specifically designed to require,
144 such as by intimate data communication or control flow between those
145 subprograms and other parts of the work.
146
147 The Corresponding Source need not include anything that users
148 can regenerate automatically from other parts of the Corresponding
149 Source.
150
151 The Corresponding Source for a work in source code form is that
152 same work.
153
154 2. Basic Permissions.
155
156 All rights granted under this License are granted for the term of
157 copyright on the Program, and are irrevocable provided the stated
158 conditions are met. This License explicitly affirms your unlimited
159 permission to run the unmodified Program. The output from running a
160 covered work is covered by this License only if the output, given its
161 content, constitutes a covered work. This License acknowledges your
162 rights of fair use or other equivalent, as provided by copyright law.
163
164 You may make, run and propagate covered works that you do not
165 convey, without conditions so long as your license otherwise remains
166 in force. You may convey covered works to others for the sole purpose
167 of having them make modifications exclusively for you, or provide you
168 with facilities for running those works, provided that you comply with
169 the terms of this License in conveying all material for which you do
170 not control copyright. Those thus making or running the covered works
171 for you must do so exclusively on your behalf, under your direction
172 and control, on terms that prohibit them from making any copies of
173 your copyrighted material outside their relationship with you.
174
175 Conveying under any other circumstances is permitted solely under
176 the conditions stated below. Sublicensing is not allowed; section 10
177 makes it unnecessary.
178
179 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
181 No covered work shall be deemed part of an effective technological
182 measure under any applicable law fulfilling obligations under article
183 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 similar laws prohibiting or restricting circumvention of such
185 measures.
186
187 When you convey a covered work, you waive any legal power to forbid
188 circumvention of technological measures to the extent such circumvention
189 is effected by exercising rights under this License with respect to
190 the covered work, and you disclaim any intention to limit operation or
191 modification of the work as a means of enforcing, against the work's
192 users, your or third parties' legal rights to forbid circumvention of
193 technological measures.
194
195 4. Conveying Verbatim Copies.
196
197 You may convey verbatim copies of the Program's source code as you
198 receive it, in any medium, provided that you conspicuously and
199 appropriately publish on each copy an appropriate copyright notice;
200 keep intact all notices stating that this License and any
201 non-permissive terms added in accord with section 7 apply to the code;
202 keep intact all notices of the absence of any warranty; and give all
203 recipients a copy of this License along with the Program.
204
205 You may charge any price or no price for each copy that you convey,
206 and you may offer support or warranty protection for a fee.
207
208 5. Conveying Modified Source Versions.
209
210 You may convey a work based on the Program, or the modifications to
211 produce it from the Program, in the form of source code under the
212 terms of section 4, provided that you also meet all of these conditions:
213
214 a) The work must carry prominent notices stating that you modified
215 it, and giving a relevant date.
216
217 b) The work must carry prominent notices stating that it is
218 released under this License and any conditions added under section
219 7. This requirement modifies the requirement in section 4 to
220 "keep intact all notices".
221
222 c) You must license the entire work, as a whole, under this
223 License to anyone who comes into possession of a copy. This
224 License will therefore apply, along with any applicable section 7
225 additional terms, to the whole of the work, and all its parts,
226 regardless of how they are packaged. This License gives no
227 permission to license the work in any other way, but it does not
228 invalidate such permission if you have separately received it.
229
230 d) If the work has interactive user interfaces, each must display
231 Appropriate Legal Notices; however, if the Program has interactive
232 interfaces that do not display Appropriate Legal Notices, your
233 work need not make them do so.
234
235 A compilation of a covered work with other separate and independent
236 works, which are not by their nature extensions of the covered work,
237 and which are not combined with it such as to form a larger program,
238 in or on a volume of a storage or distribution medium, is called an
239 "aggregate" if the compilation and its resulting copyright are not
240 used to limit the access or legal rights of the compilation's users
241 beyond what the individual works permit. Inclusion of a covered work
242 in an aggregate does not cause this License to apply to the other
243 parts of the aggregate.
244
245 6. Conveying Non-Source Forms.
246
247 You may convey a covered work in object code form under the terms
248 of sections 4 and 5, provided that you also convey the
249 machine-readable Corresponding Source under the terms of this License,
250 in one of these ways:
251
252 a) Convey the object code in, or embodied in, a physical product
253 (including a physical distribution medium), accompanied by the
254 Corresponding Source fixed on a durable physical medium
255 customarily used for software interchange.
256
257 b) Convey the object code in, or embodied in, a physical product
258 (including a physical distribution medium), accompanied by a
259 written offer, valid for at least three years and valid for as
260 long as you offer spare parts or customer support for that product
261 model, to give anyone who possesses the object code either (1) a
262 copy of the Corresponding Source for all the software in the
263 product that is covered by this License, on a durable physical
264 medium customarily used for software interchange, for a price no
265 more than your reasonable cost of physically performing this
266 conveying of source, or (2) access to copy the
267 Corresponding Source from a network server at no charge.
268
269 c) Convey individual copies of the object code with a copy of the
270 written offer to provide the Corresponding Source. This
271 alternative is allowed only occasionally and noncommercially, and
272 only if you received the object code with such an offer, in accord
273 with subsection 6b.
274
275 d) Convey the object code by offering access from a designated
276 place (gratis or for a charge), and offer equivalent access to the
277 Corresponding Source in the same way through the same place at no
278 further charge. You need not require recipients to copy the
279 Corresponding Source along with the object code. If the place to
280 copy the object code is a network server, the Corresponding Source
281 may be on a different server (operated by you or a third party)
282 that supports equivalent copying facilities, provided you maintain
283 clear directions next to the object code saying where to find the
284 Corresponding Source. Regardless of what server hosts the
285 Corresponding Source, you remain obligated to ensure that it is
286 available for as long as needed to satisfy these requirements.
287
288 e) Convey the object code using peer-to-peer transmission, provided
289 you inform other peers where the object code and Corresponding
290 Source of the work are being offered to the general public at no
291 charge under subsection 6d.
292
293 A separable portion of the object code, whose source code is excluded
294 from the Corresponding Source as a System Library, need not be
295 included in conveying the object code work.
296
297 A "User Product" is either (1) a "consumer product", which means any
298 tangible personal property which is normally used for personal, family,
299 or household purposes, or (2) anything designed or sold for incorporation
300 into a dwelling. In determining whether a product is a consumer product,
301 doubtful cases shall be resolved in favor of coverage. For a particular
302 product received by a particular user, "normally used" refers to a
303 typical or common use of that class of product, regardless of the status
304 of the particular user or of the way in which the particular user
305 actually uses, or expects or is expected to use, the product. A product
306 is a consumer product regardless of whether the product has substantial
307 commercial, industrial or non-consumer uses, unless such uses represent
308 the only significant mode of use of the product.
309
310 "Installation Information" for a User Product means any methods,
311 procedures, authorization keys, or other information required to install
312 and execute modified versions of a covered work in that User Product from
313 a modified version of its Corresponding Source. The information must
314 suffice to ensure that the continued functioning of the modified object
315 code is in no case prevented or interfered with solely because
316 modification has been made.
317
318 If you convey an object code work under this section in, or with, or
319 specifically for use in, a User Product, and the conveying occurs as
320 part of a transaction in which the right of possession and use of the
321 User Product is transferred to the recipient in perpetuity or for a
322 fixed term (regardless of how the transaction is characterized), the
323 Corresponding Source conveyed under this section must be accompanied
324 by the Installation Information. But this requirement does not apply
325 if neither you nor any third party retains the ability to install
326 modified object code on the User Product (for example, the work has
327 been installed in ROM).
328
329 The requirement to provide Installation Information does not include a
330 requirement to continue to provide support service, warranty, or updates
331 for a work that has been modified or installed by the recipient, or for
332 the User Product in which it has been modified or installed. Access to a
333 network may be denied when the modification itself materially and
334 adversely affects the operation of the network or violates the rules and
335 protocols for communication across the network.
336
337 Corresponding Source conveyed, and Installation Information provided,
338 in accord with this section must be in a format that is publicly
339 documented (and with an implementation available to the public in
340 source code form), and must require no special password or key for
341 unpacking, reading or copying.
342
343 7. Additional Terms.
344
345 "Additional permissions" are terms that supplement the terms of this
346 License by making exceptions from one or more of its conditions.
347 Additional permissions that are applicable to the entire Program shall
348 be treated as though they were included in this License, to the extent
349 that they are valid under applicable law. If additional permissions
350 apply only to part of the Program, that part may be used separately
351 under those permissions, but the entire Program remains governed by
352 this License without regard to the additional permissions.
353
354 When you convey a copy of a covered work, you may at your option
355 remove any additional permissions from that copy, or from any part of
356 it. (Additional permissions may be written to require their own
357 removal in certain cases when you modify the work.) You may place
358 additional permissions on material, added by you to a covered work,
359 for which you have or can give appropriate copyright permission.
360
361 Notwithstanding any other provision of this License, for material you
362 add to a covered work, you may (if authorized by the copyright holders of
363 that material) supplement the terms of this License with terms:
364
365 a) Disclaiming warranty or limiting liability differently from the
366 terms of sections 15 and 16 of this License; or
367
368 b) Requiring preservation of specified reasonable legal notices or
369 author attributions in that material or in the Appropriate Legal
370 Notices displayed by works containing it; or
371
372 c) Prohibiting misrepresentation of the origin of that material, or
373 requiring that modified versions of such material be marked in
374 reasonable ways as different from the original version; or
375
376 d) Limiting the use for publicity purposes of names of licensors or
377 authors of the material; or
378
379 e) Declining to grant rights under trademark law for use of some
380 trade names, trademarks, or service marks; or
381
382 f) Requiring indemnification of licensors and authors of that
383 material by anyone who conveys the material (or modified versions of
384 it) with contractual assumptions of liability to the recipient, for
385 any liability that these contractual assumptions directly impose on
386 those licensors and authors.
387
388 All other non-permissive additional terms are considered "further
389 restrictions" within the meaning of section 10. If the Program as you
390 received it, or any part of it, contains a notice stating that it is
391 governed by this License along with a term that is a further
392 restriction, you may remove that term. If a license document contains
393 a further restriction but permits relicensing or conveying under this
394 License, you may add to a covered work material governed by the terms
395 of that license document, provided that the further restriction does
396 not survive such relicensing or conveying.
397
398 If you add terms to a covered work in accord with this section, you
399 must place, in the relevant source files, a statement of the
400 additional terms that apply to those files, or a notice indicating
401 where to find the applicable terms.
402
403 Additional terms, permissive or non-permissive, may be stated in the
404 form of a separately written license, or stated as exceptions;
405 the above requirements apply either way.
406
407 8. Termination.
408
409 You may not propagate or modify a covered work except as expressly
410 provided under this License. Any attempt otherwise to propagate or
411 modify it is void, and will automatically terminate your rights under
412 this License (including any patent licenses granted under the third
413 paragraph of section 11).
414
415 However, if you cease all violation of this License, then your
416 license from a particular copyright holder is reinstated (a)
417 provisionally, unless and until the copyright holder explicitly and
418 finally terminates your license, and (b) permanently, if the copyright
419 holder fails to notify you of the violation by some reasonable means
420 prior to 60 days after the cessation.
421
422 Moreover, your license from a particular copyright holder is
423 reinstated permanently if the copyright holder notifies you of the
424 violation by some reasonable means, this is the first time you have
425 received notice of violation of this License (for any work) from that
426 copyright holder, and you cure the violation prior to 30 days after
427 your receipt of the notice.
428
429 Termination of your rights under this section does not terminate the
430 licenses of parties who have received copies or rights from you under
431 this License. If your rights have been terminated and not permanently
432 reinstated, you do not qualify to receive new licenses for the same
433 material under section 10.
434
435 9. Acceptance Not Required for Having Copies.
436
437 You are not required to accept this License in order to receive or
438 run a copy of the Program. Ancillary propagation of a covered work
439 occurring solely as a consequence of using peer-to-peer transmission
440 to receive a copy likewise does not require acceptance. However,
441 nothing other than this License grants you permission to propagate or
442 modify any covered work. These actions infringe copyright if you do
443 not accept this License. Therefore, by modifying or propagating a
444 covered work, you indicate your acceptance of this License to do so.
445
446 10. Automatic Licensing of Downstream Recipients.
447
448 Each time you convey a covered work, the recipient automatically
449 receives a license from the original licensors, to run, modify and
450 propagate that work, subject to this License. You are not responsible
451 for enforcing compliance by third parties with this License.
452
453 An "entity transaction" is a transaction transferring control of an
454 organization, or substantially all assets of one, or subdividing an
455 organization, or merging organizations. If propagation of a covered
456 work results from an entity transaction, each party to that
457 transaction who receives a copy of the work also receives whatever
458 licenses to the work the party's predecessor in interest had or could
459 give under the previous paragraph, plus a right to possession of the
460 Corresponding Source of the work from the predecessor in interest, if
461 the predecessor has it or can get it with reasonable efforts.
462
463 You may not impose any further restrictions on the exercise of the
464 rights granted or affirmed under this License. For example, you may
465 not impose a license fee, royalty, or other charge for exercise of
466 rights granted under this License, and you may not initiate litigation
467 (including a cross-claim or counterclaim in a lawsuit) alleging that
468 any patent claim is infringed by making, using, selling, offering for
469 sale, or importing the Program or any portion of it.
470
471 11. Patents.
472
473 A "contributor" is a copyright holder who authorizes use under this
474 License of the Program or a work on which the Program is based. The
475 work thus licensed is called the contributor's "contributor version".
476
477 A contributor's "essential patent claims" are all patent claims
478 owned or controlled by the contributor, whether already acquired or
479 hereafter acquired, that would be infringed by some manner, permitted
480 by this License, of making, using, or selling its contributor version,
481 but do not include claims that would be infringed only as a
482 consequence of further modification of the contributor version. For
483 purposes of this definition, "control" includes the right to grant
484 patent sublicenses in a manner consistent with the requirements of
485 this License.
486
487 Each contributor grants you a non-exclusive, worldwide, royalty-free
488 patent license under the contributor's essential patent claims, to
489 make, use, sell, offer for sale, import and otherwise run, modify and
490 propagate the contents of its contributor version.
491
492 In the following three paragraphs, a "patent license" is any express
493 agreement or commitment, however denominated, not to enforce a patent
494 (such as an express permission to practice a patent or covenant not to
495 sue for patent infringement). To "grant" such a patent license to a
496 party means to make such an agreement or commitment not to enforce a
497 patent against the party.
498
499 If you convey a covered work, knowingly relying on a patent license,
500 and the Corresponding Source of the work is not available for anyone
501 to copy, free of charge and under the terms of this License, through a
502 publicly available network server or other readily accessible means,
503 then you must either (1) cause the Corresponding Source to be so
504 available, or (2) arrange to deprive yourself of the benefit of the
505 patent license for this particular work, or (3) arrange, in a manner
506 consistent with the requirements of this License, to extend the patent
507 license to downstream recipients. "Knowingly relying" means you have
508 actual knowledge that, but for the patent license, your conveying the
509 covered work in a country, or your recipient's use of the covered work
510 in a country, would infringe one or more identifiable patents in that
511 country that you have reason to believe are valid.
512
513 If, pursuant to or in connection with a single transaction or
514 arrangement, you convey, or propagate by procuring conveyance of, a
515 covered work, and grant a patent license to some of the parties
516 receiving the covered work authorizing them to use, propagate, modify
517 or convey a specific copy of the covered work, then the patent license
518 you grant is automatically extended to all recipients of the covered
519 work and works based on it.
520
521 A patent license is "discriminatory" if it does not include within
522 the scope of its coverage, prohibits the exercise of, or is
523 conditioned on the non-exercise of one or more of the rights that are
524 specifically granted under this License. You may not convey a covered
525 work if you are a party to an arrangement with a third party that is
526 in the business of distributing software, under which you make payment
527 to the third party based on the extent of your activity of conveying
528 the work, and under which the third party grants, to any of the
529 parties who would receive the covered work from you, a discriminatory
530 patent license (a) in connection with copies of the covered work
531 conveyed by you (or copies made from those copies), or (b) primarily
532 for and in connection with specific products or compilations that
533 contain the covered work, unless you entered into that arrangement,
534 or that patent license was granted, prior to 28 March 2007.
535
536 Nothing in this License shall be construed as excluding or limiting
537 any implied license or other defenses to infringement that may
538 otherwise be available to you under applicable patent law.
539
540 12. No Surrender of Others' Freedom.
541
542 If conditions are imposed on you (whether by court order, agreement or
543 otherwise) that contradict the conditions of this License, they do not
544 excuse you from the conditions of this License. If you cannot convey a
545 covered work so as to satisfy simultaneously your obligations under this
546 License and any other pertinent obligations, then as a consequence you may
547 not convey it at all. For example, if you agree to terms that obligate you
548 to collect a royalty for further conveying from those to whom you convey
549 the Program, the only way you could satisfy both those terms and this
550 License would be to refrain entirely from conveying the Program.
551
552 13. Use with the GNU Affero General Public License.
553
554 Notwithstanding any other provision of this License, you have
555 permission to link or combine any covered work with a work licensed
556 under version 3 of the GNU Affero General Public License into a single
557 combined work, and to convey the resulting work. The terms of this
558 License will continue to apply to the part which is the covered work,
559 but the special requirements of the GNU Affero General Public License,
560 section 13, concerning interaction through a network will apply to the
561 combination as such.
562
563 14. Revised Versions of this License.
564
565 The Free Software Foundation may publish revised and/or new versions of
566 the GNU General Public License from time to time. Such new versions will
567 be similar in spirit to the present version, but may differ in detail to
568 address new problems or concerns.
569
570 Each version is given a distinguishing version number. If the
571 Program specifies that a certain numbered version of the GNU General
572 Public License "or any later version" applies to it, you have the
573 option of following the terms and conditions either of that numbered
574 version or of any later version published by the Free Software
575 Foundation. If the Program does not specify a version number of the
576 GNU General Public License, you may choose any version ever published
577 by the Free Software Foundation.
578
579 If the Program specifies that a proxy can decide which future
580 versions of the GNU General Public License can be used, that proxy's
581 public statement of acceptance of a version permanently authorizes you
582 to choose that version for the Program.
583
584 Later license versions may give you additional or different
585 permissions. However, no additional obligations are imposed on any
586 author or copyright holder as a result of your choosing to follow a
587 later version.
588
589 15. Disclaimer of Warranty.
590
591 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
600 16. Limitation of Liability.
601
602 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 SUCH DAMAGES.
611
612 17. Interpretation of Sections 15 and 16.
613
614 If the disclaimer of warranty and limitation of liability provided
615 above cannot be given local legal effect according to their terms,
616 reviewing courts shall apply local law that most closely approximates
617 an absolute waiver of all civil liability in connection with the
618 Program, unless a warranty or assumption of liability accompanies a
619 copy of the Program in return for a fee.
620
621 END OF TERMS AND CONDITIONS
622
623 How to Apply These Terms to Your New Programs
624
625 If you develop a new program, and you want it to be of the greatest
626 possible use to the public, the best way to achieve this is to make it
627 free software which everyone can redistribute and change under these terms.
628
629 To do so, attach the following notices to the program. It is safest
630 to attach them to the start of each source file to most effectively
631 state the exclusion of warranty; and each file should have at least
632 the "copyright" line and a pointer to where the full notice is found.
633
634 JD-GUI, a standalone graphical utility that displays Java sources from
635 CLASS files
636 Copyright (C) 2008-2019 Emmanuel Dupuy
637
638 This program is free software: you can redistribute it and/or modify
639 it under the terms of the GNU General Public License as published by
640 the Free Software Foundation, either version 3 of the License, or
641 (at your option) any later version.
642
643 This program is distributed in the hope that it will be useful,
644 but WITHOUT ANY WARRANTY; without even the implied warranty of
645 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
646 GNU General Public License for more details.
647
648 You should have received a copy of the GNU General Public License
649 along with this program. If not, see <http://www.gnu.org/licenses/>.
650
651 Also add information on how to contact you by electronic and paper mail.
652
653 If the program does terminal interaction, make it output a short
654 notice like this when it starts in an interactive mode:
655
656 JD-GUI Copyright (C) 2008-2019 Emmanuel Dupuy
657 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
658 This is free software, and you are welcome to redistribute it
659 under certain conditions; type `show c' for details.
660
661 The hypothetical commands `show w' and `show c' should show the appropriate
662 parts of the General Public License. Of course, your program's commands
663 might be different; for a GUI interface, you would use an "about box".
664
665 You should also get your employer (if you work as a programmer) or school,
666 if any, to sign a "copyright disclaimer" for the program, if necessary.
667 For more information on this, and how to apply and follow the GNU GPL, see
668 <http://www.gnu.org/licenses/>.
669
670 The GNU General Public License does not permit incorporating your program
671 into proprietary programs. If your program is a subroutine library, you
672 may consider it more useful to permit linking proprietary applications with
673 the library. If this is what you want to do, use the GNU Lesser General
674 Public License instead of this License. But first, please read
675 <http://www.gnu.org/philosophy/why-not-lgpl.html>.
0 GNU GENERAL PUBLIC LICENSE
1
2 Version 3, 29 June 2007
3
4 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5 Everyone is permitted to copy and distribute verbatim copies
6 of this license document, but changing it is not allowed.
7
8 Preamble
9
10 The GNU General Public License is a free, copyleft license for
11 software and other kinds of works.
12
13 The licenses for most software and other practical works are designed
14 to take away your freedom to share and change the works. By contrast,
15 the GNU General Public License is intended to guarantee your freedom to
16 share and change all versions of a program--to make sure it remains free
17 software for all its users. We, the Free Software Foundation, use the
18 GNU General Public License for most of our software; it applies also to
19 any other work released this way by its authors. You can apply it to
20 your programs, too.
21
22 When we speak of free software, we are referring to freedom, not
23 price. Our General Public Licenses are designed to make sure that you
24 have the freedom to distribute copies of free software (and charge for
25 them if you wish), that you receive source code or can get it if you
26 want it, that you can change the software or use pieces of it in new
27 free programs, and that you know you can do these things.
28
29 To protect your rights, we need to prevent others from denying you
30 these rights or asking you to surrender the rights. Therefore, you have
31 certain responsibilities if you distribute copies of the software, or if
32 you modify it: responsibilities to respect the freedom of others.
33
34 For example, if you distribute copies of such a program, whether
35 gratis or for a fee, you must pass on to the recipients the same
36 freedoms that you received. You must make sure that they, too, receive
37 or can get the source code. And you must show them these terms so they
38 know their rights.
39
40 Developers that use the GNU GPL protect your rights with two steps:
41 (1) assert copyright on the software, and (2) offer you this License
42 giving you legal permission to copy, distribute and/or modify it.
43
44 For the developers' and authors' protection, the GPL clearly explains
45 that there is no warranty for this free software. For both users' and
46 authors' sake, the GPL requires that modified versions be marked as
47 changed, so that their problems will not be attributed erroneously to
48 authors of previous versions.
49
50 Some devices are designed to deny users access to install or run
51 modified versions of the software inside them, although the manufacturer
52 can do so. This is fundamentally incompatible with the aim of
53 protecting users' freedom to change the software. The systematic
54 pattern of such abuse occurs in the area of products for individuals to
55 use, which is precisely where it is most unacceptable. Therefore, we
56 have designed this version of the GPL to prohibit the practice for those
57 products. If such problems arise substantially in other domains, we
58 stand ready to extend this provision to those domains in future versions
59 of the GPL, as needed to protect the freedom of users.
60
61 Finally, every program is threatened constantly by software patents.
62 States should not allow patents to restrict development and use of
63 software on general-purpose computers, but in those that do, we wish to
64 avoid the special danger that patents applied to a free program could
65 make it effectively proprietary. To prevent this, the GPL assures that
66 patents cannot be used to render the program non-free.
67
68 The precise terms and conditions for copying, distribution and
69 modification follow.
70
71 TERMS AND CONDITIONS
72
73 0. Definitions.
74
75 "This License" refers to version 3 of the GNU General Public License.
76
77 "Copyright" also means copyright-like laws that apply to other kinds of
78 works, such as semiconductor masks.
79
80 "The Program" refers to any copyrightable work licensed under this
81 License. Each licensee is addressed as "you". "Licensees" and
82 "recipients" may be individuals or organizations.
83
84 To "modify" a work means to copy from or adapt all or part of the work
85 in a fashion requiring copyright permission, other than the making of an
86 exact copy. The resulting work is called a "modified version" of the
87 earlier work or a work "based on" the earlier work.
88
89 A "covered work" means either the unmodified Program or a work based
90 on the Program.
91
92 To "propagate" a work means to do anything with it that, without
93 permission, would make you directly or secondarily liable for
94 infringement under applicable copyright law, except executing it on a
95 computer or modifying a private copy. Propagation includes copying,
96 distribution (with or without modification), making available to the
97 public, and in some countries other activities as well.
98
99 To "convey" a work means any kind of propagation that enables other
100 parties to make or receive copies. Mere interaction with a user through
101 a computer network, with no transfer of a copy, is not conveying.
102
103 An interactive user interface displays "Appropriate Legal Notices"
104 to the extent that it includes a convenient and prominently visible
105 feature that (1) displays an appropriate copyright notice, and (2)
106 tells the user that there is no warranty for the work (except to the
107 extent that warranties are provided), that licensees may convey the
108 work under this License, and how to view a copy of this License. If
109 the interface presents a list of user commands or options, such as a
110 menu, a prominent item in the list meets this criterion.
111
112 1. Source Code.
113
114 The "source code" for a work means the preferred form of the work
115 for making modifications to it. "Object code" means any non-source
116 form of a work.
117
118 A "Standard Interface" means an interface that either is an official
119 standard defined by a recognized standards body, or, in the case of
120 interfaces specified for a particular programming language, one that
121 is widely used among developers working in that language.
122
123 The "System Libraries" of an executable work include anything, other
124 than the work as a whole, that (a) is included in the normal form of
125 packaging a Major Component, but which is not part of that Major
126 Component, and (b) serves only to enable use of the work with that
127 Major Component, or to implement a Standard Interface for which an
128 implementation is available to the public in source code form. A
129 "Major Component", in this context, means a major essential component
130 (kernel, window system, and so on) of the specific operating system
131 (if any) on which the executable work runs, or a compiler used to
132 produce the work, or an object code interpreter used to run it.
133
134 The "Corresponding Source" for a work in object code form means all
135 the source code needed to generate, install, and (for an executable
136 work) run the object code and to modify the work, including scripts to
137 control those activities. However, it does not include the work's
138 System Libraries, or general-purpose tools or generally available free
139 programs which are used unmodified in performing those activities but
140 which are not part of the work. For example, Corresponding Source
141 includes interface definition files associated with source files for
142 the work, and the source code for shared libraries and dynamically
143 linked subprograms that the work is specifically designed to require,
144 such as by intimate data communication or control flow between those
145 subprograms and other parts of the work.
146
147 The Corresponding Source need not include anything that users
148 can regenerate automatically from other parts of the Corresponding
149 Source.
150
151 The Corresponding Source for a work in source code form is that
152 same work.
153
154 2. Basic Permissions.
155
156 All rights granted under this License are granted for the term of
157 copyright on the Program, and are irrevocable provided the stated
158 conditions are met. This License explicitly affirms your unlimited
159 permission to run the unmodified Program. The output from running a
160 covered work is covered by this License only if the output, given its
161 content, constitutes a covered work. This License acknowledges your
162 rights of fair use or other equivalent, as provided by copyright law.
163
164 You may make, run and propagate covered works that you do not
165 convey, without conditions so long as your license otherwise remains
166 in force. You may convey covered works to others for the sole purpose
167 of having them make modifications exclusively for you, or provide you
168 with facilities for running those works, provided that you comply with
169 the terms of this License in conveying all material for which you do
170 not control copyright. Those thus making or running the covered works
171 for you must do so exclusively on your behalf, under your direction
172 and control, on terms that prohibit them from making any copies of
173 your copyrighted material outside their relationship with you.
174
175 Conveying under any other circumstances is permitted solely under
176 the conditions stated below. Sublicensing is not allowed; section 10
177 makes it unnecessary.
178
179 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
181 No covered work shall be deemed part of an effective technological
182 measure under any applicable law fulfilling obligations under article
183 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 similar laws prohibiting or restricting circumvention of such
185 measures.
186
187 When you convey a covered work, you waive any legal power to forbid
188 circumvention of technological measures to the extent such circumvention
189 is effected by exercising rights under this License with respect to
190 the covered work, and you disclaim any intention to limit operation or
191 modification of the work as a means of enforcing, against the work's
192 users, your or third parties' legal rights to forbid circumvention of
193 technological measures.
194
195 4. Conveying Verbatim Copies.
196
197 You may convey verbatim copies of the Program's source code as you
198 receive it, in any medium, provided that you conspicuously and
199 appropriately publish on each copy an appropriate copyright notice;
200 keep intact all notices stating that this License and any
201 non-permissive terms added in accord with section 7 apply to the code;
202 keep intact all notices of the absence of any warranty; and give all
203 recipients a copy of this License along with the Program.
204
205 You may charge any price or no price for each copy that you convey,
206 and you may offer support or warranty protection for a fee.
207
208 5. Conveying Modified Source Versions.
209
210 You may convey a work based on the Program, or the modifications to
211 produce it from the Program, in the form of source code under the
212 terms of section 4, provided that you also meet all of these conditions:
213
214 a) The work must carry prominent notices stating that you modified
215 it, and giving a relevant date.
216
217 b) The work must carry prominent notices stating that it is
218 released under this License and any conditions added under section
219 7. This requirement modifies the requirement in section 4 to
220 "keep intact all notices".
221
222 c) You must license the entire work, as a whole, under this
223 License to anyone who comes into possession of a copy. This
224 License will therefore apply, along with any applicable section 7
225 additional terms, to the whole of the work, and all its parts,
226 regardless of how they are packaged. This License gives no
227 permission to license the work in any other way, but it does not
228 invalidate such permission if you have separately received it.
229
230 d) If the work has interactive user interfaces, each must display
231 Appropriate Legal Notices; however, if the Program has interactive
232 interfaces that do not display Appropriate Legal Notices, your
233 work need not make them do so.
234
235 A compilation of a covered work with other separate and independent
236 works, which are not by their nature extensions of the covered work,
237 and which are not combined with it such as to form a larger program,
238 in or on a volume of a storage or distribution medium, is called an
239 "aggregate" if the compilation and its resulting copyright are not
240 used to limit the access or legal rights of the compilation's users
241 beyond what the individual works permit. Inclusion of a covered work
242 in an aggregate does not cause this License to apply to the other
243 parts of the aggregate.
244
245 6. Conveying Non-Source Forms.
246
247 You may convey a covered work in object code form under the terms
248 of sections 4 and 5, provided that you also convey the
249 machine-readable Corresponding Source under the terms of this License,
250 in one of these ways:
251
252 a) Convey the object code in, or embodied in, a physical product
253 (including a physical distribution medium), accompanied by the
254 Corresponding Source fixed on a durable physical medium
255 customarily used for software interchange.
256
257 b) Convey the object code in, or embodied in, a physical product
258 (including a physical distribution medium), accompanied by a
259 written offer, valid for at least three years and valid for as
260 long as you offer spare parts or customer support for that product
261 model, to give anyone who possesses the object code either (1) a
262 copy of the Corresponding Source for all the software in the
263 product that is covered by this License, on a durable physical
264 medium customarily used for software interchange, for a price no
265 more than your reasonable cost of physically performing this
266 conveying of source, or (2) access to copy the
267 Corresponding Source from a network server at no charge.
268
269 c) Convey individual copies of the object code with a copy of the
270 written offer to provide the Corresponding Source. This
271 alternative is allowed only occasionally and noncommercially, and
272 only if you received the object code with such an offer, in accord
273 with subsection 6b.
274
275 d) Convey the object code by offering access from a designated
276 place (gratis or for a charge), and offer equivalent access to the
277 Corresponding Source in the same way through the same place at no
278 further charge. You need not require recipients to copy the
279 Corresponding Source along with the object code. If the place to
280 copy the object code is a network server, the Corresponding Source
281 may be on a different server (operated by you or a third party)
282 that supports equivalent copying facilities, provided you maintain
283 clear directions next to the object code saying where to find the
284 Corresponding Source. Regardless of what server hosts the
285 Corresponding Source, you remain obligated to ensure that it is
286 available for as long as needed to satisfy these requirements.
287
288 e) Convey the object code using peer-to-peer transmission, provided
289 you inform other peers where the object code and Corresponding
290 Source of the work are being offered to the general public at no
291 charge under subsection 6d.
292
293 A separable portion of the object code, whose source code is excluded
294 from the Corresponding Source as a System Library, need not be
295 included in conveying the object code work.
296
297 A "User Product" is either (1) a "consumer product", which means any
298 tangible personal property which is normally used for personal, family,
299 or household purposes, or (2) anything designed or sold for incorporation
300 into a dwelling. In determining whether a product is a consumer product,
301 doubtful cases shall be resolved in favor of coverage. For a particular
302 product received by a particular user, "normally used" refers to a
303 typical or common use of that class of product, regardless of the status
304 of the particular user or of the way in which the particular user
305 actually uses, or expects or is expected to use, the product. A product
306 is a consumer product regardless of whether the product has substantial
307 commercial, industrial or non-consumer uses, unless such uses represent
308 the only significant mode of use of the product.
309
310 "Installation Information" for a User Product means any methods,
311 procedures, authorization keys, or other information required to install
312 and execute modified versions of a covered work in that User Product from
313 a modified version of its Corresponding Source. The information must
314 suffice to ensure that the continued functioning of the modified object
315 code is in no case prevented or interfered with solely because
316 modification has been made.
317
318 If you convey an object code work under this section in, or with, or
319 specifically for use in, a User Product, and the conveying occurs as
320 part of a transaction in which the right of possession and use of the
321 User Product is transferred to the recipient in perpetuity or for a
322 fixed term (regardless of how the transaction is characterized), the
323 Corresponding Source conveyed under this section must be accompanied
324 by the Installation Information. But this requirement does not apply
325 if neither you nor any third party retains the ability to install
326 modified object code on the User Product (for example, the work has
327 been installed in ROM).
328
329 The requirement to provide Installation Information does not include a
330 requirement to continue to provide support service, warranty, or updates
331 for a work that has been modified or installed by the recipient, or for
332 the User Product in which it has been modified or installed. Access to a
333 network may be denied when the modification itself materially and
334 adversely affects the operation of the network or violates the rules and
335 protocols for communication across the network.
336
337 Corresponding Source conveyed, and Installation Information provided,
338 in accord with this section must be in a format that is publicly
339 documented (and with an implementation available to the public in
340 source code form), and must require no special password or key for
341 unpacking, reading or copying.
342
343 7. Additional Terms.
344
345 "Additional permissions" are terms that supplement the terms of this
346 License by making exceptions from one or more of its conditions.
347 Additional permissions that are applicable to the entire Program shall
348 be treated as though they were included in this License, to the extent
349 that they are valid under applicable law. If additional permissions
350 apply only to part of the Program, that part may be used separately
351 under those permissions, but the entire Program remains governed by
352 this License without regard to the additional permissions.
353
354 When you convey a copy of a covered work, you may at your option
355 remove any additional permissions from that copy, or from any part of
356 it. (Additional permissions may be written to require their own
357 removal in certain cases when you modify the work.) You may place
358 additional permissions on material, added by you to a covered work,
359 for which you have or can give appropriate copyright permission.
360
361 Notwithstanding any other provision of this License, for material you
362 add to a covered work, you may (if authorized by the copyright holders of
363 that material) supplement the terms of this License with terms:
364
365 a) Disclaiming warranty or limiting liability differently from the
366 terms of sections 15 and 16 of this License; or
367
368 b) Requiring preservation of specified reasonable legal notices or
369 author attributions in that material or in the Appropriate Legal
370 Notices displayed by works containing it; or
371
372 c) Prohibiting misrepresentation of the origin of that material, or
373 requiring that modified versions of such material be marked in
374 reasonable ways as different from the original version; or
375
376 d) Limiting the use for publicity purposes of names of licensors or
377 authors of the material; or
378
379 e) Declining to grant rights under trademark law for use of some
380 trade names, trademarks, or service marks; or
381
382 f) Requiring indemnification of licensors and authors of that
383 material by anyone who conveys the material (or modified versions of
384 it) with contractual assumptions of liability to the recipient, for
385 any liability that these contractual assumptions directly impose on
386 those licensors and authors.
387
388 All other non-permissive additional terms are considered "further
389 restrictions" within the meaning of section 10. If the Program as you
390 received it, or any part of it, contains a notice stating that it is
391 governed by this License along with a term that is a further
392 restriction, you may remove that term. If a license document contains
393 a further restriction but permits relicensing or conveying under this
394 License, you may add to a covered work material governed by the terms
395 of that license document, provided that the further restriction does
396 not survive such relicensing or conveying.
397
398 If you add terms to a covered work in accord with this section, you
399 must place, in the relevant source files, a statement of the
400 additional terms that apply to those files, or a notice indicating
401 where to find the applicable terms.
402
403 Additional terms, permissive or non-permissive, may be stated in the
404 form of a separately written license, or stated as exceptions;
405 the above requirements apply either way.
406
407 8. Termination.
408
409 You may not propagate or modify a covered work except as expressly
410 provided under this License. Any attempt otherwise to propagate or
411 modify it is void, and will automatically terminate your rights under
412 this License (including any patent licenses granted under the third
413 paragraph of section 11).
414
415 However, if you cease all violation of this License, then your
416 license from a particular copyright holder is reinstated (a)
417 provisionally, unless and until the copyright holder explicitly and
418 finally terminates your license, and (b) permanently, if the copyright
419 holder fails to notify you of the violation by some reasonable means
420 prior to 60 days after the cessation.
421
422 Moreover, your license from a particular copyright holder is
423 reinstated permanently if the copyright holder notifies you of the
424 violation by some reasonable means, this is the first time you have
425 received notice of violation of this License (for any work) from that
426 copyright holder, and you cure the violation prior to 30 days after
427 your receipt of the notice.
428
429 Termination of your rights under this section does not terminate the
430 licenses of parties who have received copies or rights from you under
431 this License. If your rights have been terminated and not permanently
432 reinstated, you do not qualify to receive new licenses for the same
433 material under section 10.
434
435 9. Acceptance Not Required for Having Copies.
436
437 You are not required to accept this License in order to receive or
438 run a copy of the Program. Ancillary propagation of a covered work
439 occurring solely as a consequence of using peer-to-peer transmission
440 to receive a copy likewise does not require acceptance. However,
441 nothing other than this License grants you permission to propagate or
442 modify any covered work. These actions infringe copyright if you do
443 not accept this License. Therefore, by modifying or propagating a
444 covered work, you indicate your acceptance of this License to do so.
445
446 10. Automatic Licensing of Downstream Recipients.
447
448 Each time you convey a covered work, the recipient automatically
449 receives a license from the original licensors, to run, modify and
450 propagate that work, subject to this License. You are not responsible
451 for enforcing compliance by third parties with this License.
452
453 An "entity transaction" is a transaction transferring control of an
454 organization, or substantially all assets of one, or subdividing an
455 organization, or merging organizations. If propagation of a covered
456 work results from an entity transaction, each party to that
457 transaction who receives a copy of the work also receives whatever
458 licenses to the work the party's predecessor in interest had or could
459 give under the previous paragraph, plus a right to possession of the
460 Corresponding Source of the work from the predecessor in interest, if
461 the predecessor has it or can get it with reasonable efforts.
462
463 You may not impose any further restrictions on the exercise of the
464 rights granted or affirmed under this License. For example, you may
465 not impose a license fee, royalty, or other charge for exercise of
466 rights granted under this License, and you may not initiate litigation
467 (including a cross-claim or counterclaim in a lawsuit) alleging that
468 any patent claim is infringed by making, using, selling, offering for
469 sale, or importing the Program or any portion of it.
470
471 11. Patents.
472
473 A "contributor" is a copyright holder who authorizes use under this
474 License of the Program or a work on which the Program is based. The
475 work thus licensed is called the contributor's "contributor version".
476
477 A contributor's "essential patent claims" are all patent claims
478 owned or controlled by the contributor, whether already acquired or
479 hereafter acquired, that would be infringed by some manner, permitted
480 by this License, of making, using, or selling its contributor version,
481 but do not include claims that would be infringed only as a
482 consequence of further modification of the contributor version. For
483 purposes of this definition, "control" includes the right to grant
484 patent sublicenses in a manner consistent with the requirements of
485 this License.
486
487 Each contributor grants you a non-exclusive, worldwide, royalty-free
488 patent license under the contributor's essential patent claims, to
489 make, use, sell, offer for sale, import and otherwise run, modify and
490 propagate the contents of its contributor version.
491
492 In the following three paragraphs, a "patent license" is any express
493 agreement or commitment, however denominated, not to enforce a patent
494 (such as an express permission to practice a patent or covenant not to
495 sue for patent infringement). To "grant" such a patent license to a
496 party means to make such an agreement or commitment not to enforce a
497 patent against the party.
498
499 If you convey a covered work, knowingly relying on a patent license,
500 and the Corresponding Source of the work is not available for anyone
501 to copy, free of charge and under the terms of this License, through a
502 publicly available network server or other readily accessible means,
503 then you must either (1) cause the Corresponding Source to be so
504 available, or (2) arrange to deprive yourself of the benefit of the
505 patent license for this particular work, or (3) arrange, in a manner
506 consistent with the requirements of this License, to extend the patent
507 license to downstream recipients. "Knowingly relying" means you have
508 actual knowledge that, but for the patent license, your conveying the
509 covered work in a country, or your recipient's use of the covered work
510 in a country, would infringe one or more identifiable patents in that
511 country that you have reason to believe are valid.
512
513 If, pursuant to or in connection with a single transaction or
514 arrangement, you convey, or propagate by procuring conveyance of, a
515 covered work, and grant a patent license to some of the parties
516 receiving the covered work authorizing them to use, propagate, modify
517 or convey a specific copy of the covered work, then the patent license
518 you grant is automatically extended to all recipients of the covered
519 work and works based on it.
520
521 A patent license is "discriminatory" if it does not include within
522 the scope of its coverage, prohibits the exercise of, or is
523 conditioned on the non-exercise of one or more of the rights that are
524 specifically granted under this License. You may not convey a covered
525 work if you are a party to an arrangement with a third party that is
526 in the business of distributing software, under which you make payment
527 to the third party based on the extent of your activity of conveying
528 the work, and under which the third party grants, to any of the
529 parties who would receive the covered work from you, a discriminatory
530 patent license (a) in connection with copies of the covered work
531 conveyed by you (or copies made from those copies), or (b) primarily
532 for and in connection with specific products or compilations that
533 contain the covered work, unless you entered into that arrangement,
534 or that patent license was granted, prior to 28 March 2007.
535
536 Nothing in this License shall be construed as excluding or limiting
537 any implied license or other defenses to infringement that may
538 otherwise be available to you under applicable patent law.
539
540 12. No Surrender of Others' Freedom.
541
542 If conditions are imposed on you (whether by court order, agreement or
543 otherwise) that contradict the conditions of this License, they do not
544 excuse you from the conditions of this License. If you cannot convey a
545 covered work so as to satisfy simultaneously your obligations under this
546 License and any other pertinent obligations, then as a consequence you may
547 not convey it at all. For example, if you agree to terms that obligate you
548 to collect a royalty for further conveying from those to whom you convey
549 the Program, the only way you could satisfy both those terms and this
550 License would be to refrain entirely from conveying the Program.
551
552 13. Use with the GNU Affero General Public License.
553
554 Notwithstanding any other provision of this License, you have
555 permission to link or combine any covered work with a work licensed
556 under version 3 of the GNU Affero General Public License into a single
557 combined work, and to convey the resulting work. The terms of this
558 License will continue to apply to the part which is the covered work,
559 but the special requirements of the GNU Affero General Public License,
560 section 13, concerning interaction through a network will apply to the
561 combination as such.
562
563 14. Revised Versions of this License.
564
565 The Free Software Foundation may publish revised and/or new versions of
566 the GNU General Public License from time to time. Such new versions will
567 be similar in spirit to the present version, but may differ in detail to
568 address new problems or concerns.
569
570 Each version is given a distinguishing version number. If the
571 Program specifies that a certain numbered version of the GNU General
572 Public License "or any later version" applies to it, you have the
573 option of following the terms and conditions either of that numbered
574 version or of any later version published by the Free Software
575 Foundation. If the Program does not specify a version number of the
576 GNU General Public License, you may choose any version ever published
577 by the Free Software Foundation.
578
579 If the Program specifies that a proxy can decide which future
580 versions of the GNU General Public License can be used, that proxy's
581 public statement of acceptance of a version permanently authorizes you
582 to choose that version for the Program.
583
584 Later license versions may give you additional or different
585 permissions. However, no additional obligations are imposed on any
586 author or copyright holder as a result of your choosing to follow a
587 later version.
588
589 15. Disclaimer of Warranty.
590
591 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
600 16. Limitation of Liability.
601
602 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 SUCH DAMAGES.
611
612 17. Interpretation of Sections 15 and 16.
613
614 If the disclaimer of warranty and limitation of liability provided
615 above cannot be given local legal effect according to their terms,
616 reviewing courts shall apply local law that most closely approximates
617 an absolute waiver of all civil liability in connection with the
618 Program, unless a warranty or assumption of liability accompanies a
619 copy of the Program in return for a fee.
620
621 END OF TERMS AND CONDITIONS
622
623 How to Apply These Terms to Your New Programs
624
625 If you develop a new program, and you want it to be of the greatest
626 possible use to the public, the best way to achieve this is to make it
627 free software which everyone can redistribute and change under these terms.
628
629 To do so, attach the following notices to the program. It is safest
630 to attach them to the start of each source file to most effectively
631 state the exclusion of warranty; and each file should have at least
632 the "copyright" line and a pointer to where the full notice is found.
633
634 JD-GUI, a standalone graphical utility that displays Java sources from
635 CLASS files
636 Copyright (C) 2008-2019 Emmanuel Dupuy
637
638 This program is free software: you can redistribute it and/or modify
639 it under the terms of the GNU General Public License as published by
640 the Free Software Foundation, either version 3 of the License, or
641 (at your option) any later version.
642
643 This program is distributed in the hope that it will be useful,
644 but WITHOUT ANY WARRANTY; without even the implied warranty of
645 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
646 GNU General Public License for more details.
647
648 You should have received a copy of the GNU General Public License
649 along with this program. If not, see <http://www.gnu.org/licenses/>.
650
651 Also add information on how to contact you by electronic and paper mail.
652
653 If the program does terminal interaction, make it output a short
654 notice like this when it starts in an interactive mode:
655
656 JD-GUI Copyright (C) 2008-2019 Emmanuel Dupuy
657 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
658 This is free software, and you are welcome to redistribute it
659 under certain conditions; type `show c' for details.
660
661 The hypothetical commands `show w' and `show c' should show the appropriate
662 parts of the General Public License. Of course, your program's commands
663 might be different; for a GUI interface, you would use an "about box".
664
665 You should also get your employer (if you work as a programmer) or school,
666 if any, to sign a "copyright disclaimer" for the program, if necessary.
667 For more information on this, and how to apply and follow the GNU GPL, see
668 <http://www.gnu.org/licenses/>.
669
670 The GNU General Public License does not permit incorporating your program
671 into proprietary programs. If your program is a subroutine library, you
672 may consider it more useful to permit linking proprietary applications with
673 the library. If this is what you want to do, use the GNU Lesser General
674 Public License instead of this License. But first, please read
675 <http://www.gnu.org/philosophy/why-not-lgpl.html>.
0 JD-GUI license - GPLv3
1
2 Libraries used:
3
4 Groovy - Apache License 2.0
5 Gradle - Apache License 2.0
6 JD-Core Java Release - GPLv3
7 RSyntaxTextArea - Modified BSD license
8
9 JD-GUI Mac OSX distribution:
10
11 universalJavaApplicationStub - MIT License
12
13 JD-GUI Windows distribution:
14
15 Launch4j - MIT License
0 JD-GUI license - GPLv3
1
2 Libraries used:
3
4 Groovy - Apache License 2.0
5 Gradle - Apache License 2.0
6 JD-Core Java Release - GPLv3
7 RSyntaxTextArea - Modified BSD license
8
9 JD-GUI Mac OSX distribution:
10
11 universalJavaApplicationStub - MIT License
12
13 JD-GUI Windows distribution:
14
15 Launch4j - MIT License
0 # JD-GUI
1
2 JD-GUI, a standalone graphical utility that displays Java sources from CLASS files.
3
4 ![](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/jd-gui.png)
5
6 - Java Decompiler projects home page: [http://java-decompiler.github.io](http://java-decompiler.github.io)
7 - JD-GUI source code: [https://github.com/java-decompiler/jd-gui](https://github.com/java-decompiler/jd-gui)
8
9 ## Description
10 JD-GUI is a standalone graphical utility that displays Java source codes of
11 ".class" files. You can browse the reconstructed source code with the JD-GUI
12 for instant access to methods and fields.
13
14 ## How to build JD-GUI ?
15 ```
16 > git clone https://github.com/java-decompiler/jd-gui.git
17 > cd jd-gui
18 > ./gradlew build
19 ```
20 generate :
21 - _"build/libs/jd-gui-x.y.z.jar"_
22 - _"build/libs/jd-gui-x.y.z-min.jar"_
23 - _"build/distributions/jd-gui-windows-x.y.z.zip"_
24 - _"build/distributions/jd-gui-osx-x.y.z.tar"_
25 - _"build/distributions/jd-gui-x.y.z.deb"_
26 - _"build/distributions/jd-gui-x.y.z.rpm"_
27
28 ## How to launch JD-GUI ?
29 - Double-click on _"jd-gui-x.y.z.jar"_
30 - Double-click on _"jd-gui.exe"_ application from Windows
31 - Double-click on _"JD-GUI"_ application from Mac OSX
32 - Execute _"java -jar jd-gui-x.y.z.jar"_ or _"java -classpath jd-gui-x.y.z.jar org.jd.gui.App"_
33
34 ## How to use JD-GUI ?
35 - Open a file with menu "File > Open File..."
36 - Open recent files with menu "File > Recent Files"
37 - Drag and drop files from your file explorer
38
39 ## How to extend JD-GUI ?
40 ```
41 > ./gradlew idea
42 ```
43 generate Idea Intellij project
44 ```
45 > ./gradlew eclipse
46 ```
47 generate Eclipse project
48 ```
49 > java -classpath jd-gui-x.y.z.jar;myextension1.jar;myextension2.jar org.jd.gui.App
50 ```
51 launch JD-GUI with your extensions
52
53 ## How to uninstall JD-GUI ?
54 - Java: Delete "jd-gui-x.y.z.jar" and "jd-gui.cfg".
55 - Mac OSX: Drag and drop "JD-GUI" application into the trash.
56 - Windows: Delete "jd-gui.exe" and "jd-gui.cfg".
57
58 ## License
59 Released under the [GNU GPL v3](LICENSE).
60
61 ## Donations
62 Did JD-GUI help you to solve a critical situation? Do you use JD-Eclipse daily? What about making a donation?
63
64 [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_euro.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=C88ZMVZ78RF22) [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_usd.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CRMXT4Y4QLQGU)
0 # JD-GUI
1
2 JD-GUI, a standalone graphical utility that displays Java sources from CLASS files.
3
4 ![](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/jd-gui.png)
5
6 - Java Decompiler projects home page: [http://java-decompiler.github.io](http://java-decompiler.github.io)
7 - JD-GUI source code: [https://github.com/java-decompiler/jd-gui](https://github.com/java-decompiler/jd-gui)
8
9 ## Description
10 JD-GUI is a standalone graphical utility that displays Java source codes of
11 ".class" files. You can browse the reconstructed source code with the JD-GUI
12 for instant access to methods and fields.
13
14 ## How to build JD-GUI ?
15 ```
16 > git clone https://github.com/java-decompiler/jd-gui.git
17 > cd jd-gui
18 > ./gradlew build
19 ```
20 generate :
21 - _"build/libs/jd-gui-x.y.z.jar"_
22 - _"build/libs/jd-gui-x.y.z-min.jar"_
23 - _"build/distributions/jd-gui-windows-x.y.z.zip"_
24 - _"build/distributions/jd-gui-osx-x.y.z.tar"_
25 - _"build/distributions/jd-gui-x.y.z.deb"_
26 - _"build/distributions/jd-gui-x.y.z.rpm"_
27
28 ## How to launch JD-GUI ?
29 - Double-click on _"jd-gui-x.y.z.jar"_
30 - Double-click on _"jd-gui.exe"_ application from Windows
31 - Double-click on _"JD-GUI"_ application from Mac OSX
32 - Execute _"java -jar jd-gui-x.y.z.jar"_ or _"java -classpath jd-gui-x.y.z.jar org.jd.gui.App"_
33
34 ## How to use JD-GUI ?
35 - Open a file with menu "File > Open File..."
36 - Open recent files with menu "File > Recent Files"
37 - Drag and drop files from your file explorer
38
39 ## How to extend JD-GUI ?
40 ```
41 > ./gradlew idea
42 ```
43 generate Idea Intellij project
44 ```
45 > ./gradlew eclipse
46 ```
47 generate Eclipse project
48 ```
49 > java -classpath jd-gui-x.y.z.jar;myextension1.jar;myextension2.jar org.jd.gui.App
50 ```
51 launch JD-GUI with your extensions
52
53 ## How to uninstall JD-GUI ?
54 - Java: Delete "jd-gui-x.y.z.jar" and "jd-gui.cfg".
55 - Mac OSX: Drag and drop "JD-GUI" application into the trash.
56 - Windows: Delete "jd-gui.exe" and "jd-gui.cfg".
57
58 ## License
59 Released under the [GNU GPL v3](LICENSE).
60
61 ## Donations
62 Did JD-GUI help you to solve a critical situation? Do you use JD-Eclipse daily? What about making a donation?
63
64 [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_euro.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=C88ZMVZ78RF22) [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_usd.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CRMXT4Y4QLQGU)
0 apply plugin: 'java'
1
2 version = '1.0.0'
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api;
8
9 import org.jd.gui.api.feature.UriGettable;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.spi.*;
13
14 import javax.swing.*;
15 import java.io.File;
16 import java.net.URI;
17 import java.nio.file.Path;
18 import java.util.Collection;
19 import java.util.Map;
20 import java.util.concurrent.Future;
21
22 public interface API {
23 boolean openURI(URI uri);
24
25 boolean openURI(int x, int y, Collection<Container.Entry> entries, String query, String fragment);
26
27 void addURI(URI uri);
28
29 <T extends JComponent & UriGettable> void addPanel(String title, Icon icon, String tip, T component);
30
31 Collection<Action> getContextualActions(Container.Entry entry, String fragment);
32
33 UriLoader getUriLoader(URI uri);
34
35 FileLoader getFileLoader(File file);
36
37 ContainerFactory getContainerFactory(Path rootPath);
38
39 PanelFactory getMainPanelFactory(Container container);
40
41 TreeNodeFactory getTreeNodeFactory(Container.Entry entry);
42
43 TypeFactory getTypeFactory(Container.Entry entry);
44
45 Indexer getIndexer(Container.Entry entry);
46
47 SourceSaver getSourceSaver(Container.Entry entry);
48
49 Map<String, String> getPreferences();
50
51 Collection<Future<Indexes>> getCollectionOfFutureIndexes();
52
53 interface LoadSourceListener {
54 void sourceLoaded(String source);
55 }
56
57 String getSource(Container.Entry entry);
58
59 void loadSource(Container.Entry entry, LoadSourceListener listener);
60
61 File loadSourceFile(Container.Entry entry);
62 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.model.Container;
10
11 public interface ContainerEntryGettable {
12 Container.Entry getEntry();
13 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface ContentCopyable {
10 void copy();
11 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Indexes;
11
12 public interface ContentIndexable {
13 Indexes index(API api);
14 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.API;
10
11 import java.io.OutputStream;
12
13 public interface ContentSavable {
14 String getFileName();
15
16 void save(API api, OutputStream os);
17 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface ContentSearchable {
10 boolean highlightText(String text, boolean caseSensitive);
11
12 void findNext(String text, boolean caseSensitive);
13
14 void findPrevious(String text, boolean caseSensitive);
15 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface ContentSelectable {
10 void selectAll();
11 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface FocusedTypeGettable extends ContainerEntryGettable {
10 String getFocusedTypeName();
11 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.model.Indexes;
10
11 import java.util.Collection;
12 import java.util.concurrent.Future;
13
14 public interface IndexesChangeListener {
15 void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes);
16 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface LineNumberNavigable {
10 int getMaximumLineNumber();
11
12 void goToLineNumber(int lineNumber);
13
14 boolean checkLineNumber(int lineNumber);
15 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import javax.swing.*;
10
11 public interface PageChangeListener {
12 <T extends JComponent & UriGettable> void pageChanged(T page);
13 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface PageChangeable {
10 void addPageChangeListener(PageChangeListener listener);
11 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 public interface PageClosable {
10 boolean closePage();
11 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.API;
10
11 import javax.swing.*;
12
13 public interface PageCreator {
14 <T extends JComponent & UriGettable> T createPage(API api);
15 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import java.util.Map;
10
11 public interface PreferencesChangeListener {
12 void preferencesChanged(Map<String, String> preferences);
13 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.API;
10
11 import java.nio.file.Path;
12
13 public interface SourcesSavable {
14 String getSourceFileName();
15
16 int getFileCount();
17
18 void save(API api, Controller controller, Listener listener, Path path);
19
20 interface Controller {
21 boolean isCancelled();
22 }
23
24 interface Listener {
25 void pathSaved(Path path);
26 }
27 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import org.jd.gui.api.API;
10
11 public interface TreeNodeExpandable {
12 void populateTreeNode(API api);
13 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import java.net.URI;
10
11 public interface UriGettable {
12 URI getUri();
13 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.feature;
8
9 import java.net.URI;
10
11 /**
12 * uri : scheme '://' path ('?' query)? ('#' fragment)?<br>
13 * scheme : 'generic' | 'jar' | 'war' | 'ear' | 'dex' | ...<br>
14 * path : singlePath('!' singlePath)*<br>
15 * singlePath : [path/to/dir/] | [path/to/file]<br>
16 * query : queryLineNumber | queryPosition | querySearch<br>
17 * queryLineNumber : 'lineNumber=' [numeric]<br>
18 * queryPosition : 'position=' [numeric]<br>
19 * querySearch : 'highlightPattern=' queryPattern '&highlightFlags=' queryFlags ('&highlightScope=' typeName)?<br>
20 * queryPattern : [start of string] | [start of type name] | [start of field name] | [start of method name]<br>
21 * queryFlags : 'd'? // Match declarations<br>
22 * 'r'? // Match references<br>
23 * 't'? // Match types<br>
24 * 'c'? // Match constructors<br>
25 * 'm'? // Match methods<br>
26 * 'f'? // Match fields<br>
27 * 's'? // Match strings<br>
28 * fragment : fragmentType | fragmentField | fragmentMethod<br>
29 * fragmentType : typeName<br>
30 * fragmentField : typeName '-' [field name] '-' descriptor<br>
31 * fragmentMethod : typeName '-' [method name] '-' methodDescriptor<br>
32 * methodDescriptor : '(*)?' | // Match all method descriptors<br>
33 * '(' descriptor* ')' descriptor<br>
34 * descriptor : '?' | // Match a primitive or a type name<br>
35 * '['* primitiveOrTypeName<br>
36 * primitiveOrTypeName : 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'L' typeName ';' | 'S' | 'Z'<br>
37 * typeName : [internal qualified name] | '*\/' [name]<br>
38 * <br>
39 * Examples:<br>
40 * <ul>
41 * <li>file://dir1/dir2/</li>
42 * <li>file://dir1/dir2/file</li>
43 * <li>jar://dir1/dir2/</li>
44 * <li>jar://dir1/dir2/file</li>
45 *
46 * <li>jar://dir1/dir2/javafile</li>
47 * <li>jar://dir1/dir2/javafile#type</li>
48 * <li>jar://dir1/dir2/javafile#type-fieldName-descriptor</li>
49 * <li>jar://dir1/dir2/javafile#type-methodName-descriptor</li>
50 * <li>jar://dir1/dir2/javafile#innertype</li>
51 * <li>jar://dir1/dir2/javafile#innertype-fieldName-?</li>
52 * <li>jar://dir1/dir2/javafile#innertype-methodName-(*)?</li>
53 * <li>jar://dir1/dir2/javafile#innertype-methodName-(?JZLjava/lang/Sting;C)I</li>
54 * <li>jar://dir1/dir2/javafile#innertype-fieldName-descriptor</li>
55 * <li>jar://dir1/dir2/javafile#innertype-methodName-descriptor</li>
56 *
57 * <li>file://dir1/dir2/file?lineNumber=numeric</li>
58 * <li>file://dir1/dir2/file?position=numeric</li>
59 * <li>file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=java/lang/String</li>
60 * <li>file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=*\/String</li>
61 * </ul>
62 */
63 public interface UriOpenable {
64 boolean openUri(URI uri);
65 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.model;
8
9 import java.io.InputStream;
10 import java.net.URI;
11 import java.util.Collection;
12
13 public interface Container {
14 String getType();
15
16 Entry getRoot();
17
18 /**
19 * File or directory
20 */
21 interface Entry {
22 Container getContainer();
23
24 Entry getParent();
25
26 URI getUri();
27
28 String getPath();
29
30 boolean isDirectory();
31
32 long length();
33
34 InputStream getInputStream();
35
36 Collection<Entry> getChildren();
37 }
38 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.model;
8
9 import java.util.Collection;
10 import java.util.Map;
11
12 /**
13 * Whatever the language/file format (Java|Groovy|Scala/Class|DEX, Java|Javascript/Source, C#/CIL, ...), type names,
14 * stored in the indexes, use the JVM internal format (package separator = '/', inner class separator = '$').<br>
15 * <br>
16 * List of default indexes:
17 * <ul>
18 * <li>
19 * Map "strings"<br>
20 * key: a string<br>
21 * value: a list of entries containing the string
22 * </li>
23 * <li>
24 * Map "typeDeclarations"<br>
25 * key: a type name using internal JVM internal format<br>
26 * value: a list of entries containing the type declaration
27 * </li>
28 * <li>
29 * Map "constructorDeclarations"<br>
30 * key: a type name using internal JVM internal format<br>
31 * value: a list of entries containing the constructor declaration
32 * </li>
33 * <li>
34 * Map "constructorReferences"<br>
35 * key: a type name using internal JVM internal format<br>
36 * value: a list of entries containing the constructor reference
37 * </li>
38 * <li>
39 * Map "methodDeclarations"<br>
40 * key: a method name<br>
41 * value: a list of entries containing the method declaration
42 * </li>
43 * <li>
44 * Map "methodReferences"<br>
45 * key: a method name<br>
46 * value: a list of entries containing the method reference
47 * </li>
48 * <li>
49 * Map "fieldDeclarations"<br>
50 * key: a field name<br>
51 * value: a list of entries containing the field declaration
52 * </li>
53 * <li>
54 * Map "fieldReferences"<br>
55 * key: a field name<br>
56 * value: a list of entries containing the field reference
57 * </li>
58 * <li>
59 * Map "subTypeNames"<br>
60 * key: a super type name using internal JVM internal format<br>
61 * value: a list of sub type names using internal JVM internal format
62 * </li>
63 * </ul>
64 */
65 public interface Indexes {
66 Map<String, Collection> getIndex(String name);
67 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.model;
8
9 import javax.swing.*;
10
11 public interface TreeNodeData {
12 String getLabel();
13
14 String getTip();
15
16 Icon getIcon();
17
18 Icon getOpenIcon();
19 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.api.model;
8
9 import javax.swing.*;
10 import java.util.Collection;
11
12 public interface Type {
13 int FLAG_PUBLIC = 1;
14 int FLAG_PRIVATE = 2;
15 int FLAG_PROTECTED = 4;
16 int FLAG_STATIC = 8;
17 int FLAG_FINAL = 16;
18 int FLAG_VARARGS = 128;
19 int FLAG_INTERFACE = 512;
20 int FLAG_ABSTRACT = 1024;
21 int FLAG_ANNOTATION = 8192;
22 int FLAG_ENUM = 16384;
23
24 int getFlags();
25
26 String getName();
27
28 String getSuperName();
29
30 String getOuterName();
31
32 String getDisplayTypeName();
33
34 String getDisplayInnerTypeName();
35
36 String getDisplayPackageName();
37
38 Icon getIcon();
39
40 Collection<Type> getInnerTypes();
41
42 Collection<Field> getFields();
43
44 Collection<Method> getMethods();
45
46 interface Field {
47 int getFlags();
48
49 String getName();
50
51 String getDescriptor();
52
53 String getDisplayName();
54
55 Icon getIcon();
56 }
57
58 interface Method {
59 int getFlags();
60
61 String getName();
62
63 String getDescriptor();
64
65 String getDisplayName();
66
67 Icon getIcon();
68 }
69 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13
14 public interface ContainerFactory {
15 String getType();
16
17 boolean accept(API api, Path rootPath);
18
19 Container make(API api, Container.Entry parentEntry, Path rootPath);
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import javax.swing.*;
13 import java.util.Collection;
14
15 public interface ContextualActionsFactory {
16 String GROUP_NAME = "GroupNameKey";
17
18 /**
19 * Build a collection of actions for 'entry' and 'fragment', grouped by GROUP_NAME and sorted by NAME. Null values
20 * are added for separators.
21 *
22 * @param fragment @see jd.gui.api.feature.UriOpenable
23 * @return a collection of actions
24 */
25 Collection<Action> make(API api, Container.Entry entry, String fragment);
26 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public interface FileLoader {
14 String[] getExtensions();
15
16 String getDescription();
17
18 boolean accept(API api, File file);
19
20 boolean load(API api, File file);
21 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12
13 import java.util.regex.Pattern;
14
15 public interface Indexer {
16 String[] getSelectors();
17
18 Pattern getPathPattern();
19
20 void index(API api, Container.Entry entry, Indexes indexes);
21 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.UriGettable;
11 import org.jd.gui.api.model.Container;
12
13 import javax.swing.*;
14
15 public interface PanelFactory {
16 String[] getTypes();
17
18 <T extends JComponent & UriGettable> T make(API api, Container container);
19 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10
11 public interface PasteHandler {
12 boolean accept(Object obj);
13
14 void paste(API api, Object obj);
15 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import javax.swing.*;
10 import java.awt.*;
11 import java.util.Map;
12
13 public interface PreferencesPanel {
14 String getPreferencesGroupTitle();
15
16 String getPreferencesPanelTitle();
17
18 JComponent getPanel();
19
20 void init(Color errorBackgroundColor);
21
22 boolean isActivated();
23
24 void loadPreferences(Map<String, String> preferences);
25
26 void savePreferences(Map<String, String> preferences);
27
28 boolean arePreferencesValid();
29
30 void addPreferencesChangeListener(PreferencesPanelChangeListener listener);
31
32 interface PreferencesPanelChangeListener {
33 void preferencesPanelChanged(PreferencesPanel source);
34 }
35 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.io.File;
13
14 public interface SourceLoader {
15 String getSource(API api, Container.Entry entry);
16
17 String loadSource(API api, Container.Entry entry);
18
19 File loadSourceFile(API api, Container.Entry entry);
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13 import java.util.regex.Pattern;
14
15 public interface SourceSaver {
16 String[] getSelectors();
17
18 Pattern getPathPattern();
19
20 String getSourcePath(Container.Entry entry);
21
22 int getFileCount(API api, Container.Entry entry);
23
24 /**
25 * Check parent path, build source file name, create NIO path and save the content.
26 */
27 void save(API api, Controller controller, Listener listener, Path rootPath, Container.Entry entry);
28
29 /**
30 * Save content:
31 * <ul>
32 * <li>For file, save the source content.</li>
33 * <li>For directory, call 'save' for each children.</li>
34 * </ul>
35 */
36 void saveContent(API api, Controller controller, Listener listener, Path rootPath, Path path, Container.Entry entry);
37
38 interface Controller {
39 boolean isCancelled();
40 }
41
42 interface Listener {
43 void pathSaved(Path path);
44 }
45 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13
14 import javax.swing.tree.DefaultMutableTreeNode;
15 import java.util.regex.Pattern;
16
17 public interface TreeNodeFactory {
18 String[] getSelectors();
19
20 Pattern getPathPattern();
21
22 <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry);
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Type;
12
13 import java.util.Collection;
14 import java.util.regex.Pattern;
15
16 public interface TypeFactory {
17 String[] getSelectors();
18
19 Pattern getPathPattern();
20
21 /**
22 * @return all root types contains in 'entry'
23 */
24 Collection<Type> make(API api, Container.Entry entry);
25
26 /**
27 * @param fragment @see jd.gui.api.feature.UriOpenable
28 * @return if 'fragment' is null, return the main type in 'entry',
29 * otherwise, return the type or sub-type matching with 'fragment'
30 */
31 Type make(API api, Container.Entry entry, String fragment);
32 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.spi;
8
9 import org.jd.gui.api.API;
10
11 import java.net.URI;
12
13 public interface UriLoader {
14 String[] getSchemes();
15
16 boolean accept(API api, URI uri);
17
18 boolean load(API api, URI uri);
19 }
0 apply plugin: 'java'
1
2 dependencies {
3 provided 'com.yuvimasory:orange-extensions:1.3.0' // OSX support
4 compile project(':api')
5 runtime project(':services')
6 }
7
8 version = parent.version
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui;
8
9 import org.jd.gui.controller.MainController;
10 import org.jd.gui.model.configuration.Configuration;
11 import org.jd.gui.service.configuration.ConfigurationPersister;
12 import org.jd.gui.service.configuration.ConfigurationPersisterService;
13 import org.jd.gui.util.exception.ExceptionUtil;
14 import org.jd.gui.util.net.InterProcessCommunicationUtil;
15
16 import javax.swing.*;
17 import java.io.File;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21
22 public class App {
23 protected static final String SINGLE_INSTANCE = "UIMainWindowPreferencesProvider.singleInstance";
24
25 protected static MainController controller;
26
27 public static void main(String[] args) {
28 if (checkHelpFlag(args)) {
29 JOptionPane.showMessageDialog(null, "Usage: jd-gui [option] [input-file] ...\n\nOption:\n -h Show this help message and exit", Constants.APP_NAME, JOptionPane.INFORMATION_MESSAGE);
30 } else {
31 // Load preferences
32 ConfigurationPersister persister = ConfigurationPersisterService.getInstance().get();
33 Configuration configuration = persister.load();
34 Runtime.getRuntime().addShutdownHook(new Thread(() -> persister.save(configuration)));
35
36 if ("true".equals(configuration.getPreferences().get(SINGLE_INSTANCE))) {
37 InterProcessCommunicationUtil ipc = new InterProcessCommunicationUtil();
38 try {
39 ipc.listen(receivedArgs -> controller.openFiles(newList(receivedArgs)));
40 } catch (Exception notTheFirstInstanceException) {
41 // Send args to main windows and exit
42 ipc.send(args);
43 System.exit(0);
44 }
45 }
46
47 // Create SwingBuilder, set look and feel
48 try {
49 UIManager.setLookAndFeel(configuration.getLookAndFeel());
50 } catch (Exception e) {
51 configuration.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
52 try {
53 UIManager.setLookAndFeel(configuration.getLookAndFeel());
54 } catch (Exception ee) {
55 assert ExceptionUtil.printStackTrace(ee);
56 }
57 }
58
59 // Create main controller and show main frame
60 controller = new MainController(configuration);
61 controller.show(newList(args));
62 }
63 }
64
65 protected static boolean checkHelpFlag(String[] args) {
66 if (args != null) {
67 for (String arg : args) {
68 if ("-h".equals(arg)) {
69 return true;
70 }
71 }
72 }
73 return false;
74 }
75
76 protected static List<File> newList(String[] paths) {
77 if (paths == null) {
78 return Collections.emptyList();
79 } else {
80 ArrayList<File> files = new ArrayList<>(paths.length);
81 for (String path : paths) {
82 files.add(new File(path));
83 }
84 return files;
85 }
86 }
87 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui;
8
9 public class Constants {
10 public static final String APP_NAME = "JD-GUI";
11
12 public static final int DEFAULT_WIDTH = 600;
13 public static final int DEFAULT_HEIGHT = 400;
14
15 public static final int MINIMAL_WIDTH = 500;
16 public static final int MINIMAL_HEIGHT = 160;
17
18 public static final String CONFIG_FILENAME = "jd-gui.cfg";
19
20 public static final int MAX_RECENT_FILES = 10;
21 public static final int RECENT_FILE_MAX_LENGTH = 200;
22 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui;
8
9 import com.apple.eawt.Application;
10
11 public class OsxApp extends App {
12
13 @SuppressWarnings("unchecked")
14 public static void main(String[] args) {
15 // Create an instance of the mac OSX Application class
16 Application application = Application.getApplication();
17
18 App.main(args);
19
20 // Add an handle invoked when the application is asked to open a list of files
21 application.setOpenFileHandler(e -> controller.openFiles(e.getFiles()));
22
23 // Add an handle invoked when the application is asked to quit
24 application.setQuitHandler((e, r) -> System.exit(0));
25 }
26 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.view.AboutView;
10
11 import javax.swing.*;
12
13 public class AboutController {
14 protected AboutView aboutView;
15
16 public AboutController(JFrame mainFrame) {
17 // Create UI
18 aboutView = new AboutView(mainFrame);
19 }
20
21 public void show() {
22 // Show
23 aboutView.show();
24 }
25 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.feature.LineNumberNavigable;
10 import org.jd.gui.model.configuration.Configuration;
11 import org.jd.gui.view.GoToView;
12
13 import javax.swing.*;
14 import java.util.function.IntConsumer;
15
16 public class GoToController {
17 protected GoToView goToView;
18
19 public GoToController(Configuration configuration, JFrame mainFrame) {
20 // Create UI
21 goToView = new GoToView(configuration, mainFrame);
22 }
23
24 public void show(LineNumberNavigable navigator, IntConsumer okCallback) {
25 // Show
26 goToView.show(navigator, okCallback);
27 }
28 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.*;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.api.model.Indexes;
13 import org.jd.gui.model.configuration.Configuration;
14 import org.jd.gui.model.history.History;
15 import org.jd.gui.service.actions.ContextualActionsFactoryService;
16 import org.jd.gui.service.container.ContainerFactoryService;
17 import org.jd.gui.service.fileloader.FileLoaderService;
18 import org.jd.gui.service.indexer.IndexerService;
19 import org.jd.gui.service.mainpanel.PanelFactoryService;
20 import org.jd.gui.service.pastehandler.PasteHandlerService;
21 import org.jd.gui.service.platform.PlatformService;
22 import org.jd.gui.service.preferencespanel.PreferencesPanelService;
23 import org.jd.gui.service.sourceloader.SourceLoaderService;
24 import org.jd.gui.service.sourcesaver.SourceSaverService;
25 import org.jd.gui.service.treenode.TreeNodeFactoryService;
26 import org.jd.gui.service.type.TypeFactoryService;
27 import org.jd.gui.service.uriloader.UriLoaderService;
28 import org.jd.gui.spi.*;
29 import org.jd.gui.util.exception.ExceptionUtil;
30 import org.jd.gui.util.net.UriUtil;
31 import org.jd.gui.util.swing.SwingUtil;
32 import org.jd.gui.view.MainView;
33
34 import javax.swing.*;
35 import javax.swing.filechooser.FileNameExtensionFilter;
36 import javax.swing.filechooser.FileSystemView;
37 import java.awt.*;
38 import java.awt.datatransfer.DataFlavor;
39 import java.awt.datatransfer.Transferable;
40 import java.awt.event.ComponentAdapter;
41 import java.awt.event.ComponentEvent;
42 import java.io.File;
43 import java.io.FileOutputStream;
44 import java.io.IOException;
45 import java.io.OutputStream;
46 import java.net.URI;
47 import java.nio.file.Path;
48 import java.util.*;
49 import java.util.List;
50 import java.util.concurrent.Executors;
51 import java.util.concurrent.Future;
52 import java.util.concurrent.ScheduledExecutorService;
53 import java.util.concurrent.TimeUnit;
54
55 public class MainController implements API {
56 protected Configuration configuration;
57 protected MainView mainView;
58
59 protected GoToController goToController;
60 protected OpenTypeController openTypeController;
61 protected OpenTypeHierarchyController openTypeHierarchyController;
62 protected PreferencesController preferencesController;
63 protected SearchInConstantPoolsController searchInConstantPoolsController;
64 protected SaveAllSourcesController saveAllSourcesController;
65 protected SelectLocationController selectLocationController;
66 protected AboutController aboutController;
67 protected SourceLoaderService sourceLoaderService;
68
69 protected History history = new History();
70 protected JComponent currentPage = null;
71 protected ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
72 protected ArrayList<IndexesChangeListener> containerChangeListeners = new ArrayList<>();
73
74 @SuppressWarnings("unchecked")
75 public MainController(Configuration configuration) {
76 this.configuration = configuration;
77
78 SwingUtil.invokeLater(() -> {
79 if (PlatformService.getInstance().isLinux()) {
80 // Fix for GTKLookAndFeel
81 SwingUtil.installGtkPopupBugWorkaround();
82 }
83
84 // Create main frame
85 mainView = new MainView(
86 configuration, this, history,
87 e -> onOpen(),
88 e -> onClose(),
89 e -> onSaveSource(),
90 e -> onSaveAllSources(),
91 e -> System.exit(0),
92 e -> onCopy(),
93 e -> onPaste(),
94 e -> onSelectAll(),
95 e -> onFind(),
96 e -> onFindPrevious(),
97 e -> onFindNext(),
98 e -> onFindCriteriaChanged(),
99 () -> onFindCriteriaChanged(),
100 e -> onOpenType(),
101 e -> onOpenTypeHierarchy(),
102 e -> onGoTo(),
103 e -> openURI(history.backward()),
104 e -> openURI(history.forward()),
105 e -> onSearch(),
106 e -> onJdWebSite(),
107 e -> onJdGuiIssues(),
108 e -> onJdCoreIssues(),
109 e -> onPreferences(),
110 e -> onAbout(),
111 () -> panelClosed(),
112 page -> onCurrentPageChanged((JComponent)page),
113 file -> openFile((File)file));
114 });
115 }
116
117 // --- Show GUI --- //
118 @SuppressWarnings("unchecked")
119 public void show(List<File> files) {
120 SwingUtil.invokeLater(() -> {
121 // Show main frame
122 mainView.show(configuration.getMainWindowLocation(), configuration.getMainWindowSize(), configuration.isMainWindowMaximize());
123 if (!files.isEmpty()) {
124 openFiles(files);
125 }
126 });
127
128 // Background initializations
129 executor.schedule(() -> {
130 // Background service initialization
131 UriLoaderService.getInstance();
132 FileLoaderService.getInstance();
133 ContainerFactoryService.getInstance();
134 IndexerService.getInstance();
135 TreeNodeFactoryService.getInstance();
136 TypeFactoryService.getInstance();
137
138 SwingUtil.invokeLater(() -> {
139 // Populate recent files menu
140 mainView.updateRecentFilesMenu(configuration.getRecentFiles());
141 // Background controller creation
142 JFrame mainFrame = mainView.getMainFrame();
143 saveAllSourcesController = new SaveAllSourcesController(MainController.this, mainFrame);
144 containerChangeListeners.add(openTypeController = new OpenTypeController(MainController.this, executor, mainFrame));
145 containerChangeListeners.add(openTypeHierarchyController = new OpenTypeHierarchyController(MainController.this, executor, mainFrame));
146 goToController = new GoToController(configuration, mainFrame);
147 containerChangeListeners.add(searchInConstantPoolsController = new SearchInConstantPoolsController(MainController.this, executor, mainFrame));
148 preferencesController = new PreferencesController(configuration, mainFrame, PreferencesPanelService.getInstance().getProviders());
149 selectLocationController = new SelectLocationController(MainController.this, mainFrame);
150 aboutController = new AboutController(mainFrame);
151 sourceLoaderService = new SourceLoaderService();
152 // Add listeners
153 mainFrame.addComponentListener(new MainFrameListener(configuration));
154 // Set drop files transfer handler
155 mainFrame.setTransferHandler(new FilesTransferHandler());
156 // Background class loading
157 new JFileChooser().addChoosableFileFilter(new FileNameExtensionFilter("", "dummy"));
158 FileSystemView.getFileSystemView().isFileSystemRoot(new File("dummy"));
159 new JLayer();
160 });
161 }, 400, TimeUnit.MILLISECONDS);
162
163 PasteHandlerService.getInstance();
164 PreferencesPanelService.getInstance();
165 ContextualActionsFactoryService.getInstance();
166 SourceSaverService.getInstance();
167 }
168
169 // --- Actions --- //
170 protected void onOpen() {
171 Map<String, FileLoader> loaders = FileLoaderService.getInstance().getMapProviders();
172 StringBuilder sb = new StringBuilder();
173 ArrayList<String> extensions = new ArrayList<>(loaders.keySet());
174
175 extensions.sort(null);
176
177 for (String extension : extensions) {
178 sb.append("*.").append(extension).append(", ");
179 }
180
181 sb.setLength(sb.length()-2);
182
183 String description = sb.toString();
184 String[] array = extensions.toArray(new String[0]);
185 JFileChooser chooser = new JFileChooser();
186
187 chooser.removeChoosableFileFilter(chooser.getFileFilter());
188 chooser.addChoosableFileFilter(new FileNameExtensionFilter("All files (" + description + ")", array));
189
190 for (String extension : extensions) {
191 FileLoader loader = loaders.get(extension);
192 chooser.addChoosableFileFilter(new FileNameExtensionFilter(loader.getDescription(), loader.getExtensions()));
193 }
194
195 chooser.setCurrentDirectory(configuration.getRecentLoadDirectory());
196
197 if (chooser.showOpenDialog(mainView.getMainFrame()) == JFileChooser.APPROVE_OPTION) {
198 configuration.setRecentLoadDirectory(chooser.getCurrentDirectory());
199 openFile(chooser.getSelectedFile());
200 }
201 }
202
203 protected void onClose() {
204 mainView.closeCurrentTab();
205 }
206
207 protected void onSaveSource() {
208 if (currentPage instanceof ContentSavable) {
209 JFileChooser chooser = new JFileChooser();
210 JFrame mainFrame = mainView.getMainFrame();
211
212 chooser.setSelectedFile(new File(configuration.getRecentSaveDirectory(), ((ContentSavable)currentPage).getFileName()));
213
214 if (chooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
215 File selectedFile = chooser.getSelectedFile();
216
217 configuration.setRecentSaveDirectory(chooser.getCurrentDirectory());
218
219 if (selectedFile.exists()) {
220 String title = "Are you sure?";
221 String message = "The file '" + selectedFile.getAbsolutePath() + "' already isContainsIn.\n Do you want to replace the existing file?";
222
223 if (JOptionPane.showConfirmDialog(mainFrame, message, title, JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
224 save(selectedFile);
225 }
226 } else {
227 save(selectedFile);
228 }
229 }
230 }
231 }
232
233 protected void save(File selectedFile) {
234 try (OutputStream os = new FileOutputStream(selectedFile)) {
235 ((ContentSavable)currentPage).save(this, os);
236 } catch (IOException e) {
237 assert ExceptionUtil.printStackTrace(e);
238 }
239 }
240
241 protected void onSaveAllSources() {
242 if (! saveAllSourcesController.isActivated()) {
243 JComponent currentPanel = mainView.getSelectedMainPanel();
244
245 if (currentPanel instanceof SourcesSavable) {
246 SourcesSavable sourcesSavable = (SourcesSavable)currentPanel;
247 JFileChooser chooser = new JFileChooser();
248 JFrame mainFrame = mainView.getMainFrame();
249
250 chooser.setSelectedFile(new File(configuration.getRecentSaveDirectory(), sourcesSavable.getSourceFileName()));
251
252 if (chooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
253 File selectedFile = chooser.getSelectedFile();
254
255 configuration.setRecentSaveDirectory(chooser.getCurrentDirectory());
256
257 if (selectedFile.exists()) {
258 String title = "Are you sure?";
259 String message = "The file '" + selectedFile.getAbsolutePath() + "' already isContainsIn.\n Do you want to replace the existing file?";
260
261 if (JOptionPane.showConfirmDialog(mainFrame, message, title, JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
262 saveAllSourcesController.show(executor, sourcesSavable, selectedFile);
263 }
264 } else {
265 saveAllSourcesController.show(executor, sourcesSavable, selectedFile);
266 }
267 }
268 }
269 }
270 }
271
272 protected void onCopy() {
273 if (currentPage instanceof ContentCopyable) {
274 ((ContentCopyable)currentPage).copy();
275 }
276 }
277
278 protected void onPaste() {
279 try {
280 Transferable transferable = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
281
282 if ((transferable != null) && transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
283 Object obj = transferable.getTransferData(DataFlavor.stringFlavor);
284 PasteHandler pasteHandler = PasteHandlerService.getInstance().get(obj);
285
286 if (pasteHandler != null) {
287 pasteHandler.paste(this, obj);
288 }
289 }
290 } catch (Exception e) {
291 assert ExceptionUtil.printStackTrace(e);
292 }
293 }
294
295 protected void onSelectAll() {
296 if (currentPage instanceof ContentSelectable) {
297 ((ContentSelectable)currentPage).selectAll();
298 }
299 }
300
301 protected void onFind() {
302 if (currentPage instanceof ContentSearchable) {
303 mainView.showFindPanel();
304 }
305 }
306
307 protected void onFindCriteriaChanged() {
308 if (currentPage instanceof ContentSearchable) {
309 mainView.setFindBackgroundColor(((ContentSearchable)currentPage).highlightText(mainView.getFindText(), mainView.getFindCaseSensitive()));
310 }
311 }
312
313 protected void onFindNext() {
314 if (currentPage instanceof ContentSearchable) {
315 ((ContentSearchable)currentPage).findNext(mainView.getFindText(), mainView.getFindCaseSensitive());
316 }
317 }
318
319 protected void onOpenType() {
320 openTypeController.show(getCollectionOfFutureIndexes(), uri -> openURI(uri));
321 }
322
323 protected void onOpenTypeHierarchy() {
324 if (currentPage instanceof FocusedTypeGettable) {
325 FocusedTypeGettable ftg = (FocusedTypeGettable)currentPage;
326 openTypeHierarchyController.show(getCollectionOfFutureIndexes(), ftg.getEntry(), ftg.getFocusedTypeName(), uri -> openURI(uri));
327 }
328 }
329
330 protected void onGoTo() {
331 if (currentPage instanceof LineNumberNavigable) {
332 LineNumberNavigable lnn = (LineNumberNavigable)currentPage;
333 goToController.show(lnn, lineNumber -> lnn.goToLineNumber(lineNumber));
334 }
335 }
336
337 protected void onSearch() {
338 searchInConstantPoolsController.show(getCollectionOfFutureIndexes(), uri -> openURI(uri));
339 }
340
341 protected void onFindPrevious() {
342 if (currentPage instanceof ContentSearchable) {
343 ContentSearchable cs = (ContentSearchable)currentPage;
344 cs.findPrevious(mainView.getFindText(), mainView.getFindCaseSensitive());
345 }
346 }
347
348 protected void onJdWebSite() {
349 if (Desktop.isDesktopSupported()) {
350 Desktop desktop = Desktop.getDesktop();
351 if (desktop.isSupported(Desktop.Action.BROWSE)) {
352 try {
353 desktop.browse(URI.create("http://java-decompiler.github.io"));
354 } catch (IOException e) {
355 assert ExceptionUtil.printStackTrace(e);
356 }
357 }
358 }
359 }
360
361 protected void onJdGuiIssues() {
362 if (Desktop.isDesktopSupported()) {
363 Desktop desktop = Desktop.getDesktop();
364 if (desktop.isSupported(Desktop.Action.BROWSE)) {
365 try {
366 desktop.browse(URI.create("https://github.com/java-decompiler/jd-gui/issues"));
367 } catch (IOException e) {
368 assert ExceptionUtil.printStackTrace(e);
369 }
370 }
371 }
372 }
373
374 protected void onJdCoreIssues() {
375 if (Desktop.isDesktopSupported()) {
376 Desktop desktop = Desktop.getDesktop();
377 if (desktop.isSupported(Desktop.Action.BROWSE)) {
378 try {
379 desktop.browse(URI.create("https://github.com/java-decompiler/jd-core/issues"));
380 } catch (IOException e) {
381 assert ExceptionUtil.printStackTrace(e);
382 }
383 }
384 }
385 }
386
387 @SuppressWarnings("unchecked")
388 protected void onPreferences() {
389 preferencesController.show(() -> {
390 checkPreferencesChange(currentPage);
391 mainView.preferencesChanged(getPreferences());
392 });
393 }
394
395 protected void onAbout() {
396 aboutController.show();
397 }
398
399 protected void onCurrentPageChanged(JComponent page) {
400 currentPage = page;
401 checkPreferencesChange(page);
402 checkIndexesChange(page);
403 }
404
405 protected void checkPreferencesChange(JComponent page) {
406 if (page instanceof PreferencesChangeListener) {
407 Map<String, String> preferences = configuration.getPreferences();
408 Integer currentHashcode = Integer.valueOf(preferences.hashCode());
409 Integer lastHashcode = (Integer)page.getClientProperty("preferences-hashCode");
410
411 if (!currentHashcode.equals(lastHashcode)) {
412 ((PreferencesChangeListener)page).preferencesChanged(preferences);
413 page.putClientProperty("preferences-hashCode", currentHashcode);
414 }
415 }
416 }
417
418 protected void checkIndexesChange(JComponent page) {
419 if (page instanceof IndexesChangeListener) {
420 Collection<Future<Indexes>> collectionOfFutureIndexes = getCollectionOfFutureIndexes();
421 Integer currentHashcode = Integer.valueOf(collectionOfFutureIndexes.hashCode());
422 Integer lastHashcode = (Integer)page.getClientProperty("collectionOfFutureIndexes-hashCode");
423
424 if (!currentHashcode.equals(lastHashcode)) {
425 ((IndexesChangeListener)page).indexesChanged(collectionOfFutureIndexes);
426 page.putClientProperty("collectionOfFutureIndexes-hashCode", currentHashcode);
427 }
428 }
429 }
430
431 // --- Operations --- //
432 public void openFile(File file) {
433 openFiles(Collections.singletonList(file));
434 }
435
436 @SuppressWarnings("unchecked")
437 public void openFiles(List<File> files) {
438 ArrayList<String> errors = new ArrayList<>();
439
440 for (File file : files) {
441 // Check input file
442 if (file.exists()) {
443 FileLoader loader = getFileLoader(file);
444 if ((loader != null) && !loader.accept(this, file)) {
445 errors.add("Invalid input fileloader: '" + file.getAbsolutePath() + "'");
446 }
447 } else {
448 errors.add("File not found: '" + file.getAbsolutePath() + "'");
449 }
450 }
451
452 if (errors.isEmpty()) {
453 for (File file : files) {
454 if (openURI(file.toURI())) {
455 configuration.addRecentFile(file);
456 mainView.updateRecentFilesMenu(configuration.getRecentFiles());
457 }
458 }
459 } else {
460 StringBuilder messages = new StringBuilder();
461 int index = 0;
462
463 for (String error : errors) {
464 if (index > 0) {
465 messages.append('\n');
466 }
467 if (index >= 20) {
468 messages.append("...");
469 break;
470 }
471 messages.append(error);
472 index++;
473 }
474
475 JOptionPane.showMessageDialog(mainView.getMainFrame(), messages.toString(), "Error", JOptionPane.ERROR_MESSAGE);
476 }
477 }
478
479 // --- Drop files transfer handler --- //
480 protected class FilesTransferHandler extends TransferHandler {
481 @Override
482 public boolean canImport(TransferHandler.TransferSupport info) {
483 return info.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
484 }
485
486 @Override
487 @SuppressWarnings("unchecked")
488 public boolean importData(TransferHandler.TransferSupport info) {
489 if (info.isDrop() && info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
490 try {
491 openFiles((List<File>)info.getTransferable().getTransferData(DataFlavor.javaFileListFlavor));
492 return true;
493 } catch (Exception e) {
494 assert ExceptionUtil.printStackTrace(e);
495 }
496 }
497 return false;
498 }
499 }
500
501 // --- ComponentListener --- //
502 protected class MainFrameListener extends ComponentAdapter {
503 protected Configuration configuration;
504
505 public MainFrameListener(Configuration configuration) {
506 this.configuration = configuration;
507 }
508
509 @Override
510 public void componentMoved(ComponentEvent e) {
511 JFrame mainFrame = mainView.getMainFrame();
512
513 if ((mainFrame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
514 configuration.setMainWindowMaximize(true);
515 } else {
516 configuration.setMainWindowLocation(mainFrame.getLocation());
517 configuration.setMainWindowMaximize(false);
518 }
519 }
520
521 @Override
522 public void componentResized(ComponentEvent e) {
523 JFrame mainFrame = mainView.getMainFrame();
524
525 if ((mainFrame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
526 configuration.setMainWindowMaximize(true);
527 } else {
528 configuration.setMainWindowSize(mainFrame.getSize());
529 configuration.setMainWindowMaximize(false);
530 }
531 }
532 }
533
534 protected void panelClosed() {
535 SwingUtil.invokeLater(() -> {
536 // Fire 'indexesChanged' event
537 Collection<Future<Indexes>> collectionOfFutureIndexes = getCollectionOfFutureIndexes();
538 for (IndexesChangeListener listener : containerChangeListeners) {
539 listener.indexesChanged(collectionOfFutureIndexes);
540 }
541 if (currentPage instanceof IndexesChangeListener) {
542 ((IndexesChangeListener)currentPage).indexesChanged(collectionOfFutureIndexes);
543 }
544 });
545 }
546
547 // --- API --- //
548 @Override
549 @SuppressWarnings("unchecked")
550 public boolean openURI(URI uri) {
551 if (uri != null) {
552 boolean success = mainView.openUri(uri);
553
554 if (success == false) {
555 UriLoader uriLoader = getUriLoader(uri);
556 if (uriLoader != null) {
557 success = uriLoader.load(this, uri);
558 }
559 }
560
561 if (success) {
562 addURI(uri);
563 }
564
565 return success;
566 }
567
568 return false;
569 }
570
571 @Override
572 public boolean openURI(int x, int y, Collection<Container.Entry> entries, String query, String fragment) {
573 if (entries != null) {
574 if (entries.size() == 1) {
575 // Open the single entry uri
576 Container.Entry entry = entries.iterator().next();
577 return openURI(UriUtil.createURI(this, getCollectionOfFutureIndexes(), entry, query, fragment));
578 } else {
579 // Multiple entries -> Open a "Select location" popup
580 Collection<Future<Indexes>> collectionOfFutureIndexes = getCollectionOfFutureIndexes();
581 selectLocationController.show(
582 new Point(x+(16+2), y+2),
583 entries,
584 entry -> openURI(UriUtil.createURI(this, collectionOfFutureIndexes, entry, query, fragment)), // entry selected closure
585 () -> {}); // popup close closure
586 return true;
587 }
588 }
589
590 return false;
591 }
592
593 @Override
594 public void addURI(URI uri) {
595 history.add(uri);
596 SwingUtil.invokeLater(() -> {
597 mainView.updateHistoryActions();
598 });
599 }
600
601 @Override
602 @SuppressWarnings("unchecked")
603 public <T extends JComponent & UriGettable> void addPanel(String title, Icon icon, String tip, T component) {
604 mainView.addMainPanel(title, icon, tip, component);
605
606 if (component instanceof ContentIndexable) {
607 Future<Indexes> futureIndexes = executor.submit(() -> {
608 Indexes indexes = ((ContentIndexable)component).index(this);
609
610 SwingUtil.invokeLater(() -> {
611 // Fire 'indexesChanged' event
612 Collection<Future<Indexes>> collectionOfFutureIndexes = getCollectionOfFutureIndexes();
613 for (IndexesChangeListener listener : containerChangeListeners) {
614 listener.indexesChanged(collectionOfFutureIndexes);
615 }
616 if (currentPage instanceof IndexesChangeListener) {
617 ((IndexesChangeListener) currentPage).indexesChanged(collectionOfFutureIndexes);
618 }
619 });
620
621 return indexes;
622 });
623
624 component.putClientProperty("indexes", futureIndexes);
625 }
626 }
627
628 @Override public Collection<Action> getContextualActions(Container.Entry entry, String fragment) { return ContextualActionsFactoryService.getInstance().get(this, entry, fragment); }
629
630 @Override public FileLoader getFileLoader(File file) { return FileLoaderService.getInstance().get(this, file); }
631
632 @Override public UriLoader getUriLoader(URI uri) { return UriLoaderService.getInstance().get(this, uri); }
633
634 @Override public PanelFactory getMainPanelFactory(Container container) { return PanelFactoryService.getInstance().get(container); }
635
636 @Override public ContainerFactory getContainerFactory(Path rootPath) { return ContainerFactoryService.getInstance().get(this, rootPath); }
637
638 @Override public TreeNodeFactory getTreeNodeFactory(Container.Entry entry) { return TreeNodeFactoryService.getInstance().get(entry); }
639
640 @Override public TypeFactory getTypeFactory(Container.Entry entry) { return TypeFactoryService.getInstance().get(entry); }
641
642 @Override public Indexer getIndexer(Container.Entry entry) { return IndexerService.getInstance().get(entry); }
643
644 @Override public SourceSaver getSourceSaver(Container.Entry entry) { return SourceSaverService.getInstance().get(entry); }
645
646 @Override public Map<String, String> getPreferences() { return configuration.getPreferences(); }
647
648 @Override
649 @SuppressWarnings("unchecked")
650 public Collection<Future<Indexes>> getCollectionOfFutureIndexes() {
651 List<JComponent> mainPanels = mainView.getMainPanels();
652 ArrayList<Future<Indexes>> list = new ArrayList<Future<Indexes>>(mainPanels.size()) {
653 @Override
654 public int hashCode() {
655 int hashCode = 1;
656
657 try {
658 for (Future<Indexes> futureIndexes : this) {
659 hashCode *= 31;
660
661 if (futureIndexes.isDone()) {
662 hashCode += futureIndexes.get().hashCode();
663 }
664 }
665 } catch (Exception e) {
666 assert ExceptionUtil.printStackTrace(e);
667 }
668
669 return hashCode;
670 }
671 };
672
673 for (JComponent panel : mainPanels) {
674 Future<Indexes> futureIndexes = (Future<Indexes>)panel.getClientProperty("indexes");
675 if (futureIndexes != null) {
676 list.add(futureIndexes);
677 }
678 }
679
680 return list;
681 }
682
683 @Override
684 public String getSource(Container.Entry entry) {
685 return sourceLoaderService.getSource(this, entry);
686 }
687
688 @Override
689 public void loadSource(Container.Entry entry, LoadSourceListener listener) {
690 executor.execute(() -> {
691 String source = sourceLoaderService.loadSource(this, entry);
692
693 if ((source != null) && !source.isEmpty()) {
694 listener.sourceLoaded(source);
695 }
696 });
697 }
698
699 @Override
700 public File loadSourceFile(Container.Entry entry) {
701 return sourceLoaderService.getSourceFile(this, entry);
702 }
703 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.IndexesChangeListener;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.api.model.Indexes;
13 import org.jd.gui.util.exception.ExceptionUtil;
14 import org.jd.gui.util.net.UriUtil;
15 import org.jd.gui.view.OpenTypeView;
16
17 import javax.swing.*;
18 import java.awt.*;
19 import java.net.URI;
20 import java.util.*;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.function.Consumer;
24 import java.util.regex.Pattern;
25
26 public class OpenTypeController implements IndexesChangeListener {
27 protected static final int CACHE_MAX_ENTRIES = 5*20;
28
29 protected API api;
30 protected ScheduledExecutorService executor;
31 protected Collection<Future<Indexes>> collectionOfFutureIndexes;
32 protected Consumer<URI> openCallback;
33
34 protected JFrame mainFrame;
35 protected OpenTypeView openTypeView;
36 protected SelectLocationController selectLocationController;
37
38 protected long indexesHashCode = 0L;
39 protected Map<String, Map<String, Collection>> cache;
40
41 public OpenTypeController(API api, ScheduledExecutorService executor, JFrame mainFrame) {
42 this.api = api;
43 this.executor = executor;
44 this.mainFrame = mainFrame;
45 // Create UI
46 openTypeView = new OpenTypeView(api, mainFrame, this::updateList, this::onTypeSelected);
47 selectLocationController = new SelectLocationController(api, mainFrame);
48 // Create result cache
49 cache = new LinkedHashMap<String, Map<String, Collection>>(CACHE_MAX_ENTRIES*3/2, 0.7f, true) {
50 @Override
51 protected boolean removeEldestEntry(Map.Entry<String, Map<String, Collection>> eldest) {
52 return size() > CACHE_MAX_ENTRIES;
53 }
54 };
55 }
56
57 public void show(Collection<Future<Indexes>> collectionOfFutureIndexes, Consumer<URI> openCallback) {
58 // Init attributes
59 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
60 this.openCallback = openCallback;
61 // Refresh view
62 long hashCode = collectionOfFutureIndexes.hashCode();
63 if (hashCode != indexesHashCode) {
64 // List of indexes has changed -> Refresh result list
65 updateList(openTypeView.getPattern());
66 indexesHashCode = hashCode;
67 }
68 // Show
69 openTypeView.show();
70 }
71
72 @SuppressWarnings("unchecked")
73 protected void updateList(String pattern) {
74 int patternLength = pattern.length();
75
76 if (patternLength == 0) {
77 // Display
78 openTypeView.updateList(Collections.emptyMap());
79 } else {
80 executor.execute(() -> {
81 // Waiting the end of indexation...
82 openTypeView.showWaitCursor();
83
84 Pattern regExpPattern = createRegExpPattern(pattern);
85 Map<String, Collection<Container.Entry>> result = new HashMap<>();
86
87 try {
88 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
89 if (futureIndexes.isDone()) {
90 Indexes indexes = futureIndexes.get();
91 String key = String.valueOf(indexes.hashCode()) + "***" + pattern;
92 Map<String, Collection> matchingEntries = cache.get(key);
93
94 if (matchingEntries != null) {
95 // Merge 'result' and 'matchingEntries'
96 for (Map.Entry<String, Collection> mapEntry : matchingEntries.entrySet()) {
97 Collection<Container.Entry> collection = result.get(mapEntry.getKey());
98 if (collection == null) {
99 result.put(mapEntry.getKey(), collection = new HashSet<>());
100 }
101 collection.addAll(mapEntry.getValue());
102 }
103 } else {
104 // Waiting the end of indexation...
105 Map<String, Collection> index = indexes.getIndex("typeDeclarations");
106
107 if ((index != null) && !index.isEmpty()) {
108 matchingEntries = new HashMap<>();
109
110 // Filter
111 if (patternLength == 1) {
112 match(pattern.charAt(0), index, matchingEntries);
113 } else {
114 String lastKey = key.substring(0, patternLength - 1);
115 Map<String, Collection> lastResult = cache.get(lastKey);
116
117 if (lastResult != null) {
118 match(regExpPattern, lastResult, matchingEntries);
119 } else {
120 match(regExpPattern, index, matchingEntries);
121 }
122 }
123
124 // Store 'matchingEntries'
125 cache.put(key, matchingEntries);
126
127 // Merge 'result' and 'matchingEntries'
128 for (Map.Entry<String, Collection> mapEntry : matchingEntries.entrySet()) {
129 Collection<Container.Entry> collection = result.get(mapEntry.getKey());
130 if (collection == null) {
131 result.put(mapEntry.getKey(), collection = new HashSet<>());
132 }
133 collection.addAll(mapEntry.getValue());
134 }
135 }
136 }
137 }
138 }
139 } catch (Exception e) {
140 assert ExceptionUtil.printStackTrace(e);
141 }
142
143 SwingUtilities.invokeLater(() -> {
144 openTypeView.hideWaitCursor();
145 // Display
146 openTypeView.updateList(result);
147 });
148 });
149 }
150 }
151
152 @SuppressWarnings("unchecked")
153 protected static void match(char c, Map<String, Collection> index, Map<String, Collection> result) {
154 // Filter
155 if (Character.isLowerCase(c)) {
156 char upperCase = Character.toUpperCase(c);
157
158 for (Map.Entry<String, Collection> mapEntry : index.entrySet()) {
159 String typeName = mapEntry.getKey();
160 Collection<Container.Entry> entries = mapEntry.getValue();
161 // Search last package separator
162 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
163 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
164 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
165
166 if (lastIndex < typeName.length()) {
167 char first = typeName.charAt(lastIndex);
168
169 if ((first == c) || (first == upperCase)) {
170 add(result, typeName, entries);
171 }
172 }
173 }
174 } else {
175 for (Map.Entry<String, Collection> mapEntry : index.entrySet()) {
176 String typeName = mapEntry.getKey();
177 Collection<Container.Entry> entries = mapEntry.getValue();
178 // Search last package separator
179 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
180 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
181 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
182
183 if ((lastIndex < typeName.length()) && (typeName.charAt(lastIndex) == c)) {
184 add(result, typeName, entries);
185 }
186 }
187 }
188 }
189
190 /**
191 * Create a regular expression to match package, type and inner type name.
192 *
193 * Rules:
194 * '*' matches 0 ou N characters
195 * '?' matches 1 character
196 * lower case matches insensitive case
197 * upper case matches upper case
198 */
199 protected static Pattern createRegExpPattern(String pattern) {
200 // Create regular expression
201 int patternLength = pattern.length();
202 StringBuilder sbPattern = new StringBuilder(patternLength * 4);
203
204 for (int i=0; i<patternLength; i++) {
205 char c = pattern.charAt(i);
206
207 if (Character.isUpperCase(c)) {
208 if (i > 1) {
209 sbPattern.append(".*");
210 }
211 sbPattern.append(c);
212 } else if (Character.isLowerCase(c)) {
213 sbPattern.append('[').append(c).append(Character.toUpperCase(c)).append(']');
214 } else if (c == '*') {
215 sbPattern.append(".*");
216 } else if (c == '?') {
217 sbPattern.append(".");
218 } else {
219 sbPattern.append(c);
220 }
221 }
222
223 sbPattern.append(".*");
224
225 return Pattern.compile(sbPattern.toString());
226 }
227
228 @SuppressWarnings("unchecked")
229 protected static void match(Pattern regExpPattern, Map<String, Collection> index, Map<String, Collection> result) {
230 for (Map.Entry<String, Collection> mapEntry : index.entrySet()) {
231 String typeName = mapEntry.getKey();
232 Collection<Container.Entry> entries = mapEntry.getValue();
233 // Search last package separator
234 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
235 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
236 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
237
238 if (regExpPattern.matcher(typeName.substring(lastIndex)).matches()) {
239 add(result, typeName, entries);
240 }
241 }
242 }
243
244 @SuppressWarnings("unchecked")
245 protected static void add(Map<String, Collection> map, String key, Collection value) {
246 Collection<Container.Entry> collection = map.get(key);
247
248 if (collection == null) {
249 map.put(key, collection = new HashSet<>());
250 }
251
252 collection.addAll(value);
253 }
254
255 protected void onTypeSelected(Point leftBottom, Collection<Container.Entry> entries, String typeName) {
256 if (entries.size() == 1) {
257 // Open the single entry uri
258 openCallback.accept(UriUtil.createURI(api, collectionOfFutureIndexes, entries.iterator().next(), null, typeName));
259 } else {
260 // Multiple entries -> Open a "Select location" popup
261 selectLocationController.show(
262 new Point(leftBottom.x+(16+2), leftBottom.y+2),
263 entries,
264 (entry) -> openCallback.accept(UriUtil.createURI(api, collectionOfFutureIndexes, entry, null, typeName)), // entry selected callback
265 () -> openTypeView.focus()); // popup close callback
266 }
267 }
268
269 // --- IndexesChangeListener --- //
270 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
271 if (openTypeView.isVisible()) {
272 // Update the list of containers
273 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
274 // And refresh
275 updateList(openTypeView.getPattern());
276 }
277 }
278 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.IndexesChangeListener;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.api.model.Indexes;
13 import org.jd.gui.util.net.UriUtil;
14 import org.jd.gui.view.OpenTypeHierarchyView;
15
16 import javax.swing.*;
17 import java.awt.*;
18 import java.net.URI;
19 import java.util.Collection;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.ScheduledExecutorService;
22 import java.util.function.Consumer;
23
24 public class OpenTypeHierarchyController implements IndexesChangeListener {
25 protected API api;
26 private ScheduledExecutorService executor;
27
28 protected JFrame mainFrame;
29 protected OpenTypeHierarchyView openTypeHierarchyView;
30 protected SelectLocationController selectLocationController;
31
32 protected Collection<Future<Indexes>> collectionOfFutureIndexes;
33 protected Consumer<URI> openCallback;
34
35 public OpenTypeHierarchyController(API api, ScheduledExecutorService executor, JFrame mainFrame) {
36 this.api = api;
37 this.executor = executor;
38 this.mainFrame = mainFrame;
39 // Create UI
40 openTypeHierarchyView = new OpenTypeHierarchyView(api, mainFrame, this::onTypeSelected);
41 selectLocationController = new SelectLocationController(api, mainFrame);
42 }
43
44 public void show(Collection<Future<Indexes>> collectionOfFutureIndexes, Container.Entry entry, String typeName, Consumer<URI> openCallback) {
45 // Init attributes
46 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
47 this.openCallback = openCallback;
48 executor.execute(() -> {
49 // Waiting the end of indexation...
50 openTypeHierarchyView.showWaitCursor();
51 SwingUtilities.invokeLater(() -> {
52 openTypeHierarchyView.hideWaitCursor();
53 // Show
54 openTypeHierarchyView.show(collectionOfFutureIndexes, entry, typeName);
55 });
56 });
57 }
58
59 protected void onTypeSelected(Point leftBottom, Collection<Container.Entry> entries, String typeName) {
60 if (entries.size() == 1) {
61 // Open the single entry uri
62 openCallback.accept(UriUtil.createURI(api, collectionOfFutureIndexes, entries.iterator().next(), null, typeName));
63 } else {
64 // Multiple entries -> Open a "Select location" popup
65 selectLocationController.show(
66 new Point(leftBottom.x+(16+2), leftBottom.y+2),
67 entries,
68 (entry) -> openCallback.accept(UriUtil.createURI(api, collectionOfFutureIndexes, entry, null, typeName)), // entry selected
69 () -> openTypeHierarchyView.focus()); // popup closeClosure
70 }
71 }
72
73 // --- IndexesChangeListener --- //
74 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
75 if (openTypeHierarchyView.isVisible()) {
76 // Update the list of containers
77 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
78 // And refresh
79 openTypeHierarchyView.updateTree(collectionOfFutureIndexes);
80 }
81 }
82 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.model.configuration.Configuration;
10 import org.jd.gui.spi.PreferencesPanel;
11 import org.jd.gui.view.PreferencesView;
12
13 import javax.swing.*;
14 import java.util.Collection;
15
16 public class PreferencesController {
17 protected PreferencesView preferencesView;
18
19 public PreferencesController(Configuration configuration, JFrame mainFrame, Collection<PreferencesPanel> panels) {
20 // Create UI
21 preferencesView = new PreferencesView(configuration, mainFrame, panels);
22 }
23
24 public void show(Runnable okCallback) {
25 // Show
26 preferencesView.show(okCallback);
27 }
28 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.SourcesSavable;
11 import org.jd.gui.util.exception.ExceptionUtil;
12 import org.jd.gui.view.SaveAllSourcesView;
13
14 import javax.swing.*;
15 import java.io.File;
16 import java.nio.file.Files;
17 import java.nio.file.Path;
18 import java.nio.file.Paths;
19 import java.util.concurrent.ScheduledExecutorService;
20
21 public class SaveAllSourcesController implements SourcesSavable.Controller, SourcesSavable.Listener {
22 protected API api;
23 protected SaveAllSourcesView saveAllSourcesView;
24 protected boolean cancel;
25 protected int counter;
26 protected int mask;
27
28 public SaveAllSourcesController(API api, JFrame mainFrame) {
29 this.api = api;
30 // Create UI
31 this.saveAllSourcesView = new SaveAllSourcesView(mainFrame, this::onCanceled);
32 }
33
34 public void show(ScheduledExecutorService executor, SourcesSavable savable, File file) {
35 // Show
36 this.saveAllSourcesView.show(file);
37 // Execute background task
38 executor.execute(() -> {
39 int fileCount = savable.getFileCount();
40
41 saveAllSourcesView.updateProgressBar(0);
42 saveAllSourcesView.setMaxValue(fileCount);
43
44 cancel = false;
45 counter = 0;
46 mask = 2;
47
48 while (fileCount > 64) {
49 fileCount >>= 1;
50 mask <<= 1;
51 }
52
53 mask--;
54
55 try {
56 Path path = Paths.get(file.toURI());
57 Files.deleteIfExists(path);
58
59 try {
60 savable.save(api, this, this, path);
61 } catch (Exception e) {
62 assert ExceptionUtil.printStackTrace(e);
63 saveAllSourcesView.showActionFailedDialog();
64 cancel = true;
65 }
66
67 if (cancel) {
68 Files.deleteIfExists(path);
69 }
70 } catch (Throwable t) {
71 assert ExceptionUtil.printStackTrace(t);
72 }
73
74 saveAllSourcesView.hide();
75 });
76 }
77
78 public boolean isActivated() { return saveAllSourcesView.isVisible(); }
79
80 protected void onCanceled() { cancel = true; }
81
82 // --- SourcesSavable.Controller --- //
83 @Override public boolean isCancelled() { return cancel; }
84
85 // --- SourcesSavable.Listener --- //
86 @Override
87 public void pathSaved(Path path) {
88 if (((counter++) & mask) == 0) {
89 saveAllSourcesView.updateProgressBar(counter);
90 }
91 }
92 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.IndexesChangeListener;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.api.model.Indexes;
13 import org.jd.gui.api.model.Type;
14 import org.jd.gui.model.container.DelegatingFilterContainer;
15 import org.jd.gui.service.type.TypeFactoryService;
16 import org.jd.gui.spi.TypeFactory;
17 import org.jd.gui.util.exception.ExceptionUtil;
18 import org.jd.gui.util.function.TriConsumer;
19 import org.jd.gui.view.SearchInConstantPoolsView;
20
21 import javax.swing.*;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.util.*;
25 import java.util.concurrent.Future;
26 import java.util.concurrent.ScheduledExecutorService;
27 import java.util.function.BiConsumer;
28 import java.util.function.BiFunction;
29 import java.util.function.Consumer;
30 import java.util.regex.Pattern;
31
32 public class SearchInConstantPoolsController implements IndexesChangeListener {
33 protected static final int CACHE_MAX_ENTRIES = 5*20*9;
34
35 protected API api;
36 protected ScheduledExecutorService executor;
37
38 protected JFrame mainFrame;
39 protected SearchInConstantPoolsView searchInConstantPoolsView;
40 protected Map<String, Map<String, Collection>> cache;
41 protected Set<DelegatingFilterContainer> delegatingFilterContainers = new HashSet<>();
42 protected Collection<Future<Indexes>> collectionOfFutureIndexes;
43 protected Consumer<URI> openCallback;
44 protected long indexesHashCode = 0L;
45
46 @SuppressWarnings("unchecked")
47 public SearchInConstantPoolsController(API api, ScheduledExecutorService executor, JFrame mainFrame) {
48 this.api = api;
49 this.executor = executor;
50 this.mainFrame = mainFrame;
51 // Create UI
52 this.searchInConstantPoolsView = new SearchInConstantPoolsView(
53 api, mainFrame,
54 new BiConsumer<String, Integer>() {
55 @Override public void accept(String pattern, Integer flags) { updateTree(pattern, flags); }
56 },
57 new TriConsumer<URI, String, Integer>() {
58 @Override public void accept(URI uri, String pattern, Integer flags) { onTypeSelected(uri, pattern, flags); }
59 }
60 );
61 // Create result cache
62 this.cache = new LinkedHashMap<String, Map<String, Collection>>(CACHE_MAX_ENTRIES*3/2, 0.7f, true) {
63 @Override
64 protected boolean removeEldestEntry(Map.Entry<String, Map<String, Collection>> eldest) {
65 return size() > CACHE_MAX_ENTRIES;
66 }
67 };
68 }
69
70 public void show(Collection<Future<Indexes>> collectionOfFutureIndexes, Consumer<URI> openCallback) {
71 // Init attributes
72 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
73 this.openCallback = openCallback;
74 // Refresh view
75 long hashCode = collectionOfFutureIndexes.hashCode();
76 if (hashCode != indexesHashCode) {
77 // List of indexes has changed
78 updateTree(searchInConstantPoolsView.getPattern(), searchInConstantPoolsView.getFlags());
79 indexesHashCode = hashCode;
80 }
81 // Show
82 searchInConstantPoolsView.show();
83 }
84
85 @SuppressWarnings("unchecked")
86 protected void updateTree(String pattern, int flags) {
87 delegatingFilterContainers.clear();
88
89 executor.execute(() -> {
90 // Waiting the end of indexation...
91 searchInConstantPoolsView.showWaitCursor();
92
93 int matchingTypeCount = 0;
94 int patternLength = pattern.length();
95
96 if (patternLength > 0) {
97 try {
98 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
99 if (futureIndexes.isDone()) {
100 Indexes indexes = futureIndexes.get();
101 HashSet<Container.Entry> matchingEntries = new HashSet<>();
102 // Find matched entries
103 filter(indexes, pattern, flags, matchingEntries);
104
105 if (!matchingEntries.isEmpty()) {
106 // Search root container with first matching entry
107 Container.Entry parentEntry = matchingEntries.iterator().next();
108 Container container = null;
109
110 while (parentEntry.getContainer().getRoot() != null) {
111 container = parentEntry.getContainer();
112 parentEntry = container.getRoot().getParent();
113 }
114
115 // TODO In a future release, display matching strings, types, inner-types, fields and methods, not only matching files
116 matchingEntries = getOuterEntries(matchingEntries);
117
118 matchingTypeCount += matchingEntries.size();
119
120 // Create a filtered container
121 delegatingFilterContainers.add(new DelegatingFilterContainer(container, matchingEntries));
122 }
123 }
124 }
125 } catch (Exception e) {
126 assert ExceptionUtil.printStackTrace(e);
127 }
128 }
129
130 final int count = matchingTypeCount;
131
132 searchInConstantPoolsView.hideWaitCursor();
133 searchInConstantPoolsView.updateTree(delegatingFilterContainers, count);
134 });
135 }
136
137 protected HashSet<Container.Entry> getOuterEntries(Set<Container.Entry> matchingEntries) {
138 HashMap<Container.Entry, Container.Entry> innerTypeEntryToOuterTypeEntry = new HashMap<>();
139 HashSet<Container.Entry> matchingOuterEntriesSet = new HashSet<>();
140
141 for (Container.Entry entry : matchingEntries) {
142 TypeFactory typeFactory = TypeFactoryService.getInstance().get(entry);
143
144 if (typeFactory != null) {
145 Type type = typeFactory.make(api, entry, null);
146
147 if ((type != null) && (type.getOuterName() != null)) {
148 Container.Entry outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry);
149
150 if (outerTypeEntry == null) {
151 HashMap<String, Container.Entry> typeNameToEntry = new HashMap<>();
152 HashMap<String, String> innerTypeNameToOuterTypeName = new HashMap<>();
153
154 // Populate "typeNameToEntry" and "innerTypeNameToOuterTypeName"
155 for (Container.Entry e : entry.getParent().getChildren()) {
156 typeFactory = TypeFactoryService.getInstance().get(e);
157
158 if (typeFactory != null) {
159 type = typeFactory.make(api, e, null);
160
161 if (type != null) {
162 typeNameToEntry.put(type.getName(), e);
163 if (type.getOuterName() != null) {
164 innerTypeNameToOuterTypeName.put(type.getName(), type.getOuterName());
165 }
166 }
167 }
168 }
169
170 // Search outer type entries and populate "innerTypeEntryToOuterTypeEntry"
171 for (Map.Entry<String, String> e : innerTypeNameToOuterTypeName.entrySet()) {
172 Container.Entry innerTypeEntry = typeNameToEntry.get(e.getKey());
173
174 if (innerTypeEntry != null) {
175 String outerTypeName = e.getValue();
176
177 for (;;) {
178 String typeName = innerTypeNameToOuterTypeName.get(outerTypeName);
179 if (typeName != null) {
180 outerTypeName = typeName;
181 } else {
182 break;
183 }
184 }
185
186 outerTypeEntry = typeNameToEntry.get(outerTypeName);
187
188 if (outerTypeEntry != null) {
189 innerTypeEntryToOuterTypeEntry.put(innerTypeEntry, outerTypeEntry);
190 }
191 }
192 }
193
194 // Get outer type entry
195 outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry);
196
197 if (outerTypeEntry == null) {
198 outerTypeEntry = entry;
199 }
200 }
201
202 matchingOuterEntriesSet.add(outerTypeEntry);
203 } else{
204 matchingOuterEntriesSet.add(entry);
205 }
206 }
207 }
208
209 return matchingOuterEntriesSet;
210 }
211
212 protected void filter(Indexes indexes, String pattern, int flags, Set<Container.Entry> matchingEntries) {
213 boolean declarations = ((flags & SearchInConstantPoolsView.SEARCH_DECLARATION) != 0);
214 boolean references = ((flags & SearchInConstantPoolsView.SEARCH_REFERENCE) != 0);
215
216 if ((flags & SearchInConstantPoolsView.SEARCH_TYPE) != 0) {
217 if (declarations)
218 match(indexes, "typeDeclarations", pattern,
219 SearchInConstantPoolsController::matchTypeEntriesWithChar,
220 SearchInConstantPoolsController::matchTypeEntriesWithString, matchingEntries);
221 if (references)
222 match(indexes, "typeReferences", pattern,
223 SearchInConstantPoolsController::matchTypeEntriesWithChar,
224 SearchInConstantPoolsController::matchTypeEntriesWithString, matchingEntries);
225 }
226
227 if ((flags & SearchInConstantPoolsView.SEARCH_CONSTRUCTOR) != 0) {
228 if (declarations)
229 match(indexes, "constructorDeclarations", pattern,
230 SearchInConstantPoolsController::matchTypeEntriesWithChar,
231 SearchInConstantPoolsController::matchTypeEntriesWithString, matchingEntries);
232 if (references)
233 match(indexes, "constructorReferences", pattern,
234 SearchInConstantPoolsController::matchTypeEntriesWithChar,
235 SearchInConstantPoolsController::matchTypeEntriesWithString, matchingEntries);
236 }
237
238 if ((flags & SearchInConstantPoolsView.SEARCH_METHOD) != 0) {
239 if (declarations)
240 match(indexes, "methodDeclarations", pattern,
241 SearchInConstantPoolsController::matchWithChar,
242 SearchInConstantPoolsController::matchWithString, matchingEntries);
243 if (references)
244 match(indexes, "methodReferences", pattern,
245 SearchInConstantPoolsController::matchWithChar,
246 SearchInConstantPoolsController::matchWithString, matchingEntries);
247 }
248
249 if ((flags & SearchInConstantPoolsView.SEARCH_FIELD) != 0) {
250 if (declarations)
251 match(indexes, "fieldDeclarations", pattern,
252 SearchInConstantPoolsController::matchWithChar,
253 SearchInConstantPoolsController::matchWithString, matchingEntries);
254 if (references)
255 match(indexes, "fieldReferences", pattern,
256 SearchInConstantPoolsController::matchWithChar,
257 SearchInConstantPoolsController::matchWithString, matchingEntries);
258 }
259
260 if ((flags & SearchInConstantPoolsView.SEARCH_STRING) != 0) {
261 if (declarations || references)
262 match(indexes, "strings", pattern,
263 SearchInConstantPoolsController::matchWithChar,
264 SearchInConstantPoolsController::matchWithString, matchingEntries);
265 }
266
267 if ((flags & SearchInConstantPoolsView.SEARCH_MODULE) != 0) {
268 if (declarations)
269 match(indexes, "javaModuleDeclarations", pattern,
270 SearchInConstantPoolsController::matchWithChar,
271 SearchInConstantPoolsController::matchWithString, matchingEntries);
272 if (references)
273 match(indexes, "javaModuleReferences", pattern,
274 SearchInConstantPoolsController::matchWithChar,
275 SearchInConstantPoolsController::matchWithString, matchingEntries);
276 }
277 }
278
279 @SuppressWarnings("unchecked")
280 protected void match(Indexes indexes, String indexName, String pattern,
281 BiFunction<Character, Map<String, Collection>, Map<String, Collection>> matchWithCharFunction,
282 BiFunction<String, Map<String, Collection>, Map<String, Collection>> matchWithStringFunction,
283 Set<Container.Entry> matchingEntries) {
284 int patternLength = pattern.length();
285
286 if (patternLength > 0) {
287 String key = String.valueOf(indexes.hashCode()) + "***" + indexName + "***" + pattern;
288 Map<String, Collection> matchedEntries = cache.get(key);
289
290 if (matchedEntries == null) {
291 Map<String, Collection> index = indexes.getIndex(indexName);
292
293 if (index != null) {
294 if (patternLength == 1) {
295 matchedEntries = matchWithCharFunction.apply(pattern.charAt(0), index);
296 } else {
297 String lastKey = key.substring(0, key.length() - 1);
298 Map<String, Collection> lastMatchedTypes = cache.get(lastKey);
299 if (lastMatchedTypes != null) {
300 matchedEntries = matchWithStringFunction.apply(pattern, lastMatchedTypes);
301 } else {
302 matchedEntries = matchWithStringFunction.apply(pattern, index);
303 }
304 }
305 }
306
307 // Cache matchingEntries
308 cache.put(key, matchedEntries);
309 }
310
311 if (matchedEntries != null) {
312 for (Collection<Container.Entry> entries : matchedEntries.values()) {
313 matchingEntries.addAll(entries);
314 }
315 }
316 }
317 }
318
319 protected static Map<String, Collection> matchTypeEntriesWithChar(char c, Map<String, Collection> index) {
320 if ((c == '*') || (c == '?')) {
321 return index;
322 } else {
323 Map<String, Collection> map = new HashMap<>();
324
325 for (String typeName : index.keySet()) {
326 // Search last package separator
327 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
328 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
329 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
330
331 if ((lastIndex < typeName.length()) && (typeName.charAt(lastIndex) == c)) {
332 map.put(typeName, index.get(typeName));
333 }
334 }
335
336 return map;
337 }
338 }
339
340 protected static Map<String, Collection> matchTypeEntriesWithString(String pattern, Map<String, Collection> index) {
341 Pattern p = createPattern(pattern);
342 Map<String, Collection> map = new HashMap<>();
343
344 for (String typeName : index.keySet()) {
345 // Search last package separator
346 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
347 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
348 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
349
350 if (p.matcher(typeName.substring(lastIndex)).matches()) {
351 map.put(typeName, index.get(typeName));
352 }
353 }
354
355 return map;
356 }
357
358 protected static Map<String, Collection> matchWithChar(char c, Map<String, Collection> index) {
359 if ((c == '*') || (c == '?')) {
360 return index;
361 } else {
362 Map<String, Collection> map = new HashMap<>();
363
364 for (String key : index.keySet()) {
365 if (!key.isEmpty() && (key.charAt(0) == c)) {
366 map.put(key, index.get(key));
367 }
368 }
369
370 return map;
371 }
372 }
373
374 protected static Map<String, Collection> matchWithString(String pattern, Map<String, Collection> index) {
375 Pattern p = createPattern(pattern);
376 Map<String, Collection> map = new HashMap<>();
377
378 for (String key : index.keySet()) {
379 if (p.matcher(key).matches()) {
380 map.put(key, index.get(key));
381 }
382 }
383
384 return map;
385 }
386
387 /**
388 * Create a simple regular expression
389 *
390 * Rules:
391 * '*' matchTypeEntries 0 ou N characters
392 * '?' matchTypeEntries 1 character
393 */
394 protected static Pattern createPattern(String pattern) {
395 int patternLength = pattern.length();
396 StringBuilder sbPattern = new StringBuilder(patternLength * 2);
397
398 for (int i = 0; i < patternLength; i++) {
399 char c = pattern.charAt(i);
400
401 if (c == '*') {
402 sbPattern.append(".*");
403 } else if (c == '?') {
404 sbPattern.append('.');
405 } else if (c == '.') {
406 sbPattern.append("\\.");
407 } else {
408 sbPattern.append(c);
409 }
410 }
411
412 sbPattern.append(".*");
413
414 return Pattern.compile(sbPattern.toString());
415 }
416
417 protected void onTypeSelected(URI uri, String pattern, int flags) {
418 // Open the single entry uri
419 Container.Entry entry = null;
420
421 for (DelegatingFilterContainer container : delegatingFilterContainers) {
422 entry = container.getEntry(uri);
423 if (entry != null)
424 break;
425 }
426
427 if (entry != null) {
428 StringBuilder sbPattern = new StringBuilder(200 + pattern.length());
429
430 sbPattern.append("highlightPattern=");
431 sbPattern.append(pattern);
432 sbPattern.append("&highlightFlags=");
433
434 if ((flags & SearchInConstantPoolsView.SEARCH_DECLARATION) != 0)
435 sbPattern.append('d');
436 if ((flags & SearchInConstantPoolsView.SEARCH_REFERENCE) != 0)
437 sbPattern.append('r');
438 if ((flags & SearchInConstantPoolsView.SEARCH_TYPE) != 0)
439 sbPattern.append('t');
440 if ((flags & SearchInConstantPoolsView.SEARCH_CONSTRUCTOR) != 0)
441 sbPattern.append('c');
442 if ((flags & SearchInConstantPoolsView.SEARCH_METHOD) != 0)
443 sbPattern.append('m');
444 if ((flags & SearchInConstantPoolsView.SEARCH_FIELD) != 0)
445 sbPattern.append('f');
446 if ((flags & SearchInConstantPoolsView.SEARCH_STRING) != 0)
447 sbPattern.append('s');
448 if ((flags & SearchInConstantPoolsView.SEARCH_MODULE) != 0)
449 sbPattern.append('M');
450
451 // TODO In a future release, add 'highlightScope' to display search results in correct type and inner-type
452 // def type = TypeFactoryService.instance.get(entry)?.make(api, entry, null)
453 // if (type) {
454 // sbPattern.append('&highlightScope=')
455 // sbPattern.append(type.name)
456 //
457 // def query = sbPattern.toString()
458 // def outerPath = UriUtil.getOuterPath(collectionOfFutureIndexes, entry, type)
459 //
460 // openClosure(new URI(entry.uri.scheme, entry.uri.host, outerPath, query, null))
461 // } else {
462 String query = sbPattern.toString();
463 URI u = entry.getUri();
464
465 try {
466 openCallback.accept(new URI(u.getScheme(), u.getHost(), u.getPath(), query, null));
467 } catch (URISyntaxException e) {
468 assert ExceptionUtil.printStackTrace(e);
469 }
470 // }
471 }
472 }
473
474 // --- IndexesChangeListener --- //
475 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
476 if (searchInConstantPoolsView.isVisible()) {
477 // Update the list of containers
478 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
479 // And refresh
480 updateTree(searchInConstantPoolsView.getPattern(), searchInConstantPoolsView.getFlags());
481 }
482 }
483 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.controller;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Type;
12 import org.jd.gui.model.container.DelegatingFilterContainer;
13 import org.jd.gui.service.type.TypeFactoryService;
14 import org.jd.gui.spi.TypeFactory;
15 import org.jd.gui.view.SelectLocationView;
16
17 import javax.swing.*;
18 import java.awt.*;
19 import java.net.URI;
20 import java.util.*;
21 import java.util.function.Consumer;
22
23 public class SelectLocationController {
24 protected static final ContainerEntryComparator CONTAINER_ENTRY_COMPARATOR = new ContainerEntryComparator();
25
26 protected API api;
27 protected SelectLocationView selectLocationView;
28
29 public SelectLocationController(API api, JFrame mainFrame) {
30 this.api = api;
31 // Create UI
32 selectLocationView = new SelectLocationView(api, mainFrame);
33 }
34
35 @SuppressWarnings("unchecked")
36 public void show(Point location, Collection<Container.Entry> entries, Consumer<Container.Entry> selectedLocationCallback, Runnable closeCallback) {
37 // Show UI
38 HashMap<Container, ArrayList<Container.Entry>> map = new HashMap<>();
39
40 for (Container.Entry entry : entries) {
41 Container container = entry.getContainer();
42
43 // Search root container
44 while (true) {
45 Container parentContainer = container.getRoot().getParent().getContainer();
46 if (parentContainer.getRoot() == null) {
47 break;
48 } else {
49 container = parentContainer;
50 }
51 }
52
53 ArrayList<Container.Entry> list = map.get(container);
54
55 if (list == null) {
56 map.put(container, list=new ArrayList<>());
57 }
58
59 list.add(entry);
60 }
61
62 HashSet<DelegatingFilterContainer> delegatingFilterContainers = new HashSet<>();
63
64 for (Map.Entry<Container, ArrayList<Container.Entry>> mapEntry : map.entrySet()) {
65 Container container = mapEntry.getKey();
66 // Create a filtered container
67 // TODO In a future release, display matching types and inner-types, not only matching files
68 delegatingFilterContainers.add(new DelegatingFilterContainer(container, getOuterEntries(mapEntry.getValue())));
69 }
70
71 Consumer<URI> selectedEntryCallback = uri -> onLocationSelected(delegatingFilterContainers, uri, selectedLocationCallback);
72
73 selectLocationView.show(location, delegatingFilterContainers, entries.size(), selectedEntryCallback, closeCallback);
74 }
75
76 protected Collection<Container.Entry> getOuterEntries(Collection<Container.Entry> entries) {
77 HashMap<Container.Entry, Container.Entry> innerTypeEntryToOuterTypeEntry = new HashMap<>();
78 HashSet<Container.Entry> outerEntriesSet = new HashSet<>();
79
80 for (Container.Entry entry : entries) {
81 Container.Entry outerTypeEntry = null;
82 TypeFactory factory = TypeFactoryService.getInstance().get(entry);
83
84 if (factory != null) {
85 Type type = factory.make(api, entry, null);
86
87 if ((type != null) && (type.getOuterName() != null)) {
88 outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry);
89
90 if (outerTypeEntry == null) {
91 HashMap<String, Container.Entry> typeNameToEntry = new HashMap<>();
92 HashMap<String, String> innerTypeNameToOuterTypeName = new HashMap<>();
93
94 // Populate "typeNameToEntry" and "innerTypeNameToOuterTypeName"
95 for (Container.Entry e : entry.getParent().getChildren()) {
96 factory = TypeFactoryService.getInstance().get(e);
97
98 if (factory != null) {
99 type = factory.make(api, e, null);
100
101 if (type != null) {
102 typeNameToEntry.put(type.getName(), e);
103 if (type.getOuterName() != null) {
104 innerTypeNameToOuterTypeName.put(type.getName(), type.getOuterName());
105 }
106 }
107 }
108 }
109
110 // Search outer type entries and populate "innerTypeEntryToOuterTypeEntry"
111 for (Map.Entry<String, String> e : innerTypeNameToOuterTypeName.entrySet()) {
112 Container.Entry innerTypeEntry = typeNameToEntry.get(e.getKey());
113
114 if (innerTypeEntry != null) {
115 String outerTypeName = e.getValue();
116
117 for (;;) {
118 String typeName = innerTypeNameToOuterTypeName.get(outerTypeName);
119 if (typeName != null) {
120 outerTypeName = typeName;
121 } else {
122 break;
123 }
124 }
125
126 outerTypeEntry = typeNameToEntry.get(outerTypeName);
127
128 if (outerTypeEntry != null) {
129 innerTypeEntryToOuterTypeEntry.put(innerTypeEntry, outerTypeEntry);
130 }
131 }
132 }
133
134 // Get outer type entry
135 outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry);
136 }
137 }
138 }
139
140 if (outerTypeEntry != null) {
141 outerEntriesSet.add(outerTypeEntry);
142 } else {
143 outerEntriesSet.add(entry);
144 }
145 }
146
147 // Return outer type entries sorted by path
148 ArrayList<Container.Entry> result = new ArrayList<>(outerEntriesSet);
149
150 result.sort(CONTAINER_ENTRY_COMPARATOR);
151
152 return result;
153 }
154
155 protected void onLocationSelected(Set<DelegatingFilterContainer> delegatingFilterContainers, URI uri, Consumer<Container.Entry> selectedLocationCallback) {
156 // Open the single entry uri
157 Container.Entry entry = null;
158
159 for (DelegatingFilterContainer container : delegatingFilterContainers) {
160 entry = container.getEntry(uri);
161 if (entry != null) {
162 break;
163 }
164 }
165
166 if (entry != null) {
167 selectedLocationCallback.accept(entry);
168 }
169 }
170
171 protected static class ContainerEntryComparator implements Comparator<Container.Entry> {
172 @Override
173 public int compare(Container.Entry e1, Container.Entry e2) {
174 return e1.getPath().compareTo(e2.getPath());
175 }
176 }
177 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.configuration;
8
9 import org.jd.gui.Constants;
10
11 import java.awt.*;
12 import java.io.File;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17
18 public class Configuration {
19 protected Point mainWindowLocation;
20 protected Dimension mainWindowSize;
21 protected boolean mainWindowMaximize;
22 protected String lookAndFeel;
23
24 protected List<File> recentFiles = new ArrayList<>();
25
26 protected File recentLoadDirectory;
27 protected File recentSaveDirectory;
28
29 protected Map<String, String> preferences = new HashMap<>();
30
31 public Point getMainWindowLocation() {
32 return mainWindowLocation;
33 }
34
35 public Dimension getMainWindowSize() {
36 return mainWindowSize;
37 }
38
39 public boolean isMainWindowMaximize() {
40 return mainWindowMaximize;
41 }
42
43 public String getLookAndFeel() {
44 return lookAndFeel;
45 }
46
47 public List<File> getRecentFiles() {
48 return recentFiles;
49 }
50
51 public File getRecentLoadDirectory() {
52 return recentLoadDirectory;
53 }
54
55 public File getRecentSaveDirectory() {
56 return recentSaveDirectory;
57 }
58
59 public Map<String, String> getPreferences() {
60 return preferences;
61 }
62
63 public void setMainWindowLocation(Point mainWindowLocation) {
64 this.mainWindowLocation = mainWindowLocation;
65 }
66
67 public void setMainWindowSize(Dimension mainWindowSize) {
68 this.mainWindowSize = mainWindowSize;
69 }
70
71 public void setMainWindowMaximize(boolean mainWindowMaximize) {
72 this.mainWindowMaximize = mainWindowMaximize;
73 }
74
75 public void setLookAndFeel(String lookAndFeel) {
76 this.lookAndFeel = lookAndFeel;
77 }
78
79 public void setRecentFiles(List<File> recentFiles) {
80 this.recentFiles = recentFiles;
81 }
82
83 public void setRecentLoadDirectory(File recentLoadDirectory) {
84 this.recentLoadDirectory = recentLoadDirectory;
85 }
86
87 public void setRecentSaveDirectory(File recentSaveDirectory) {
88 this.recentSaveDirectory = recentSaveDirectory;
89 }
90
91 public void setPreferences(Map<String, String> preferences) {
92 this.preferences = preferences;
93 }
94
95 public void addRecentFile(File file) {
96 recentFiles.remove(file);
97 recentFiles.add(0, file);
98 if (recentFiles.size() > Constants.MAX_RECENT_FILES) {
99 recentFiles.remove(Constants.MAX_RECENT_FILES);
100 }
101 }
102 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.model.Container;
10
11 import java.io.InputStream;
12 import java.net.URI;
13 import java.util.*;
14
15 public class DelegatingFilterContainer implements Container {
16 protected static final URI DEFAULT_ROOT_URI = URI.create("file:.");
17
18 protected Container container;
19 protected DelegatedEntry root;
20
21 protected Set<URI> validEntries = new HashSet<>();
22 protected Map<URI, DelegatedEntry> uriToDelegatedEntry = new HashMap<>();
23 protected Map<URI, DelegatedContainer> uriToDelegatedContainer = new HashMap<>();
24
25 public DelegatingFilterContainer(Container container, Collection<Entry> entries) {
26 this.container = container;
27 this.root = getDelegatedEntry(container.getRoot());
28
29 for (Entry entry : entries) {
30 while ((entry != null) && !validEntries.contains(entry.getUri())) {
31 validEntries.add(entry.getUri());
32 entry = entry.getParent();
33 }
34 }
35 }
36
37 @Override public String getType() { return container.getType(); }
38 @Override public Container.Entry getRoot() { return root; }
39
40 public Container.Entry getEntry(URI uri) { return uriToDelegatedEntry.get(uri); }
41 public Set<URI> getUris() { return validEntries; }
42
43 protected DelegatedEntry getDelegatedEntry(Container.Entry entry) {
44 URI uri = entry.getUri();
45 DelegatedEntry delegatedEntry = uriToDelegatedEntry.get(uri);
46 if (delegatedEntry == null) {
47 uriToDelegatedEntry.put(uri, delegatedEntry =new DelegatedEntry(entry));
48 }
49 return delegatedEntry;
50 }
51
52 protected DelegatedContainer getDelegatedContainer(Container container) {
53 Entry root = container.getRoot();
54 URI uri = (root == null) ? DEFAULT_ROOT_URI : root.getUri();
55 DelegatedContainer delegatedContainer = uriToDelegatedContainer.get(uri);
56 if (delegatedContainer == null) {
57 uriToDelegatedContainer.put(uri, delegatedContainer =new DelegatedContainer(container));
58 }
59 return delegatedContainer;
60 }
61
62 protected class DelegatedEntry implements Entry, Comparable<DelegatedEntry> {
63 protected Entry entry;
64 protected Collection<Entry> children;
65
66 public DelegatedEntry(Entry entry) {
67 this.entry = entry;
68 }
69
70 @Override public Container getContainer() { return getDelegatedContainer(entry.getContainer()); }
71 @Override public Entry getParent() { return getDelegatedEntry(entry.getParent()); }
72 @Override public URI getUri() { return entry.getUri(); }
73 @Override public String getPath() { return entry.getPath(); }
74 @Override public boolean isDirectory() { return entry.isDirectory(); }
75 @Override public long length() { return entry.length(); }
76 @Override public InputStream getInputStream() { return entry.getInputStream(); }
77
78 @Override
79 public Collection<Entry> getChildren() {
80 if (children == null) {
81 children = new ArrayList<>();
82 for (Entry child : entry.getChildren()) {
83 if (validEntries.contains(child.getUri())) {
84 children.add(getDelegatedEntry(child));
85 }
86 }
87 }
88 return children;
89 }
90
91 @Override
92 public int compareTo(DelegatedEntry other) {
93 if (entry.isDirectory()) {
94 if (!other.isDirectory()) {
95 return -1;
96 }
97 } else {
98 if (other.isDirectory()) {
99 return 1;
100 }
101 }
102 return entry.getPath().compareTo(other.getPath());
103 }
104 }
105
106 protected class DelegatedContainer implements Container {
107 protected Container container;
108
109 public DelegatedContainer(Container container) {
110 this.container = container;
111 }
112
113 @Override public String getType() { return container.getType(); }
114 @Override public Entry getRoot() { return getDelegatedEntry(container.getRoot()); }
115 }
116 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.history;
8
9 import java.net.URI;
10 import java.util.ArrayList;
11
12 public class History {
13 protected URI current = null;
14 protected ArrayList<URI> backward = new ArrayList<>();
15 protected ArrayList<URI> forward = new ArrayList<>();
16
17 public void add(URI uri) {
18 if (current == null) {
19 // Init history
20 forward.clear();
21 current = uri;
22 return;
23 }
24
25 if (current.equals(uri)) {
26 // Already stored -> Nothing to do
27 return;
28 }
29
30 if (uri.getPath().toString().equals(current.getPath().toString())) {
31 if ((uri.getFragment() == null) && (uri.getQuery() == null)) {
32 // Ignore
33 } else if ((current.getFragment() == null) && (current.getQuery() == null)) {
34 // Replace current URI
35 current = uri;
36 } else {
37 // Store URI
38 forward.clear();
39 backward.add(current);
40 current = uri;
41 }
42 return;
43 }
44
45 if (uri.toString().startsWith(current.toString())) {
46 // Replace current URI
47 current = uri;
48 return;
49 }
50
51 if (current.toString().startsWith(uri.toString())) {
52 // Parent URI -> Nothing to do
53 return;
54 }
55
56 // Store URI
57 forward.clear();
58 backward.add(current);
59 current = uri;
60 }
61
62 public URI backward() {
63 if (! backward.isEmpty()) {
64 forward.add(current);
65 int size = backward.size();
66 current = backward.remove(size-1);
67 }
68 return current;
69 }
70
71 public URI forward() {
72 if (! forward.isEmpty()) {
73 backward.add(current);
74 int size = forward.size();
75 current = forward.remove(size-1);
76 }
77 return current;
78 }
79
80 public boolean canBackward() { return !backward.isEmpty(); }
81 public boolean canForward() { return !forward.isEmpty(); }
82 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.actions;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.service.extension.ExtensionService;
12 import org.jd.gui.spi.ContextualActionsFactory;
13
14 import javax.swing.*;
15 import java.util.*;
16
17 public class ContextualActionsFactoryService {
18 protected static final ContextualActionsFactoryService CONTEXTUAL_ACTIONS_FACTORY_SERVICE = new ContextualActionsFactoryService();
19
20 public static ContextualActionsFactoryService getInstance() { return CONTEXTUAL_ACTIONS_FACTORY_SERVICE; }
21
22 protected static final ActionNameComparator COMPARATOR = new ActionNameComparator();
23
24 protected final Collection<ContextualActionsFactory> providers = ExtensionService.getInstance().load(ContextualActionsFactory.class);
25
26 public Collection<Action> get(API api, Container.Entry entry, String fragment) {
27 HashMap<String, ArrayList<Action>> mapActions = new HashMap<>();
28
29 for (ContextualActionsFactory provider : providers) {
30 Collection<Action> actions = provider.make(api, entry, fragment);
31
32 for (Action action : actions) {
33 String groupName = (String)action.getValue(ContextualActionsFactory.GROUP_NAME);
34 ArrayList<Action> list = mapActions.get(groupName);
35
36 if (list == null) {
37 mapActions.put(groupName, list=new ArrayList<>());
38 }
39
40 list.add(action);
41 }
42 }
43
44 if (!mapActions.isEmpty()) {
45 ArrayList<Action> result = new ArrayList<>();
46
47 // Sort by group names
48 ArrayList<String> groupNames = new ArrayList<>(mapActions.keySet());
49 Collections.sort(groupNames);
50
51 for (String groupName : groupNames) {
52 if (! result.isEmpty()) {
53 // Add 'null' to mark a separator
54 result.add(null);
55 }
56 // Sort by names
57 ArrayList<Action> actions = mapActions.get(groupName);
58 Collections.sort(actions, COMPARATOR);
59 result.addAll(actions);
60 }
61
62 return result;
63 } else {
64 return Collections.emptyList();
65 }
66 }
67
68 protected static class ActionNameComparator implements Comparator<Action> {
69 @Override
70 public int compare(Action a1, Action a2) {
71 String n1 = (String)a1.getValue(Action.NAME);
72 if (n1 == null) {
73 n1 = "";
74 }
75
76 String n2 = (String)a2.getValue(Action.NAME);
77 if (n2 == null) {
78 n2 = "";
79 }
80
81 return n1.compareTo(n2);
82 }
83 }
84 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.configuration;
8
9 import org.jd.gui.model.configuration.Configuration;
10
11 public interface ConfigurationPersister {
12 Configuration load();
13
14 void save(Configuration configuration);
15 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.configuration;
8
9 public class ConfigurationPersisterService {
10 protected static final ConfigurationPersisterService CONFIGURATION_PERSISTER_SERVICE = new ConfigurationPersisterService();
11
12 protected ConfigurationPersister provider = new ConfigurationXmlPersisterProvider();
13
14 public static ConfigurationPersisterService getInstance() { return CONFIGURATION_PERSISTER_SERVICE; }
15
16 protected ConfigurationPersisterService() {}
17
18 public ConfigurationPersister get() {
19 return provider;
20 }
21 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.configuration;
8
9 import org.jd.gui.Constants;
10 import org.jd.gui.model.configuration.Configuration;
11 import org.jd.gui.service.platform.PlatformService;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import javax.swing.*;
15 import javax.xml.stream.*;
16 import java.awt.*;
17 import java.io.*;
18 import java.net.URL;
19 import java.util.*;
20 import java.util.List;
21 import java.util.jar.Manifest;
22
23 public class ConfigurationXmlPersisterProvider implements ConfigurationPersister {
24 protected static final String ERROR_BACKGROUND_COLOR = "JdGuiPreferences.errorBackgroundColor";
25 protected static final String JD_CORE_VERSION = "JdGuiPreferences.jdCoreVersion";
26
27 protected static final File FILE = getConfigFile();
28
29 protected static File getConfigFile() {
30 String configFilePath = System.getProperty(Constants.CONFIG_FILENAME);
31
32 if (configFilePath != null) {
33 File configFile = new File(configFilePath);
34 if (configFile.exists()) {
35 return configFile;
36 }
37 }
38
39 if (PlatformService.getInstance().isLinux()) {
40 // See: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
41 String xdgConfigHome = System.getenv("XDG_CONFIG_HOME");
42 if (xdgConfigHome != null) {
43 File xdgConfigHomeFile = new File(xdgConfigHome);
44 if (xdgConfigHomeFile.exists()) {
45 return new File(xdgConfigHomeFile, Constants.CONFIG_FILENAME);
46 }
47 }
48
49 File userConfigFile = new File(System.getProperty("user.home"), ".config");
50 if (userConfigFile.exists()) {
51 return new File(userConfigFile, Constants.CONFIG_FILENAME);
52 }
53 } else if (PlatformService.getInstance().isWindows()) {
54 // See: http://blogs.msdn.com/b/patricka/archive/2010/03/18/where-should-i-store-my-data-and-configuration-files-if-i-target-multiple-os-versions.aspx
55 String roamingConfigHome = System.getenv("APPDATA");
56 if (roamingConfigHome != null) {
57 File roamingConfigHomeFile = new File(roamingConfigHome);
58 if (roamingConfigHomeFile.exists()) {
59 return new File(roamingConfigHomeFile, Constants.CONFIG_FILENAME);
60 }
61 }
62 }
63
64 return new File(Constants.CONFIG_FILENAME);
65 }
66
67 @Override
68 public Configuration load() {
69 // Default values
70 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
71
72 int w = (screenSize.width>Constants.DEFAULT_WIDTH) ? Constants.DEFAULT_WIDTH : screenSize.width;
73 int h = (screenSize.height>Constants.DEFAULT_HEIGHT) ? Constants.DEFAULT_HEIGHT : screenSize.height;
74 int x = (screenSize.width-w)/2;
75 int y = (screenSize.height-h)/2;
76
77 Configuration config = new Configuration();
78 config.setMainWindowLocation(new Point(x, y));
79 config.setMainWindowSize(new Dimension(w, h));
80 config.setMainWindowMaximize(false);
81
82 String defaultLaf = System.getProperty("swing.defaultlaf");
83
84 config.setLookAndFeel((defaultLaf != null) ? defaultLaf : UIManager.getSystemLookAndFeelClassName());
85
86 File recentSaveDirectory = new File(System.getProperty("user.dir"));
87
88 config.setRecentLoadDirectory(recentSaveDirectory);
89 config.setRecentSaveDirectory(recentSaveDirectory);
90
91 if (FILE.exists()) {
92 try (FileInputStream fis = new FileInputStream(FILE)) {
93 XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(fis);
94
95 // Load values
96 String name = "";
97 Stack<String> names = new Stack<>();
98 List<File> recentFiles = new ArrayList<>();
99 boolean maximize = false;
100 Map<String, String> preferences = config.getPreferences();
101
102 while (reader.hasNext()) {
103 switch (reader.next()) {
104 case XMLStreamConstants.START_ELEMENT:
105 names.push(name);
106 name += '/' + reader.getLocalName();
107 switch (name) {
108 case "/configuration/gui/mainWindow/location":
109 x = Integer.parseInt(reader.getAttributeValue(null, "x"));
110 y = Integer.parseInt(reader.getAttributeValue(null, "y"));
111 break;
112 case "/configuration/gui/mainWindow/size":
113 w = Integer.parseInt(reader.getAttributeValue(null, "w"));
114 h = Integer.parseInt(reader.getAttributeValue(null, "h"));
115 break;
116 }
117 break;
118 case XMLStreamConstants.END_ELEMENT:
119 name = names.pop();
120 break;
121 case XMLStreamConstants.CHARACTERS:
122 switch (name) {
123 case "/configuration/recentFilePaths/filePath":
124 File file = new File(reader.getText().trim());
125 if (file.exists()) {
126 recentFiles.add(file);
127 }
128 break;
129 case "/configuration/recentDirectories/loadPath":
130 file = new File(reader.getText().trim());
131 if (file.exists()) {
132 config.setRecentLoadDirectory(file);
133 }
134 break;
135 case "/configuration/recentDirectories/savePath":
136 file = new File(reader.getText().trim());
137 if (file.exists()) {
138 config.setRecentSaveDirectory(file);
139 }
140 break;
141 case "/configuration/gui/lookAndFeel":
142 config.setLookAndFeel(reader.getText().trim());
143 break;
144 case "/configuration/gui/mainWindow/maximize":
145 maximize = Boolean.parseBoolean(reader.getText().trim());
146 break;
147 default:
148 if (name.startsWith("/configuration/preferences/")) {
149 String key = name.substring("/configuration/preferences/".length());
150 preferences.put(key, reader.getText().trim());
151 }
152 break;
153 }
154 break;
155 }
156 }
157
158 if (recentFiles.size() > Constants.MAX_RECENT_FILES) {
159 // Truncate
160 recentFiles = recentFiles.subList(0, Constants.MAX_RECENT_FILES);
161 }
162 config.setRecentFiles(recentFiles);
163
164 if ((x >= 0) && (y >= 0) && (x + w < screenSize.width) && (y + h < screenSize.height)) {
165 // Update preferences
166 config.setMainWindowLocation(new Point(x, y));
167 config.setMainWindowSize(new Dimension(w, h));
168 config.setMainWindowMaximize(maximize);
169 }
170
171 reader.close();
172 } catch (Exception e) {
173 assert ExceptionUtil.printStackTrace(e);
174 }
175 }
176
177 if (! config.getPreferences().containsKey(ERROR_BACKGROUND_COLOR)) {
178 config.getPreferences().put(ERROR_BACKGROUND_COLOR, "0xFF6666");
179 }
180
181 config.getPreferences().put(JD_CORE_VERSION, getJdCoreVersion());
182
183 return config;
184 }
185
186 protected String getJdCoreVersion() {
187 try {
188 Enumeration<URL> enumeration = ConfigurationXmlPersisterProvider.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
189
190 while (enumeration.hasMoreElements()) {
191 try (InputStream is = enumeration.nextElement().openStream()) {
192 String attribute = new Manifest(is).getMainAttributes().getValue("JD-Core-Version");
193 if (attribute != null) {
194 return attribute;
195 }
196 }
197 }
198 } catch (IOException e) {
199 assert ExceptionUtil.printStackTrace(e);
200 }
201
202 return "SNAPSHOT";
203 }
204
205 @Override
206 public void save(Configuration configuration) {
207 Point l = configuration.getMainWindowLocation();
208 Dimension s = configuration.getMainWindowSize();
209
210 try (FileOutputStream fos = new FileOutputStream(FILE)) {
211 XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(fos);
212
213 // Save values
214 writer.writeStartDocument();
215 writer.writeCharacters("\n");
216 writer.writeStartElement("configuration");
217 writer.writeCharacters("\n\t");
218
219 writer.writeStartElement("gui");
220 writer.writeCharacters("\n\t\t");
221 writer.writeStartElement("mainWindow");
222 writer.writeCharacters("\n\t\t\t");
223 writer.writeStartElement("location");
224 writer.writeAttribute("x", String.valueOf(l.x));
225 writer.writeAttribute("y", String.valueOf(l.y));
226 writer.writeEndElement();
227 writer.writeCharacters("\n\t\t\t");
228 writer.writeStartElement("size");
229 writer.writeAttribute("w", String.valueOf(s.width));
230 writer.writeAttribute("h", String.valueOf(s.height));
231 writer.writeEndElement();
232 writer.writeCharacters("\n\t\t\t");
233 writer.writeStartElement("maximize");
234 writer.writeCharacters(String.valueOf(configuration.isMainWindowMaximize()));
235 writer.writeEndElement();
236 writer.writeCharacters("\n\t\t");
237 writer.writeEndElement();
238 writer.writeCharacters("\n\t\t");
239 writer.writeStartElement("lookAndFeel");
240 writer.writeCharacters(configuration.getLookAndFeel());
241 writer.writeEndElement();
242 writer.writeCharacters("\n\t");
243 writer.writeEndElement();
244 writer.writeCharacters("\n\t");
245
246 writer.writeStartElement("recentFilePaths");
247
248 for (File recentFile : configuration.getRecentFiles()) {
249 writer.writeCharacters("\n\t\t");
250 writer.writeStartElement("filePath");
251 writer.writeCharacters(recentFile.getAbsolutePath());
252 writer.writeEndElement();
253 }
254
255 writer.writeCharacters("\n\t");
256 writer.writeEndElement();
257 writer.writeCharacters("\n\t");
258
259 writer.writeStartElement("recentDirectories");
260 writer.writeCharacters("\n\t\t");
261 writer.writeStartElement("loadPath");
262 writer.writeCharacters(configuration.getRecentLoadDirectory().getAbsolutePath());
263 writer.writeEndElement();
264 writer.writeCharacters("\n\t\t");
265 writer.writeStartElement("savePath");
266 writer.writeCharacters(configuration.getRecentSaveDirectory().getAbsolutePath());
267 writer.writeEndElement();
268 writer.writeCharacters("\n\t");
269 writer.writeEndElement();
270 writer.writeCharacters("\n\t");
271
272 writer.writeStartElement("preferences");
273
274 for (Map.Entry<String, String> preference : configuration.getPreferences().entrySet()) {
275 writer.writeCharacters("\n\t\t");
276 writer.writeStartElement(preference.getKey());
277 writer.writeCharacters(preference.getValue());
278 writer.writeEndElement();
279 }
280
281 writer.writeCharacters("\n\t");
282 writer.writeEndElement();
283 writer.writeCharacters("\n");
284
285 writer.writeEndElement();
286 writer.writeEndDocument();
287 writer.close();
288 } catch (Exception e) {
289 assert ExceptionUtil.printStackTrace(e);
290 }
291 }
292 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.ContainerFactory;
12
13 import java.nio.file.Path;
14 import java.util.Collection;
15
16 public class ContainerFactoryService {
17 protected static final ContainerFactoryService CONTAINER_FACTORY_SERVICE = new ContainerFactoryService();
18
19 public static ContainerFactoryService getInstance() { return CONTAINER_FACTORY_SERVICE; }
20
21 protected final Collection<ContainerFactory> providers = ExtensionService.getInstance().load(ContainerFactory.class);
22
23 public ContainerFactory get(API api, Path rootPath) {
24 for (ContainerFactory containerFactory : providers) {
25 if (containerFactory.accept(api, rootPath)) {
26 return containerFactory;
27 }
28 }
29
30 return null;
31 }
32 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.extension;
8
9 import org.jd.gui.util.exception.ExceptionUtil;
10
11 import java.io.File;
12 import java.net.URI;
13 import java.net.URL;
14 import java.net.URLClassLoader;
15 import java.util.*;
16
17 public class ExtensionService {
18 protected static final ExtensionService EXTENSION_SERVICE = new ExtensionService();
19 protected static final UrlComparator URL_COMPARATOR = new UrlComparator();
20
21 protected ClassLoader extensionClassLoader;
22
23 public static ExtensionService getInstance() {
24 return EXTENSION_SERVICE;
25 }
26
27 protected ExtensionService() {
28 try {
29 URI jarUri = ExtensionService.class.getProtectionDomain().getCodeSource().getLocation().toURI();
30 File baseDirectory = new File(jarUri).getParentFile();
31 File extDirectory = new File(baseDirectory, "ext");
32
33 if (extDirectory.exists() && extDirectory.isDirectory()) {
34 ArrayList<URL> urls = new ArrayList<>();
35
36 searchJarAndMetaInf(urls, extDirectory);
37
38 if (!urls.isEmpty()) {
39 URL[] array = urls.toArray(new URL[urls.size()]);
40 Arrays.sort(array, URL_COMPARATOR);
41 extensionClassLoader = new URLClassLoader(array, ExtensionService.class.getClassLoader());
42 }
43 }
44 } catch (Exception e) {
45 assert ExceptionUtil.printStackTrace(e);
46 }
47
48 extensionClassLoader = ExtensionService.class.getClassLoader();
49 }
50
51 protected void searchJarAndMetaInf(List<URL> urls, File directory) throws Exception {
52 File metaInf = new File(directory, "META-INF");
53
54 if (metaInf.exists() && metaInf.isDirectory()) {
55 urls.add(directory.toURI().toURL());
56 } else {
57 for (File child : directory.listFiles()) {
58 if (child.isDirectory()) {
59 searchJarAndMetaInf(urls, child);
60 } else if (child.getName().toLowerCase().endsWith(".jar")) {
61 urls.add(new URL("jar", "", child.toURI().toURL().toString() + "!/"));
62 }
63 }
64 }
65 }
66
67 public <T> Collection<T> load(Class<T> service) {
68 ArrayList<T> list = new ArrayList<>();
69 Iterator<T> iterator = ServiceLoader.load(service, extensionClassLoader).iterator();
70
71 while (iterator.hasNext()) {
72 list.add(iterator.next());
73 }
74
75 return list;
76 }
77
78 protected static class UrlComparator implements Comparator<URL> {
79 @Override
80 public int compare(URL url1, URL url2) {
81 return url1.getPath().compareTo(url2.getPath());
82 }
83 }
84 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.FileLoader;
12
13 import java.io.File;
14 import java.util.Collection;
15 import java.util.HashMap;
16
17 public class FileLoaderService {
18 protected static final FileLoaderService FILE_LOADER_SERVICE = new FileLoaderService();
19
20 public static FileLoaderService getInstance() { return FILE_LOADER_SERVICE; }
21
22 protected final Collection<FileLoader> providers = ExtensionService.getInstance().load(FileLoader.class);
23
24 protected HashMap<String, FileLoader> mapProviders = new HashMap<>();
25
26 protected FileLoaderService() {
27 for (FileLoader provider : providers) {
28 for (String extension : provider.getExtensions()) {
29 mapProviders.put(extension, provider);
30 }
31 }
32 }
33
34 public FileLoader get(API api, File file) {
35 String name = file.getName();
36 int lastDot = name.lastIndexOf('.');
37 String extension = name.substring(lastDot+1);
38 FileLoader provider = mapProviders.get(extension);
39 return provider;
40 }
41
42 public HashMap<String, FileLoader> getMapProviders() {
43 return mapProviders;
44 }
45 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.Indexer;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15
16 public class IndexerService {
17 protected static final IndexerService INDEXER_SERVICE = new IndexerService();
18
19 public static IndexerService getInstance() { return INDEXER_SERVICE; }
20
21 protected HashMap<String, Indexers> mapProviders = new HashMap<>();
22
23 protected IndexerService() {
24 Collection<Indexer> providers = ExtensionService.getInstance().load(Indexer.class);
25
26 for (Indexer provider : providers) {
27 for (String selector : provider.getSelectors()) {
28 Indexers indexers = mapProviders.get(selector);
29
30 if (indexers == null) {
31 mapProviders.put(selector, indexers=new Indexers());
32 }
33
34 indexers.add(provider);
35 }
36 }
37 }
38
39 public Indexer get(Container.Entry entry) {
40 Indexer indexer = get(entry.getContainer().getType(), entry);
41 return (indexer != null) ? indexer : get("*", entry);
42 }
43
44 protected Indexer get(String containerType, Container.Entry entry) {
45 String path = entry.getPath();
46 String type = entry.isDirectory() ? "dir" : "file";
47 String prefix = containerType + ':' + type;
48 Indexer indexer = null;
49 Indexers indexers = mapProviders.get(prefix + ':' + path);
50
51 if (indexers != null) {
52 indexer = indexers.match(path);
53 }
54
55 if (indexer == null) {
56 int lastSlashIndex = path.lastIndexOf('/');
57 String name = path.substring(lastSlashIndex+1);
58
59 indexers = mapProviders.get(prefix + ":*/" + name);
60 if (indexers != null) {
61 indexer = indexers.match(path);
62 }
63
64 if (indexer == null) {
65 int index = name.lastIndexOf('.');
66
67 if (index != -1) {
68 String extension = name.substring(index + 1);
69
70 indexers = mapProviders.get(prefix + ":*." + extension);
71 if (indexers != null) {
72 indexer = indexers.match(path);
73 }
74 }
75
76 if (indexer == null) {
77 indexers = mapProviders.get(prefix + ":*");
78 if (indexers != null) {
79 indexer = indexers.match(path);
80 }
81 }
82 }
83 }
84
85 return indexer;
86 }
87
88 protected static class Indexers {
89 protected HashMap<String, Indexer> indexers = new HashMap<>();
90 protected Indexer defaultIndexer;
91
92 public void add(Indexer indexer) {
93 if (indexer.getPathPattern() != null) {
94 indexers.put(indexer.getPathPattern().pattern(), indexer);
95 } else {
96 defaultIndexer = indexer;
97 }
98 }
99
100 public Indexer match(String path) {
101 for (Indexer indexer : indexers.values()) {
102 if (indexer.getPathPattern().matcher(path).matches()) {
103 return indexer;
104 }
105 }
106 return defaultIndexer;
107 }
108 }
109 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.mainpanel;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContentIndexable;
11 import org.jd.gui.api.feature.SourcesSavable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.api.model.Indexes;
15 import org.jd.gui.spi.Indexer;
16 import org.jd.gui.spi.PanelFactory;
17 import org.jd.gui.spi.SourceSaver;
18 import org.jd.gui.spi.TreeNodeFactory;
19 import org.jd.gui.util.exception.ExceptionUtil;
20 import org.jd.gui.view.component.panel.TreeTabbedPanel;
21
22 import javax.swing.*;
23 import javax.swing.tree.DefaultMutableTreeNode;
24 import javax.swing.tree.DefaultTreeModel;
25 import java.io.IOException;
26 import java.net.URI;
27 import java.net.URISyntaxException;
28 import java.nio.file.FileSystem;
29 import java.nio.file.FileSystems;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.util.*;
33
34 public class ContainerPanelFactoryProvider implements PanelFactory {
35 protected static final String[] TYPES = { "default" };
36
37 @Override public String[] getTypes() { return TYPES; }
38
39 @Override
40 @SuppressWarnings("unchecked")
41 public <T extends JComponent & UriGettable> T make(API api, Container container) {
42 return (T)new ContainerPanel(api, container);
43 }
44
45 protected class ContainerPanel extends TreeTabbedPanel implements ContentIndexable, SourcesSavable {
46 protected Container.Entry entry;
47
48 public ContainerPanel(API api, Container container) {
49 super(api, container.getRoot().getParent().getUri());
50
51 this.entry = container.getRoot().getParent();
52
53 DefaultMutableTreeNode root = new DefaultMutableTreeNode();
54
55 for (Container.Entry entry : container.getRoot().getChildren()) {
56 TreeNodeFactory factory = api.getTreeNodeFactory(entry);
57 if (factory != null) {
58 root.add(factory.make(api, entry));
59 }
60 }
61
62 tree.setModel(new DefaultTreeModel(root));
63 }
64
65 // --- ContentIndexable --- //
66 @Override
67 public Indexes index(API api) {
68 HashMap<String, Map<String, Collection>> map = new HashMap<>();
69 DelegatedMapMapWithDefault mapWithDefault = new DelegatedMapMapWithDefault(map);
70
71 // Index populating value automatically
72 Indexes indexesWithDefault = name -> mapWithDefault.get(name);
73
74 // Index entry
75 Indexer indexer = api.getIndexer(entry);
76
77 if (indexer != null) {
78 indexer.index(api, entry, indexesWithDefault);
79 }
80
81 // To prevent memory leaks, return an index without the 'populate' behaviour
82 return name -> map.get(name);
83 }
84
85 // --- SourcesSavable --- //
86 @Override
87 public String getSourceFileName() {
88 SourceSaver saver = api.getSourceSaver(entry);
89
90 if (saver != null) {
91 String path = saver.getSourcePath(entry);
92 int index = path.lastIndexOf('/');
93 return path.substring(index+1);
94 } else {
95 return null;
96 }
97 }
98
99 @Override
100 public int getFileCount() {
101 SourceSaver saver = api.getSourceSaver(entry);
102 return (saver != null) ? saver.getFileCount(api, entry) : 0;
103 }
104
105 @Override
106 public void save(API api, Controller controller, Listener listener, Path path) {
107 try {
108 Path parentPath = path.getParent();
109
110 if ((parentPath != null) && !Files.exists(parentPath)) {
111 Files.createDirectories(parentPath);
112 }
113
114 URI uri = path.toUri();
115 URI archiveUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath() + "!/", null);
116
117 try (FileSystem archiveFs = FileSystems.newFileSystem(archiveUri, Collections.singletonMap("create", "true"))) {
118 Path archiveRootPath = archiveFs.getPath("/");
119 SourceSaver saver = api.getSourceSaver(entry);
120
121 if (saver != null) {
122 saver.saveContent(
123 api,
124 () -> controller.isCancelled(),
125 (p) -> listener. pathSaved(p),
126 archiveRootPath, archiveRootPath, entry);
127 }
128 }
129 } catch (URISyntaxException|IOException e) {
130 assert ExceptionUtil.printStackTrace(e);
131 }
132 }
133 }
134
135 protected static class DelegatedMap<K, V> implements Map<K, V> {
136 protected Map<K, V> map;
137
138 public DelegatedMap(Map<K, V> map) { this.map = map; }
139
140 @Override public int size() { return map.size(); }
141 @Override public boolean isEmpty() { return map.isEmpty(); }
142 @Override public boolean containsKey(Object o) { return map.containsKey(o); }
143 @Override public boolean containsValue(Object o) { return map.containsValue(o); }
144 @Override public V get(Object o) { return map.get(o); }
145 @Override public V put(K k, V v) { return map.put(k, v); }
146 @Override public V remove(Object o) { return map.remove(o); }
147 @Override public void putAll(Map<? extends K, ? extends V> map) { this.map.putAll(map); }
148 @Override public void clear() { map.clear(); }
149 @Override public Set<K> keySet() { return map.keySet(); }
150 @Override public Collection<V> values() { return map.values(); }
151 @Override public Set<Entry<K, V>> entrySet() { return map.entrySet(); }
152 @Override public boolean equals(Object o) { return map.equals(o); }
153 @Override public int hashCode() { return map.hashCode(); }
154 }
155
156 protected static class DelegatedMapWithDefault extends DelegatedMap<String, Collection> {
157 public DelegatedMapWithDefault(Map<String, Collection> map) { super(map); }
158
159 @Override public Collection get(Object o) {
160 Collection value = map.get(o);
161 if (value == null) {
162 String key = o.toString();
163 map.put(key, value=new ArrayList());
164 }
165 return value;
166 }
167 }
168
169 protected static class DelegatedMapMapWithDefault extends DelegatedMap<String, Map<String, Collection>> {
170 protected HashMap<String, Map<String, Collection>> wrappers = new HashMap<>();
171
172 public DelegatedMapMapWithDefault(Map<String, Map<String, Collection>> map) { super(map); }
173
174 @Override public Map<String, Collection> get(Object o) {
175 Map<String, Collection> value = wrappers.get(o);
176
177 if (value == null) {
178 String key = o.toString();
179 HashMap<String, Collection> m = new HashMap<>();
180 map.put(key, m);
181 wrappers.put(key, value=new DelegatedMapWithDefault(m));
182 }
183
184 return value;
185 }
186 }
187 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.mainpanel;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.PanelFactory;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15
16 public class PanelFactoryService {
17 protected static final PanelFactoryService PANEL_FACTORY_SERVICE = new PanelFactoryService();
18
19 public static PanelFactoryService getInstance() { return PANEL_FACTORY_SERVICE; }
20
21 protected HashMap<String, PanelFactory> mapProviders = new HashMap<>();
22
23 protected PanelFactoryService() {
24 Collection<PanelFactory> providers = ExtensionService.getInstance().load(PanelFactory.class);
25
26 for (PanelFactory provider : providers) {
27 for (String type : provider.getTypes()) {
28 mapProviders.put(type, provider);
29 }
30 }
31 }
32
33 public PanelFactory get(Container container) {
34 PanelFactory factory = mapProviders.get(container.getType());
35 return (factory != null) ? factory : mapProviders.get("default");
36 }
37 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.pastehandler;
8
9 import org.jd.gui.service.extension.ExtensionService;
10 import org.jd.gui.spi.PasteHandler;
11
12 import java.util.Collection;
13
14 public class PasteHandlerService {
15 protected static final PasteHandlerService PASTE_HANDLER_SERVICE = new PasteHandlerService();
16
17 public static PasteHandlerService getInstance() { return PASTE_HANDLER_SERVICE; }
18
19 protected final Collection<PasteHandler> providers = ExtensionService.getInstance().load(PasteHandler.class);
20
21 public PasteHandler get(Object obj) {
22 for (PasteHandler provider : providers) {
23 if (provider.accept(obj)) {
24 return provider;
25 }
26 }
27 return null;
28 }
29 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.platform;
8
9 public class PlatformService {
10 protected static final PlatformService PLATFORM_SERVICE = new PlatformService();
11
12 public enum OS { Linux, MacOSX, Windows }
13
14 protected OS os;
15
16 protected PlatformService() {
17 String osName = System.getProperty("os.name").toLowerCase();
18
19 if (osName.contains("windows")) {
20 os = OS.Windows;
21 } else if (osName.contains("mac os")) {
22 os = OS.MacOSX;
23 } else {
24 os = OS.Linux;
25 }
26 }
27
28 public static PlatformService getInstance() { return PLATFORM_SERVICE; }
29
30 public OS getOs() { return os; }
31
32 public boolean isLinux() { return os == OS.Linux; }
33 public boolean isMac() { return os == OS.MacOSX; }
34 public boolean isWindows() { return os == OS.Windows; }
35 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.service.extension.ExtensionService;
10 import org.jd.gui.spi.PreferencesPanel;
11
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Iterator;
15
16 public class PreferencesPanelService {
17 protected static final PreferencesPanelService PREFERENCES_PANEL_SERVICE = new PreferencesPanelService();
18
19 public static PreferencesPanelService getInstance() { return PREFERENCES_PANEL_SERVICE; }
20
21 protected final Collection<PreferencesPanel> providers;
22
23 protected PreferencesPanelService() {
24 Collection<PreferencesPanel> list = ExtensionService.getInstance().load(PreferencesPanel.class);
25 Iterator<PreferencesPanel> iterator = list.iterator();
26
27 while (iterator.hasNext()) {
28 if (!iterator.next().isActivated()) {
29 iterator.remove();
30 }
31 }
32
33 HashMap<String, PreferencesPanel> map = new HashMap<>();
34
35 for (PreferencesPanel panel : list) {
36 map.put(panel.getPreferencesGroupTitle() + '$' + panel.getPreferencesPanelTitle(), panel);
37 }
38
39 providers = map.values();
40 }
41
42 public Collection<PreferencesPanel> getProviders() {
43 return providers;
44 }
45 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.service.platform.PlatformService;
10 import org.jd.gui.spi.PreferencesPanel;
11
12 import javax.swing.*;
13 import java.awt.*;
14 import java.util.Map;
15
16 /**
17 * Single instance is the default mode on Mac OSX, so this panel is not activated.
18 */
19 public class UISingleInstancePreferencesProvider extends JPanel implements PreferencesPanel {
20 protected static final String SINGLE_INSTANCE = "UIMainWindowPreferencesProvider.singleInstance";
21
22 protected JCheckBox singleInstanceTabsCheckBox;
23
24 public UISingleInstancePreferencesProvider() {
25 super(new GridLayout(0,1));
26
27 singleInstanceTabsCheckBox = new JCheckBox("Single instance");
28
29 add(singleInstanceTabsCheckBox);
30 }
31
32 // --- PreferencesPanel --- //
33 @Override public String getPreferencesGroupTitle() { return "User Interface"; }
34 @Override public String getPreferencesPanelTitle() { return "Main window"; }
35 @Override public JComponent getPanel() { return this; }
36
37 @Override public void init(Color errorBackgroundColor) {}
38
39 @Override public boolean isActivated() { return !PlatformService.getInstance().isMac(); }
40
41 @Override
42 public void loadPreferences(Map<String, String> preferences) {
43 singleInstanceTabsCheckBox.setSelected("true".equals(preferences.get(SINGLE_INSTANCE)));
44 }
45
46 @Override
47 public void savePreferences(Map<String, String> preferences) {
48 preferences.put(SINGLE_INSTANCE, Boolean.toString(singleInstanceTabsCheckBox.isSelected()));
49 }
50
51 @Override public boolean arePreferencesValid() { return true; }
52
53 @Override public void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {}
54 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.service.platform.PlatformService;
10 import org.jd.gui.spi.PreferencesPanel;
11
12 import javax.swing.*;
13 import java.awt.*;
14 import java.util.Map;
15
16 /**
17 * JTabbedPane.WRAP_TAB_LAYOUT is not supported by Aqua L&F.
18 * This panel is not activated on Mac OSX.
19 */
20 public class UITabsPreferencesProvider extends JPanel implements PreferencesPanel {
21 protected static final String TAB_LAYOUT = "UITabsPreferencesProvider.singleLineTabs";
22
23 protected JCheckBox singleLineTabsCheckBox;
24
25 public UITabsPreferencesProvider() {
26 super(new GridLayout(0,1));
27
28 singleLineTabsCheckBox = new JCheckBox("Tabs on a single line");
29
30 add(singleLineTabsCheckBox);
31 }
32
33 // --- PreferencesPanel --- //
34 @Override public String getPreferencesGroupTitle() { return "User Interface"; }
35 @Override public String getPreferencesPanelTitle() { return "Tabs"; }
36 @Override public JComponent getPanel() { return this; }
37
38 @Override public void init(Color errorBackgroundColor) {}
39
40 @Override public boolean isActivated() { return !PlatformService.getInstance().isMac(); }
41
42 @Override public void loadPreferences(Map<String, String> preferences) {
43 singleLineTabsCheckBox.setSelected("true".equals(preferences.get(TAB_LAYOUT)));
44 }
45
46 @Override public void savePreferences(Map<String, String> preferences) {
47 preferences.put(TAB_LAYOUT, Boolean.toString(singleLineTabsCheckBox.isSelected()));
48 }
49
50 @Override public boolean arePreferencesValid() { return true; }
51
52 @Override public void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {}
53 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourceloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.service.extension.ExtensionService;
12 import org.jd.gui.spi.SourceLoader;
13
14 import java.io.File;
15 import java.util.Collection;
16
17 public class SourceLoaderService {
18 protected static final SourceLoaderService SOURCE_LOADER_SERVICE = new SourceLoaderService();
19
20 public static SourceLoaderService getInstance() { return SOURCE_LOADER_SERVICE; }
21
22 protected Collection<SourceLoader> providers = ExtensionService.getInstance().load(SourceLoader.class);
23
24 public String getSource(API api, Container.Entry entry) {
25 for (SourceLoader provider : providers) {
26 String source = provider.getSource(api, entry);
27
28 if ((source != null) && !source.isEmpty()) {
29 return source;
30 }
31 }
32
33 return null;
34 }
35
36 public String loadSource(API api, Container.Entry entry) {
37 for (SourceLoader provider : providers) {
38 String source = provider.loadSource(api, entry);
39
40 if ((source != null) && !source.isEmpty()) {
41 return source;
42 }
43 }
44
45 return null;
46 }
47
48 public File getSourceFile(API api, Container.Entry entry) {
49 for (SourceLoader provider : providers) {
50 File file = provider.loadSourceFile(api, entry);
51
52 if (file != null) {
53 return file;
54 }
55 }
56
57 return null;
58 }
59 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.SourceSaver;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15
16 public class SourceSaverService {
17 protected static final SourceSaverService SOURCE_SAVER_SERVICE = new SourceSaverService();
18
19 public static SourceSaverService getInstance() { return SOURCE_SAVER_SERVICE; }
20
21 protected HashMap<String, SourceSavers> mapProviders = new HashMap<>();
22
23 protected SourceSaverService() {
24 Collection<SourceSaver> providers = ExtensionService.getInstance().load(SourceSaver.class);
25
26 for (SourceSaver provider : providers) {
27 for (String selector : provider.getSelectors()) {
28 SourceSavers savers = mapProviders.get(selector);
29
30 if (savers == null) {
31 mapProviders.put(selector, savers=new SourceSavers());
32 }
33
34 savers.add(provider);
35 }
36 }
37 }
38
39 public SourceSaver get(Container.Entry entry) {
40 SourceSaver saver = get(entry.getContainer().getType(), entry);
41 return (saver != null) ? saver : get("*", entry);
42 }
43
44 protected SourceSaver get(String containerType, Container.Entry entry) {
45 String path = entry.getPath();
46 String type = entry.isDirectory() ? "dir" : "file";
47 String prefix = containerType + ':' + type;
48 SourceSaver saver = null;
49 SourceSavers savers = mapProviders.get(prefix + ':' + path);
50
51 if (savers != null) {
52 saver = savers.match(path);
53 }
54
55 if (saver == null) {
56 int lastSlashIndex = path.lastIndexOf('/');
57 String name = path.substring(lastSlashIndex+1);
58
59 savers = mapProviders.get(prefix + ":*/" + path);
60 if (savers != null) {
61 saver = savers.match(path);
62 }
63
64 if (saver == null) {
65 int index = name.lastIndexOf('.');
66
67 if (index != -1) {
68 String extension = name.substring(index + 1);
69
70 savers = mapProviders.get(prefix + ":*." + extension);
71 if (savers != null) {
72 saver = savers.match(path);
73 }
74 }
75
76 if (saver == null) {
77 savers = mapProviders.get(prefix + ":*");
78 if (savers != null) {
79 saver = savers.match(path);
80 }
81 }
82 }
83 }
84
85 return saver;
86 }
87
88 protected static class SourceSavers {
89 protected HashMap<String, SourceSaver> savers = new HashMap<>();
90 protected SourceSaver defaultSaver;
91
92 void add(SourceSaver saver) {
93 if (saver.getPathPattern() != null) {
94 savers.put(saver.getPathPattern().pattern(), saver);
95 } else {
96 defaultSaver = saver;
97 }
98 }
99
100 SourceSaver match(String path) {
101 for (SourceSaver saver : savers.values()) {
102 if (saver.getPathPattern().matcher(path).matches()) {
103 return saver;
104 }
105 }
106 return defaultSaver;
107 }
108 }
109 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.TreeNodeFactory;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15
16 public class TreeNodeFactoryService {
17 protected static final TreeNodeFactoryService TREE_NODE_FACTORY_SERVICE = new TreeNodeFactoryService();
18
19 public static TreeNodeFactoryService getInstance() { return TREE_NODE_FACTORY_SERVICE; }
20
21 protected HashMap<String, TreeNodeFactories> mapProviders = new HashMap<>();
22
23 protected TreeNodeFactoryService() {
24 Collection<TreeNodeFactory> providers = ExtensionService.getInstance().load(TreeNodeFactory.class);
25
26 for (TreeNodeFactory provider : providers) {
27 for (String selector : provider.getSelectors()) {
28 TreeNodeFactories factories = mapProviders.get(selector);
29
30 if (factories == null) {
31 mapProviders.put(selector, factories=new TreeNodeFactories());
32 }
33
34 factories.add(provider);
35 }
36 }
37 }
38
39 public TreeNodeFactory get(Container.Entry entry) {
40 TreeNodeFactory factory = get(entry.getContainer().getType(), entry);
41 return (factory != null) ? factory : get("*", entry);
42 }
43
44 protected TreeNodeFactory get(String containerType, Container.Entry entry) {
45 String path = entry.getPath();
46 String type = entry.isDirectory() ? "dir" : "file";
47 String prefix = containerType + ':' + type + ':';
48 TreeNodeFactory factory = null;
49 TreeNodeFactories factories = mapProviders.get(prefix + path);
50
51 if (factories != null) {
52 factory = factories.match(path);
53 }
54
55 if (factory == null) {
56 int lastSlashIndex = path.lastIndexOf('/');
57 String name = path.substring(lastSlashIndex+1);
58
59 factories = mapProviders.get(prefix + "*/" + name);
60 if (factories != null) {
61 factory = factories.match(path);
62 }
63
64 if (factory == null) {
65 int index = name.lastIndexOf('.');
66
67 if (index != -1) {
68 String extension = name.substring(index + 1);
69
70 factories = mapProviders.get(prefix + "*." + extension);
71 if (factories != null) {
72 factory = factories.match(path);
73 }
74 }
75
76 if (factory == null) {
77 factories = mapProviders.get(prefix + "*");
78 if (factories != null) {
79 factory = factories.match(path);
80 }
81 }
82 }
83 }
84
85 return factory;
86 }
87
88 protected static class TreeNodeFactories {
89 protected HashMap<String, TreeNodeFactory> factories = new HashMap<>();
90 protected TreeNodeFactory defaultFactory;
91
92 public void add(TreeNodeFactory factory) {
93 if (factory.getPathPattern() != null) {
94 factories.put(factory.getPathPattern().pattern(), factory);
95 } else {
96 defaultFactory = factory;
97 }
98 }
99
100 public TreeNodeFactory match(String path) {
101 for (TreeNodeFactory factory : factories.values()) {
102 if (factory.getPathPattern().matcher(path).matches()) {
103 return factory;
104 }
105 }
106 return defaultFactory;
107 }
108 }
109 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.type;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.TypeFactory;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.Map;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18
19 public class TypeFactoryService {
20 protected static final TypeFactoryService TYPE_FACTORY_SERVICE = new TypeFactoryService();
21
22 protected Map<String, TypeFactories> mapProviders;
23
24 public static TypeFactoryService getInstance() {
25 return TYPE_FACTORY_SERVICE;
26 }
27
28 protected TypeFactoryService() {
29 Collection<TypeFactory> providers = ExtensionService.getInstance().load(TypeFactory.class);
30
31 mapProviders = new HashMap<>();
32
33 for (TypeFactory provider : providers) {
34 for (String selector : provider.getSelectors()) {
35 TypeFactories typeFactories = mapProviders.get(selector);
36
37 if (typeFactories == null) {
38 mapProviders.put(selector, typeFactories=new TypeFactories());
39 }
40
41 typeFactories.add(provider);
42 }
43 }
44 }
45
46 public TypeFactory get(Container.Entry entry) {
47 TypeFactory typeFactory = get(entry.getContainer().getType(), entry);
48 return (typeFactory != null) ? typeFactory : get("*", entry);
49 }
50
51 public TypeFactory get(String containerType, Container.Entry entry) {
52 String path = entry.getPath();
53 String type = entry.isDirectory() ? "dir" : "file";
54 String prefix = containerType + ':' + type + ':';
55 TypeFactories typeFactories = mapProviders.get(prefix + path);
56 TypeFactory factory = null;
57
58 if (typeFactories != null) {
59 factory = typeFactories.match(path);
60 }
61
62 if (factory == null) {
63 int lastSlashIndex = path.lastIndexOf('/');
64 String name = path.substring(lastSlashIndex+1);
65
66 typeFactories = mapProviders.get(prefix + "*/" + name);
67
68 if (typeFactories != null) {
69 factory = typeFactories.match(path);
70 }
71
72 if (factory == null) {
73 int index = name.lastIndexOf('.');
74 if (index != -1) {
75 String extension = name.substring(index + 1);
76
77 typeFactories = mapProviders.get(prefix + "*." + extension);
78
79 if (typeFactories != null) {
80 factory = typeFactories.match(path);
81 }
82 }
83 if (factory == null) {
84 typeFactories = mapProviders.get(prefix + '*');
85
86 if (typeFactories != null) {
87 factory = typeFactories.match(path);
88 }
89 }
90 }
91 }
92
93 return factory;
94 }
95
96 protected static class TypeFactories {
97 protected HashMap<String, TypeFactory> factories = new HashMap<>();
98 protected TypeFactory defaultFactory;
99
100 public void add(TypeFactory factory) {
101 Pattern pathPattern = factory.getPathPattern();
102
103 if (pathPattern != null) {
104 factories.put(pathPattern.pattern(), factory);
105 } else {
106 defaultFactory = factory;
107 }
108 }
109
110 public TypeFactory match(String path) {
111 for (TypeFactory factory : factories.values()) {
112 Matcher matcher = factory.getPathPattern().matcher(path);
113
114 if (matcher.matches()) {
115 return factory;
116 }
117 }
118 return defaultFactory;
119 }
120 }
121 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.uriloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.service.extension.ExtensionService;
11 import org.jd.gui.spi.UriLoader;
12
13 import java.net.URI;
14 import java.util.Collection;
15 import java.util.HashMap;
16
17 public class UriLoaderService {
18 protected static final UriLoaderService URI_LOADER_SERVICE = new UriLoaderService();
19
20 public static UriLoaderService getInstance() { return URI_LOADER_SERVICE; }
21
22 protected HashMap<String, UriLoader> mapProviders = new HashMap<>();
23
24 protected UriLoaderService() {
25 Collection<UriLoader> providers = ExtensionService.getInstance().load(UriLoader.class);
26
27 for (UriLoader provider : providers) {
28 for (String scheme : provider.getSchemes()) {
29 mapProviders.put(scheme, provider);
30 }
31 }
32 }
33
34 public UriLoader get(API api, URI uri) {
35 UriLoader provider = mapProviders.get(uri.getScheme());
36
37 if (provider.accept(api, uri)) {
38 return provider;
39 } else {
40 return null;
41 }
42 }
43 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.exception;
8
9 public class ExceptionUtil {
10 public static boolean printStackTrace(Throwable throwable) {
11 throwable.printStackTrace();
12 return true;
13 }
14 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.function;
8
9 import java.util.Objects;
10
11 @FunctionalInterface
12 public interface TriConsumer<T, U, V> {
13 void accept(T t, U u, V v);
14
15 default TriConsumer<T, U, V> andThen(TriConsumer<? super T, ? super U, ? super V> after) {
16 Objects.requireNonNull(after);
17
18 return (a, b, c) -> {
19 accept(a, b, c);
20 after.accept(a, b, c);
21 };
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.net;
8
9 import org.jd.gui.util.exception.ExceptionUtil;
10
11 import java.io.IOException;
12 import java.io.ObjectInputStream;
13 import java.io.ObjectOutputStream;
14 import java.net.InetAddress;
15 import java.net.ServerSocket;
16 import java.net.Socket;
17 import java.util.function.Consumer;
18
19 public class InterProcessCommunicationUtil {
20 protected static final int PORT = 2015_6;
21
22 public static void listen(final Consumer<String[]> consumer) throws Exception {
23 final ServerSocket listener = new ServerSocket(PORT);
24
25 Runnable runnable = new Runnable() {
26 @Override
27 public void run() {
28 while (true) {
29 try (Socket socket = listener.accept();
30 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
31 // Receive args from another JD-GUI instance
32 String[] args = (String[])ois.readObject();
33 consumer.accept(args);
34 } catch (IOException|ClassNotFoundException e) {
35 assert ExceptionUtil.printStackTrace(e);
36 }
37 }
38 }
39 };
40
41 new Thread(runnable).start();
42 }
43
44 public static void send(String[] args) {
45 try (Socket socket = new Socket(InetAddress.getLocalHost(), PORT);
46 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
47 // Send args to the main JD-GUI instance
48 oos.writeObject(args);
49 } catch (IOException e) {
50 assert ExceptionUtil.printStackTrace(e);
51 }
52 }
53 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.net;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.api.model.Type;
13 import org.jd.gui.service.type.TypeFactoryService;
14 import org.jd.gui.spi.TypeFactory;
15 import org.jd.gui.util.exception.ExceptionUtil;
16
17 import java.net.URI;
18 import java.net.URISyntaxException;
19 import java.util.Collection;
20 import java.util.concurrent.Future;
21
22 public class UriUtil {
23 /*
24 * Convert inner entry URI to outer entry uri with a fragment. Example:
25 * file://codebase/a/b/c/D$E.class => file://codebase/a/b/c/D.class#typeDeclaration=D$E
26 */
27 public static URI createURI(API api, Collection<Future<Indexes>> collectionOfFutureIndexes, Container.Entry entry, String query, String fragment) {
28 URI uri = entry.getUri();
29
30 try {
31 String path = uri.getPath();
32 TypeFactory typeFactory = TypeFactoryService.getInstance().get(entry);
33
34 if (typeFactory != null) {
35 Type type = typeFactory.make(api, entry, fragment);
36
37 if (type != null) {
38 path = getOuterPath(collectionOfFutureIndexes, entry, type);
39 }
40 }
41
42 return new URI(uri.getScheme(), uri.getHost(), path, query, fragment);
43 } catch (URISyntaxException e) {
44 assert ExceptionUtil.printStackTrace(e);
45 return uri;
46 }
47 }
48
49 @SuppressWarnings("unchecked")
50 protected static String getOuterPath(Collection<Future<Indexes>> collectionOfFutureIndexes, Container.Entry entry, Type type) {
51 String outerName = type.getOuterName();
52
53 if (outerName != null) {
54 try {
55 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
56 if (futureIndexes.isDone()) {
57 Collection<Container.Entry> outerEntries = futureIndexes.get().getIndex("typeDeclarations").get(outerName);
58
59 if (outerEntries != null) {
60 for (Container.Entry outerEntry : outerEntries) {
61 if (outerEntry.getContainer() == entry.getContainer()) {
62 return outerEntry.getUri().getPath();
63 }
64 }
65 }
66 }
67 }
68 } catch (Exception e) {
69 assert ExceptionUtil.printStackTrace(e);
70 }
71 }
72
73 return entry.getUri().getPath();
74 }
75 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.swing;
8
9 import org.jd.gui.util.exception.ExceptionUtil;
10
11 import javax.swing.*;
12 import java.awt.*;
13 import java.awt.event.ActionEvent;
14 import java.awt.event.ActionListener;
15 import java.lang.reflect.Field;
16 import java.lang.reflect.Method;
17
18 /**
19 * See: https://www.ailis.de/~k/archives/67-Workaround-for-borderless-Java-Swing-menus-on-Linux.html
20 */
21 public class SwingUtil {
22 /*
23 * This is free and unencumbered software released into the public domain.
24 *
25 * Anyone is free to copy, modify, publish, use, compile, sell, or
26 * distribute this software, either in source code form or as a compiled
27 * binary, for any purpose, commercial or non-commercial, and by any
28 * means.
29 *
30 * In jurisdictions that recognize copyright laws, the author or authors
31 * of this software dedicate any and all copyright interest in the
32 * software to the public domain. We make this dedication for the benefit
33 * of the public at large and to the detriment of our heirs and
34 * successors. We intend this dedication to be an overt act of
35 * relinquishment in perpetuity of all present and future rights to this
36 * software under copyright law.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
41 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
42 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
43 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
44 * OTHER DEALINGS IN THE SOFTWARE.
45 *
46 * For more information, please refer to <http://unlicense.org/>
47 */
48
49 /**
50 * Swing menus are looking pretty bad on Linux when the GTK LaF is used (See
51 * bug #6925412). It will most likely never be fixed anytime soon so this
52 * method provides a workaround for it. It uses reflection to change the GTK
53 * style objects of Swing so popup menu borders have a minimum thickness of
54 * 1 and menu separators have a minimum vertical thickness of 1.
55 */
56 public static void installGtkPopupBugWorkaround() {
57 // Get current look-and-feel implementation class
58 LookAndFeel laf = UIManager.getLookAndFeel();
59 Class<?> lafClass = laf.getClass();
60
61 // Do nothing when not using the problematic LaF
62 if (!lafClass.getName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")) return;
63
64 // We do reflection from here on. Failure is silently ignored. The
65 // workaround is simply not installed when something goes wrong here
66 try {
67 // Access the GTK style factory
68 Field field = lafClass.getDeclaredField("styleFactory");
69 boolean accessible = field.isAccessible();
70 field.setAccessible(true);
71 Object styleFactory = field.get(laf);
72 field.setAccessible(accessible);
73
74 // Fix the horizontal and vertical thickness of popup menu style
75 Object style = getGtkStyle(styleFactory, new JPopupMenu(), "POPUP_MENU");
76 fixGtkThickness(style, "yThickness");
77 fixGtkThickness(style, "xThickness");
78
79 // Fix the vertical thickness of the popup menu separator style
80 style = getGtkStyle(styleFactory, new JSeparator(), "POPUP_MENU_SEPARATOR");
81 fixGtkThickness(style, "yThickness");
82 } catch (Exception e) {
83 // Silently ignored. Workaround can't be applied.
84 assert ExceptionUtil.printStackTrace(e);
85 }
86 }
87
88 /**
89 * Called internally by installGtkPopupBugWorkaround to fix the thickness
90 * of a GTK style field by setting it to a minimum value of 1.
91 *
92 * @param style
93 * The GTK style object.
94 * @param fieldName
95 * The field name.
96 * @throws Exception
97 * When reflection fails.
98 */
99 private static void fixGtkThickness(Object style, String fieldName) throws Exception {
100 Field field = style.getClass().getDeclaredField(fieldName);
101 boolean accessible = field.isAccessible();
102 field.setAccessible(true);
103 field.setInt(style, Math.max(1, field.getInt(style)));
104 field.setAccessible(accessible);
105 }
106
107 /**
108 * Called internally by installGtkPopupBugWorkaround. Returns a specific
109 * GTK style object.
110 *
111 * @param styleFactory
112 * The GTK style factory.
113 * @param component
114 * The target component of the style.
115 * @param regionName
116 * The name of the target region of the style.
117 * @return The GTK style.
118 * @throws Exception
119 * When reflection fails.
120 */
121 private static Object getGtkStyle(Object styleFactory, JComponent component, String regionName) throws Exception {
122 // Create the region object
123 Class<?> regionClass = Class.forName("javax.swing.plaf.synth.Region");
124 Field field = regionClass.getField(regionName);
125 Object region = field.get(regionClass);
126
127 // Get and return the style
128 Class<?> styleFactoryClass = styleFactory.getClass();
129 Method method = styleFactoryClass.getMethod("getStyle", JComponent.class, regionClass);
130 boolean accessible = method.isAccessible();
131 method.setAccessible(true);
132 Object style = method.invoke(styleFactory, component, region);
133 method.setAccessible(accessible);
134 return style;
135 }
136
137 public static void invokeLater(Runnable runnable) {
138 if (SwingUtilities.isEventDispatchThread()) {
139 runnable.run();
140 } else {
141 SwingUtilities.invokeLater(runnable);
142 }
143 }
144
145 public static Image getImage(String iconPath) {
146 return Toolkit.getDefaultToolkit().getImage(SwingUtil.class.getResource(iconPath));
147 }
148
149 public static ImageIcon newImageIcon(String iconPath) {
150 return new ImageIcon(getImage(iconPath));
151 }
152
153 public static Action newAction(String name, boolean enable, ActionListener listener) {
154 Action action = new AbstractAction(name) {
155 @Override
156 public void actionPerformed(ActionEvent actionEvent) {
157 listener.actionPerformed(actionEvent);
158 }
159 };
160 action.setEnabled(enable);
161 return action;
162 }
163
164 public static Action newAction(String name, ImageIcon icon, boolean enable, ActionListener listener) {
165 Action action = newAction(name, enable, listener);
166 action.putValue(Action.SMALL_ICON, icon);
167 return action;
168 }
169
170 public static Action newAction(ImageIcon icon, boolean enable, ActionListener listener) {
171 Action action = newAction(null, icon, enable, listener);
172 action.putValue(Action.SMALL_ICON, icon);
173 return action;
174 }
175
176 public static Action newAction(String name, ImageIcon icon, boolean enable, String shortDescription, ActionListener listener) {
177 Action action = newAction(name, icon, enable, listener);
178 action.putValue(Action.SHORT_DESCRIPTION, shortDescription);
179 return action;
180 }
181
182 public static Action newAction(String name, boolean enable, String shortDescription, ActionListener listener) {
183 Action action = newAction(name, enable, listener);
184 action.putValue(Action.SHORT_DESCRIPTION, shortDescription);
185 return action;
186 }
187 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.util.exception.ExceptionUtil;
10 import org.jd.gui.util.swing.SwingUtil;
11
12 import javax.swing.*;
13 import java.awt.*;
14 import java.awt.event.ActionEvent;
15 import java.awt.event.KeyEvent;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.net.URL;
19 import java.util.Enumeration;
20 import java.util.jar.Attributes;
21 import java.util.jar.Manifest;
22
23 public class AboutView {
24 protected JDialog aboutDialog;
25 protected JButton aboutOkButton;
26
27 public AboutView(JFrame mainFrame) {
28 // Build GUI
29 SwingUtil.invokeLater(() -> {
30 aboutDialog = new JDialog(mainFrame, "About Java Decompiler", false);
31 aboutDialog.setResizable(false);
32
33 JPanel panel = new JPanel();
34 panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
35 panel.setLayout(new BorderLayout());
36 aboutDialog.add(panel);
37
38 Box vbox = Box.createVerticalBox();
39 panel.add(vbox, BorderLayout.NORTH);
40 JPanel subpanel = new JPanel();
41 vbox.add(subpanel);
42 subpanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
43 subpanel.setBackground(Color.WHITE);
44 subpanel.setLayout(new BorderLayout());
45 JLabel logo = new JLabel(new ImageIcon(SwingUtil.getImage("/org/jd/gui/images/jd_icon_64.png")));
46 logo.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
47 subpanel.add(logo, BorderLayout.WEST);
48 Box subvbox = Box.createVerticalBox();
49 subvbox.setBorder(BorderFactory.createEmptyBorder(15,0,15,15));
50 subpanel.add(subvbox, BorderLayout.EAST);
51 Box hbox = Box.createHorizontalBox();
52 subvbox.add(hbox);
53 JLabel mainLabel = new JLabel("Java Decompiler");
54 mainLabel.setFont(UIManager.getFont("Label.font").deriveFont(Font.BOLD, 14));
55 hbox.add(mainLabel);
56 hbox.add(Box.createHorizontalGlue());
57 hbox = Box.createHorizontalBox();
58 subvbox.add(hbox);
59 JPanel subsubpanel = new JPanel();
60 hbox.add(subsubpanel);
61 subsubpanel.setLayout(new GridLayout(2,2));
62 subsubpanel.setOpaque(false);
63 subsubpanel.setBorder(BorderFactory.createEmptyBorder(5,10,5,5));
64
65 String jdGuiVersion = "SNAPSHOT";
66 String jdCoreVersion = "SNAPSHOT";
67
68 try {
69 Enumeration<URL> enumeration = AboutView.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
70
71 while (enumeration.hasMoreElements()) {
72 try (InputStream is = enumeration.nextElement().openStream()) {
73 Attributes attributes = new Manifest(is).getMainAttributes();
74 String attribute = attributes.getValue("JD-GUI-Version");
75
76 if (attribute != null) {
77 jdGuiVersion = attribute;
78 }
79
80 attribute = attributes.getValue("JD-Core-Version");
81
82 if (attribute != null) {
83 jdCoreVersion = attribute;
84 }
85 }
86 }
87 } catch (IOException e) {
88 assert ExceptionUtil.printStackTrace(e);
89 }
90
91 subsubpanel.add(new JLabel("JD-GUI"));
92 subsubpanel.add(new JLabel("version " + jdGuiVersion));
93 subsubpanel.add(new JLabel("JD-Core"));
94 subsubpanel.add(new JLabel("version " + jdCoreVersion));
95
96 hbox.add(Box.createHorizontalGlue());
97
98 hbox = Box.createHorizontalBox();
99 hbox.add(new JLabel("Copyright © 2008, 2019 Emmanuel Dupuy"));
100 hbox.add(Box.createHorizontalGlue());
101 subvbox.add(hbox);
102
103 vbox.add(Box.createVerticalStrut(10));
104
105 hbox = Box.createHorizontalBox();
106 panel.add(hbox, BorderLayout.SOUTH);
107 hbox.add(Box.createHorizontalGlue());
108 aboutOkButton = new JButton(" Ok ");
109 Action aboutOkActionListener = new AbstractAction() {
110 @Override public void actionPerformed(ActionEvent actionEvent) { aboutDialog.setVisible(false); }
111 };
112 aboutOkButton.addActionListener(aboutOkActionListener);
113 hbox.add(aboutOkButton);
114 hbox.add(Box.createHorizontalGlue());
115
116 // Last setup
117 JRootPane rootPane = aboutDialog.getRootPane();
118 rootPane.setDefaultButton(aboutOkButton);
119 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "AboutView.ok");
120 rootPane.getActionMap().put("AboutView.ok", aboutOkActionListener);
121
122 // Prepare to display
123 aboutDialog.pack();
124 });
125 }
126
127 public void show() {
128 SwingUtil.invokeLater(() -> {
129 // Show
130 aboutDialog.setLocationRelativeTo(aboutDialog.getParent());
131 aboutDialog.setVisible(true);
132 aboutOkButton.requestFocus();
133 });
134 }
135 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.api.feature.LineNumberNavigable;
10 import org.jd.gui.model.configuration.Configuration;
11 import org.jd.gui.util.swing.SwingUtil;
12
13 import javax.swing.*;
14 import javax.swing.event.DocumentEvent;
15 import javax.swing.event.DocumentListener;
16 import java.awt.*;
17 import java.awt.event.ActionEvent;
18 import java.awt.event.KeyAdapter;
19 import java.awt.event.KeyEvent;
20 import java.util.function.IntConsumer;
21
22 public class GoToView {
23 protected JDialog goToDialog;
24 protected JLabel goToEnterLineNumberLabel;
25 protected JTextField goToEnterLineNumberTextField;
26 protected JLabel goToEnterLineNumberErrorLabel;
27
28 protected LineNumberNavigable navigator;
29 protected IntConsumer okCallback;
30
31 public GoToView(Configuration configuration, JFrame mainFrame) {
32 // Build GUI
33 SwingUtil.invokeLater(() -> {
34 goToDialog = new JDialog(mainFrame, "Go to Line", false);
35 goToDialog.setResizable(false);
36
37 Box vbox = Box.createVerticalBox();
38 vbox.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
39 goToDialog.add(vbox);
40
41 // First label "Enter line number (1..xxx):"
42 Box hbox = Box.createHorizontalBox();
43 hbox.add(goToEnterLineNumberLabel = new JLabel());
44 hbox.add(Box.createHorizontalGlue());
45 vbox.add(hbox);
46
47 vbox.add(Box.createVerticalStrut(10));
48
49 // Text field
50 vbox.add(goToEnterLineNumberTextField = new JTextField(30));
51
52 vbox.add(Box.createVerticalStrut(10));
53
54 // Error label
55 hbox = Box.createHorizontalBox();
56 hbox.add(goToEnterLineNumberErrorLabel = new JLabel(" "));
57 goToEnterLineNumberTextField.addKeyListener(new KeyAdapter() {
58 @Override public void keyTyped(KeyEvent e) {
59 if (! Character.isDigit(e.getKeyChar())) {
60 e.consume();
61 }
62 }
63 });
64 hbox.add(Box.createHorizontalGlue());
65 vbox.add(hbox);
66
67 vbox.add(Box.createVerticalStrut(15));
68
69 // Buttons "Ok" and "Cancel"
70 hbox = Box.createHorizontalBox();
71 hbox.add(Box.createHorizontalGlue());
72 JButton goToOkButton = new JButton(" Ok ");
73 hbox.add(goToOkButton);
74 goToOkButton.setEnabled(false);
75 goToOkButton.addActionListener(e -> {
76 okCallback.accept(Integer.valueOf(goToEnterLineNumberTextField.getText()));
77 goToDialog.setVisible(false);
78 });
79 hbox.add(Box.createHorizontalStrut(5));
80 JButton goToCancelButton = new JButton("Cancel");
81 hbox.add(goToCancelButton);
82 Action goToCancelActionListener = new AbstractAction() {
83 public void actionPerformed(ActionEvent actionEvent) { goToDialog.setVisible(false); }
84 };
85 goToCancelButton.addActionListener(goToCancelActionListener);
86 vbox.add(hbox);
87
88 vbox.add(Box.createVerticalStrut(13));
89
90 // Last setup
91 JRootPane rootPane = goToDialog.getRootPane();
92 rootPane.setDefaultButton(goToOkButton);
93 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "OpenTypeView.cancel");
94 rootPane.getActionMap().put("OpenTypeView.cancel", goToCancelActionListener);
95
96 // Add main listener
97 goToEnterLineNumberTextField.getDocument().addDocumentListener(new DocumentListener() {
98 protected Color backgroundColor = UIManager.getColor("TextField.background");
99 protected Color errorBackgroundColor = Color.decode(configuration.getPreferences().get("JdGuiPreferences.errorBackgroundColor"));
100
101 @Override public void insertUpdate(DocumentEvent e) { onTextChange(); }
102 @Override public void removeUpdate(DocumentEvent e) { onTextChange(); }
103 @Override public void changedUpdate(DocumentEvent e) { onTextChange(); }
104
105 protected void onTextChange() {
106 String text = goToEnterLineNumberTextField.getText();
107
108 if (text.length() == 0) {
109 goToOkButton.setEnabled(false);
110 clearErrorMessage();
111 } else {
112 try {
113 int lineNumber = Integer.valueOf(text);
114
115 if (lineNumber > navigator.getMaximumLineNumber()) {
116 goToOkButton.setEnabled(false);
117 showErrorMessage("Line number out of range");
118 } else if (navigator.checkLineNumber(lineNumber)) {
119 goToOkButton.setEnabled(true);
120 clearErrorMessage();
121 } else {
122 goToOkButton.setEnabled(false);
123 showErrorMessage("Line number not found");
124 }
125 } catch (NumberFormatException e) {
126 goToOkButton.setEnabled(false);
127 showErrorMessage("Not a number");
128 }
129 }
130 }
131
132 protected void showErrorMessage(String message) {
133 goToEnterLineNumberErrorLabel.setText(message);
134 goToEnterLineNumberTextField.setBackground(errorBackgroundColor);
135 }
136
137 protected void clearErrorMessage() {
138 goToEnterLineNumberErrorLabel.setText(" ");
139 goToEnterLineNumberTextField.setBackground(backgroundColor);
140 }
141 });
142
143 // Prepare to display
144 goToDialog.pack();
145 goToDialog.setLocationRelativeTo(mainFrame);
146 });
147 }
148
149 public void show(LineNumberNavigable navigator, IntConsumer okCallback) {
150 this.navigator = navigator;
151 this.okCallback = okCallback;
152
153 SwingUtil.invokeLater(() -> {
154 // Init
155 goToEnterLineNumberLabel.setText("Enter line number (1.." + navigator.getMaximumLineNumber() + "):");
156 goToEnterLineNumberTextField.setText("");
157 // Show
158 goToDialog.setVisible(true);
159 goToEnterLineNumberTextField.requestFocus();
160 });
161 }
162 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.Constants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.*;
12 import org.jd.gui.model.configuration.Configuration;
13 import org.jd.gui.model.history.History;
14 import org.jd.gui.service.platform.PlatformService;
15 import org.jd.gui.util.exception.ExceptionUtil;
16 import org.jd.gui.view.component.IconButton;
17 import org.jd.gui.view.component.panel.MainTabbedPanel;
18
19 import javax.swing.*;
20 import javax.swing.border.Border;
21 import javax.swing.event.ChangeEvent;
22 import javax.swing.event.ChangeListener;
23 import javax.swing.text.BadLocationException;
24 import javax.swing.text.Document;
25 import java.awt.*;
26 import java.awt.event.ActionListener;
27 import java.awt.event.InputEvent;
28 import java.awt.event.KeyAdapter;
29 import java.awt.event.KeyEvent;
30 import java.io.File;
31 import java.net.URI;
32 import java.util.Arrays;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.function.Consumer;
36
37 import static org.jd.gui.util.swing.SwingUtil.*;
38
39 @SuppressWarnings("unchecked")
40 public class MainView<T extends JComponent & UriGettable> implements UriOpenable, PreferencesChangeListener {
41 protected History history;
42 protected Consumer<File> openFilesCallback;
43 protected JFrame mainFrame;
44 protected JMenu recentFiles = new JMenu("Recent Files");
45 protected Action closeAction;
46 protected Action openTypeAction;
47 protected Action backwardAction;
48 protected Action forwardAction;
49 protected MainTabbedPanel mainTabbedPanel;
50 protected Box findPanel;
51 protected JComboBox findComboBox;
52 protected JCheckBox findCaseSensitive;
53 protected Color findBackgroundColor;
54 protected Color findErrorBackgroundColor;
55
56 public MainView(
57 Configuration configuration, API api, History history,
58 ActionListener openActionListener,
59 ActionListener closeActionListener,
60 ActionListener saveActionListener,
61 ActionListener saveAllSourcesActionListener,
62 ActionListener exitActionListener,
63 ActionListener copyActionListener,
64 ActionListener pasteActionListener,
65 ActionListener selectAllActionListener,
66 ActionListener findActionListener,
67 ActionListener findPreviousActionListener,
68 ActionListener findNextActionListener,
69 ActionListener findCaseSensitiveActionListener,
70 Runnable findCriteriaChangedCallback,
71 ActionListener openTypeActionListener,
72 ActionListener openTypeHierarchyActionListener,
73 ActionListener goToActionListener,
74 ActionListener backwardActionListener,
75 ActionListener forwardActionListener,
76 ActionListener searchActionListener,
77 ActionListener jdWebSiteActionListener,
78 ActionListener jdGuiIssuesActionListener,
79 ActionListener jdCoreIssuesActionListener,
80 ActionListener preferencesActionListener,
81 ActionListener aboutActionListener,
82 Runnable panelClosedCallback,
83 Consumer<T> currentPageChangedCallback,
84 Consumer<File> openFilesCallback) {
85 this.history = history;
86 this.openFilesCallback = openFilesCallback;
87 // Build GUI
88 invokeLater(() -> {
89 mainFrame = new JFrame("Java Decompiler");
90 mainFrame.setIconImages(Arrays.asList(getImage("/org/jd/gui/images/jd_icon_32.png"), getImage("/org/jd/gui/images/jd_icon_64.png"), getImage("/org/jd/gui/images/jd_icon_128.png")));
91 mainFrame.setMinimumSize(new Dimension(Constants.MINIMAL_WIDTH, Constants.MINIMAL_HEIGHT));
92 mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
93
94 // Find panel //
95 Action findNextAction = newAction("Next", newImageIcon("/org/jd/gui/images/next_nav.png"), true, findNextActionListener);
96 findPanel = Box.createHorizontalBox();
97 findPanel.setVisible(false);
98 findPanel.add(new JLabel("Find: "));
99 findComboBox = new JComboBox();
100 findComboBox.setEditable(true);
101 JComponent editorComponent = (JComponent)findComboBox.getEditor().getEditorComponent();
102 editorComponent.addKeyListener(new KeyAdapter() {
103 protected String lastStr = "";
104
105 @Override
106 public void keyReleased(KeyEvent e) {
107 switch (e.getKeyCode()) {
108 case KeyEvent.VK_ESCAPE:
109 findPanel.setVisible(false);
110 break;
111 case KeyEvent.VK_ENTER:
112 String str = getFindText();
113 if (str.length() > 1) {
114 int index = ((DefaultComboBoxModel)findComboBox.getModel()).getIndexOf(str);
115 if(index != -1 ) {
116 findComboBox.removeItemAt(index);
117 }
118 findComboBox.insertItemAt(str, 0);
119 findComboBox.setSelectedIndex(0);
120 findNextAction.actionPerformed(null);
121 }
122 break;
123 default:
124 str = getFindText();
125 if (! lastStr.equals(str)) {
126 findCriteriaChangedCallback.run();
127 lastStr = str;
128 }
129 }
130 }
131 });
132 editorComponent.setOpaque(true);
133 findComboBox.setBackground(this.findBackgroundColor = editorComponent.getBackground());
134 this.findErrorBackgroundColor = Color.decode(configuration.getPreferences().get("JdGuiPreferences.errorBackgroundColor"));
135
136 findPanel.add(findComboBox);
137 findPanel.add(Box.createHorizontalStrut(5));
138 JToolBar toolBar = new JToolBar();
139 toolBar.setFloatable(false);
140 toolBar.setRollover(true);
141
142 IconButton findNextButton = new IconButton("Next", newAction(newImageIcon("/org/jd/gui/images/next_nav.png"), true, findNextActionListener));
143 toolBar.add(findNextButton);
144
145 toolBar.add(Box.createHorizontalStrut(5));
146
147 IconButton findPreviousButton = new IconButton("Previous", newAction(newImageIcon("/org/jd/gui/images/prev_nav.png"), true, findPreviousActionListener));
148 toolBar.add(findPreviousButton);
149
150 findPanel.add(toolBar);
151 findCaseSensitive = new JCheckBox();
152 findCaseSensitive.setAction(newAction("Case sensitive", true, findCaseSensitiveActionListener));
153 findPanel.add(findCaseSensitive);
154 findPanel.add(Box.createHorizontalGlue());
155
156 IconButton findCloseButton = new IconButton(newAction(null, null, true, e -> findPanel.setVisible(false)));
157 findCloseButton.setContentAreaFilled(false);
158 findCloseButton.setIcon(newImageIcon("/org/jd/gui/images/close.gif"));
159 findCloseButton.setRolloverIcon(newImageIcon("/org/jd/gui/images/close_active.gif"));
160 findPanel.add(findCloseButton);
161
162 if (PlatformService.getInstance().isMac()) {
163 findPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
164 Border border = BorderFactory.createEmptyBorder();
165 findNextButton.setBorder(border);
166 findPreviousButton.setBorder(border);
167 findCloseButton.setBorder(border);
168 } else {
169 findPanel.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 2));
170 }
171
172 // Actions //
173 boolean browser = Desktop.isDesktopSupported() ? Desktop.getDesktop().isSupported(Desktop.Action.BROWSE) : false;
174 Action openAction = newAction("Open File...", newImageIcon("/org/jd/gui/images/open.png"), true, "Open a file", openActionListener);
175 closeAction = newAction("Close", false, closeActionListener);
176 Action saveAction = newAction("Save", newImageIcon("/org/jd/gui/images/save.png"), false, saveActionListener);
177 Action saveAllSourcesAction = newAction("Save All Sources", newImageIcon("/org/jd/gui/images/save_all.png"), false, saveAllSourcesActionListener);
178 Action exitAction = newAction("Exit", true, "Quit this program", exitActionListener);
179 Action copyAction = newAction("Copy", newImageIcon("/org/jd/gui/images/copy.png"), false, copyActionListener);
180 Action pasteAction = newAction("Paste Log", newImageIcon("/org/jd/gui/images/paste.png"), true, pasteActionListener);
181 Action selectAllAction = newAction("Select all", false, selectAllActionListener);
182 Action findAction = newAction("Find...", false, findActionListener);
183 openTypeAction = newAction("Open Type...", newImageIcon("/org/jd/gui/images/open_type.png"), false, openTypeActionListener);
184 Action openTypeHierarchyAction = newAction("Open Type Hierarchy...", false, openTypeHierarchyActionListener);
185 Action goToAction = newAction("Go to Line...", false, goToActionListener);
186 backwardAction = newAction("Back", newImageIcon("/org/jd/gui/images/backward_nav.png"), false, backwardActionListener);
187 forwardAction = newAction("Forward", newImageIcon("/org/jd/gui/images/forward_nav.png"), false, forwardActionListener);
188 Action searchAction = newAction("Search...", newImageIcon("/org/jd/gui/images/search_src.png"), false, searchActionListener);
189 Action jdWebSiteAction = newAction("JD Web site", browser, "Open JD Web site", jdWebSiteActionListener);
190 Action jdGuiIssuesActionAction = newAction("JD-GUI issues", browser, "Open JD-GUI issues page", jdGuiIssuesActionListener);
191 Action jdCoreIssuesActionAction = newAction("JD-Core issues", browser, "Open JD-Core issues page", jdCoreIssuesActionListener);
192 Action preferencesAction = newAction("Preferences...", newImageIcon("/org/jd/gui/images/preferences.png"), true, "Open the preferences panel", preferencesActionListener);
193 Action aboutAction = newAction("About...", true, "About JD-GUI", aboutActionListener);
194
195 // Menu //
196 int menuShortcutKeyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
197 JMenuBar menuBar = new JMenuBar();
198 JMenu menu = new JMenu("File");
199 menuBar.add(menu);
200 menu.add(openAction).setAccelerator(KeyStroke.getKeyStroke('O', menuShortcutKeyMask));
201 menu.addSeparator();
202 menu.add(closeAction).setAccelerator(KeyStroke.getKeyStroke('W', menuShortcutKeyMask));
203 menu.addSeparator();
204 menu.add(saveAction).setAccelerator(KeyStroke.getKeyStroke('S', menuShortcutKeyMask));
205 menu.add(saveAllSourcesAction).setAccelerator(KeyStroke.getKeyStroke('S', menuShortcutKeyMask|InputEvent.ALT_MASK));
206 menu.addSeparator();
207 menu.add(recentFiles);
208 if (!PlatformService.getInstance().isMac()) {
209 menu.addSeparator();
210 menu.add(exitAction).setAccelerator(KeyStroke.getKeyStroke('X', InputEvent.ALT_MASK));
211 }
212 menu = new JMenu("Edit");
213 menuBar.add(menu);
214 menu.add(copyAction).setAccelerator(KeyStroke.getKeyStroke('C', menuShortcutKeyMask));
215 menu.add(pasteAction).setAccelerator(KeyStroke.getKeyStroke('V', menuShortcutKeyMask));
216 menu.addSeparator();
217 menu.add(selectAllAction).setAccelerator(KeyStroke.getKeyStroke('A', menuShortcutKeyMask));
218 menu.addSeparator();
219 menu.add(findAction).setAccelerator(KeyStroke.getKeyStroke('F', menuShortcutKeyMask));
220 menu = new JMenu("Navigation");
221 menuBar.add(menu);
222 menu.add(openTypeAction).setAccelerator(KeyStroke.getKeyStroke('T', menuShortcutKeyMask));
223 menu.add(openTypeHierarchyAction).setAccelerator(KeyStroke.getKeyStroke('H', menuShortcutKeyMask));
224 menu.addSeparator();
225 menu.add(goToAction).setAccelerator(KeyStroke.getKeyStroke('L', menuShortcutKeyMask));
226 menu.addSeparator();
227 menu.add(backwardAction).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.ALT_MASK));
228 menu.add(forwardAction).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.ALT_MASK));
229 menu = new JMenu("Search");
230 menuBar.add(menu);
231 menu.add(searchAction).setAccelerator(KeyStroke.getKeyStroke('S', menuShortcutKeyMask|InputEvent.SHIFT_MASK));
232 menu = new JMenu("Help");
233 menuBar.add(menu);
234 if (browser) {
235 menu.add(jdWebSiteAction);
236 menu.add(jdGuiIssuesActionAction);
237 menu.add(jdCoreIssuesActionAction);
238 menu.addSeparator();
239 }
240 menu.add(preferencesAction).setAccelerator(KeyStroke.getKeyStroke('P', menuShortcutKeyMask|InputEvent.SHIFT_MASK));
241 if (!PlatformService.getInstance().isMac()) {
242 menu.addSeparator();
243 menu.add(aboutAction).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
244 }
245 mainFrame.setJMenuBar(menuBar);
246
247 // Icon bar //
248 JPanel panel = new JPanel();
249 panel.setLayout(new BorderLayout());
250 toolBar = new JToolBar();
251 toolBar.setFloatable(false);
252 toolBar.setRollover(true);
253 toolBar.add(new IconButton(openAction));
254 toolBar.addSeparator();
255 toolBar.add(new IconButton(openTypeAction));
256 toolBar.add(new IconButton(searchAction));
257 toolBar.addSeparator();
258 toolBar.add(new IconButton(backwardAction));
259 toolBar.add(new IconButton(forwardAction));
260 panel.add(toolBar, BorderLayout.PAGE_START);
261
262 mainTabbedPanel = new MainTabbedPanel(api);
263 mainTabbedPanel.getPageChangedListeners().add(new PageChangeListener() {
264 protected JComponent currentPage = null;
265
266 @Override public <U extends JComponent & UriGettable> void pageChanged(U page) {
267 if (currentPage != page) {
268 // Update current page
269 currentPage = page;
270 currentPageChangedCallback.accept((T)page);
271
272 invokeLater(() -> {
273 if (page == null) {
274 // Update title
275 mainFrame.setTitle("Java Decompiler");
276 // Update menu
277 saveAction.setEnabled(false);
278 copyAction.setEnabled(false);
279 selectAllAction.setEnabled(false);
280 openTypeHierarchyAction.setEnabled(false);
281 goToAction.setEnabled(false);
282 // Update find panel
283 findPanel.setVisible(false);
284 } else {
285 // Update title
286 String path = page.getUri().getPath();
287 int index = path.lastIndexOf('/');
288 String name = (index == -1) ? path : path.substring(index + 1);
289 mainFrame.setTitle((name != null) ? name + " - Java Decompiler" : "Java Decompiler");
290 // Update history
291 history.add(page.getUri());
292 // Update history actions
293 updateHistoryActions();
294 // Update menu
295 saveAction.setEnabled(page instanceof ContentSavable);
296 copyAction.setEnabled(page instanceof ContentCopyable);
297 selectAllAction.setEnabled(page instanceof ContentSelectable);
298 findAction.setEnabled(page instanceof ContentSearchable);
299 openTypeHierarchyAction.setEnabled(page instanceof FocusedTypeGettable);
300 goToAction.setEnabled(page instanceof LineNumberNavigable);
301 // Update find panel
302 if (findPanel.isVisible()) {
303 findPanel.setVisible(page instanceof ContentSearchable);
304 }
305 }
306 });
307 }
308 }
309 });
310 mainTabbedPanel.getTabbedPane().addChangeListener(new ChangeListener() {
311 protected int lastTabCount = 0;
312
313 @Override
314 public void stateChanged(ChangeEvent e) {
315 int tabCount = mainTabbedPanel.getTabbedPane().getTabCount();
316 boolean enabled = (tabCount > 0);
317
318 closeAction.setEnabled(enabled);
319 openTypeAction.setEnabled(enabled);
320 searchAction.setEnabled(enabled);
321 saveAllSourcesAction.setEnabled((mainTabbedPanel.getTabbedPane().getSelectedComponent() instanceof SourcesSavable));
322
323 if (tabCount < lastTabCount) {
324 panelClosedCallback.run();
325 }
326
327 lastTabCount = tabCount;
328 }
329 });
330 mainTabbedPanel.preferencesChanged(configuration.getPreferences());
331 panel.add(mainTabbedPanel, BorderLayout.CENTER);
332
333 panel.add(findPanel, BorderLayout.PAGE_END);
334 mainFrame.add(panel);
335 });
336 }
337
338 public void show(Point location, Dimension size, boolean maximize) {
339 invokeLater(() -> {
340 // Set position, resize and show
341 mainFrame.setLocation(location);
342 mainFrame.setSize(size);
343 mainFrame.setExtendedState(maximize ? JFrame.MAXIMIZED_BOTH : 0);
344 mainFrame.setVisible(true);
345 });
346 }
347
348 public JFrame getMainFrame() {
349 return mainFrame;
350 }
351
352 public void showFindPanel() {
353 invokeLater(() -> {
354 findPanel.setVisible(true);
355 findComboBox.requestFocus();
356 });
357 }
358
359 public void setFindBackgroundColor(boolean wasFound) {
360 invokeLater(() -> {
361 findComboBox.getEditor().getEditorComponent().setBackground(wasFound ? findBackgroundColor : findErrorBackgroundColor);
362 });
363 }
364
365 public <T extends JComponent & UriGettable> void addMainPanel(String title, Icon icon, String tip, T component) {
366 invokeLater(() -> {
367 mainTabbedPanel.addPage(title, icon, tip, component);
368 });
369 }
370
371 public <T extends JComponent & UriGettable> List<T> getMainPanels() {
372 return mainTabbedPanel.getPages();
373 }
374
375 public <T extends JComponent & UriGettable> T getSelectedMainPanel() {
376 return (T)mainTabbedPanel.getTabbedPane().getSelectedComponent();
377 }
378
379 public void closeCurrentTab() {
380 invokeLater(() -> {
381 Component component = mainTabbedPanel.getTabbedPane().getSelectedComponent();
382 if (component instanceof PageClosable) {
383 if (!((PageClosable)component).closePage()) {
384 mainTabbedPanel.removeComponent(component);
385 }
386 } else {
387 mainTabbedPanel.removeComponent(component);
388 }
389 });
390 }
391
392 public void updateRecentFilesMenu(List<File> files) {
393 invokeLater(() -> {
394 recentFiles.removeAll();
395
396 for (File file : files) {
397 JMenuItem menuItem = new JMenuItem(reduceRecentFilePath(file.getAbsolutePath()));
398 menuItem.addActionListener(e -> openFilesCallback.accept(file));
399 recentFiles.add(menuItem);
400 }
401 });
402 }
403
404 public String getFindText() {
405 Document doc = ((JTextField)findComboBox.getEditor().getEditorComponent()).getDocument();
406
407 try {
408 return doc.getText(0, doc.getLength());
409 } catch (BadLocationException e) {
410 assert ExceptionUtil.printStackTrace(e);
411 return "";
412 }
413 }
414
415 public boolean getFindCaseSensitive() { return findCaseSensitive.isSelected(); }
416
417 public void updateHistoryActions() {
418 invokeLater(() -> {
419 backwardAction.setEnabled(history.canBackward());
420 forwardAction.setEnabled(history.canForward());
421 });
422 }
423
424 // --- Utils --- //
425 static String reduceRecentFilePath(String path) {
426 int lastSeparatorPosition = path.lastIndexOf(File.separatorChar);
427
428 if ((lastSeparatorPosition == -1) || (lastSeparatorPosition < Constants.RECENT_FILE_MAX_LENGTH)) {
429 return path;
430 }
431
432 int length = Constants.RECENT_FILE_MAX_LENGTH/2 - 2;
433 String left = path.substring(0, length);
434 String right = path.substring(path.length() - length);
435
436 return left + "..." + right;
437 }
438
439 // --- URIOpener --- //
440 @Override
441 public boolean openUri(URI uri) {
442 boolean success = mainTabbedPanel.openUri(uri);
443
444 if (success) {
445 closeAction.setEnabled(true);
446 openTypeAction.setEnabled(true);
447 }
448
449 return success;
450 }
451
452 // --- PreferencesChangeListener --- //
453 @Override
454 public void preferencesChanged(Map<String, String> preferences) {
455 mainTabbedPanel.preferencesChanged(preferences);
456 }
457 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.api.model.TreeNodeData;
13 import org.jd.gui.api.model.Type;
14 import org.jd.gui.util.exception.ExceptionUtil;
15 import org.jd.gui.util.function.TriConsumer;
16 import org.jd.gui.util.swing.SwingUtil;
17 import org.jd.gui.view.component.Tree;
18 import org.jd.gui.view.renderer.TreeNodeRenderer;
19
20 import javax.swing.*;
21 import javax.swing.event.TreeExpansionEvent;
22 import javax.swing.event.TreeExpansionListener;
23 import javax.swing.tree.DefaultMutableTreeNode;
24 import javax.swing.tree.DefaultTreeModel;
25 import javax.swing.tree.TreePath;
26 import java.awt.*;
27 import java.awt.event.*;
28 import java.util.*;
29 import java.util.List;
30 import java.util.concurrent.Future;
31
32 public class OpenTypeHierarchyView {
33 protected static final ImageIcon ROOT_CLASS_ICON = new ImageIcon(OpenTypeHierarchyView.class.getClassLoader().getResource("org/jd/gui/images/generate_class.png"));
34 protected static final ImageIcon ROOT_INTERFACE_ICON = new ImageIcon(OpenTypeHierarchyView.class.getClassLoader().getResource("org/jd/gui/images/generate_int.png"));
35
36 protected static final TreeNodeComparator TREE_NODE_COMPARATOR = new TreeNodeComparator();
37
38 protected API api;
39 protected Collection<Future<Indexes>> collectionOfFutureIndexes;
40
41 protected JDialog openTypeHierarchyDialog;
42 protected Tree openTypeHierarchyTree;
43
44 protected TriConsumer<Point, Collection<Container.Entry>, String> selectedTypeCallback;
45
46 public OpenTypeHierarchyView(API api, JFrame mainFrame, TriConsumer<Point, Collection<Container.Entry>, String> selectedTypeCallback) {
47 this.api = api;
48 this.selectedTypeCallback = selectedTypeCallback;
49 // Build GUI
50 SwingUtil.invokeLater(() -> {
51 openTypeHierarchyDialog = new JDialog(mainFrame, "Hierarchy Type", false);
52
53 JPanel panel = new JPanel();
54 panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
55 panel.setLayout(new BorderLayout());
56 openTypeHierarchyDialog.add(panel);
57
58 openTypeHierarchyTree = new Tree();
59 openTypeHierarchyTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
60 openTypeHierarchyTree.setCellRenderer(new TreeNodeRenderer());
61 openTypeHierarchyTree.addMouseListener(new MouseAdapter() {
62 @Override public void mouseClicked(MouseEvent e) {
63 if (e.getClickCount() == 2) {
64 onTypeSelected();
65 }
66 }
67 });
68 openTypeHierarchyTree.addTreeExpansionListener(new TreeExpansionListener() {
69 @Override public void treeExpanded(TreeExpansionEvent e) {
70 TreeNode node = (TreeNode)e.getPath().getLastPathComponent();
71 // Expand node and find the first leaf
72 while (node.getChildCount() > 0) {
73 if (((DefaultMutableTreeNode)node.getChildAt(0)).getUserObject() == null) {
74 // Remove dummy node and create children
75 populateTreeNode(node, null);
76 }
77 if (node.getChildCount() != 1) {
78 break;
79 }
80 node = ((TreeNode)node.getChildAt(0));
81 }
82 DefaultTreeModel model = (DefaultTreeModel)openTypeHierarchyTree.getModel();
83 model.reload((TreeNode)e.getPath().getLastPathComponent());
84 openTypeHierarchyTree.setSelectionPath(new TreePath(node.getPath()));
85 }
86 @Override public void treeCollapsed(TreeExpansionEvent e) {}
87 });
88 openTypeHierarchyTree.addKeyListener(new KeyAdapter() {
89 @Override public void keyPressed(KeyEvent e) {
90 if (e.getKeyCode() == KeyEvent.VK_F4) {
91 TreeNode node = (TreeNode)openTypeHierarchyTree.getLastSelectedPathComponent();
92 if (node != null) {
93 updateTree(node.entry, node.typeName);
94 }
95 }
96 }
97 });
98
99 JScrollPane openTypeHierarchyScrollPane = new JScrollPane(openTypeHierarchyTree);
100 openTypeHierarchyScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
101 openTypeHierarchyScrollPane.setPreferredSize(new Dimension(400, 150));
102 panel.add(openTypeHierarchyScrollPane, BorderLayout.CENTER);
103
104 // Buttons "Open" and "Cancel"
105 Box vbox = Box.createVerticalBox();
106 panel.add(vbox, BorderLayout.SOUTH);
107 vbox.add(Box.createVerticalStrut(25));
108 Box hbox = Box.createHorizontalBox();
109 vbox.add(hbox);
110 hbox.add(Box.createHorizontalGlue());
111 JButton openTypeHierarchyOpenButton = new JButton("Open");
112 hbox.add(openTypeHierarchyOpenButton);
113 openTypeHierarchyOpenButton.setEnabled(false);
114 openTypeHierarchyOpenButton.addActionListener(e -> onTypeSelected());
115 hbox.add(Box.createHorizontalStrut(5));
116 JButton openTypeHierarchyCancelButton = new JButton("Cancel");
117 hbox.add(openTypeHierarchyCancelButton);
118 Action openTypeHierarchyCancelActionListener = new AbstractAction() {
119 @Override public void actionPerformed(ActionEvent actionEvent) { openTypeHierarchyDialog.setVisible(false); }
120 };
121 openTypeHierarchyCancelButton.addActionListener(openTypeHierarchyCancelActionListener);
122
123 openTypeHierarchyTree.addTreeSelectionListener(e -> {
124 Object o = openTypeHierarchyTree.getLastSelectedPathComponent();
125 if (o != null) {
126 o = ((TreeNode)o).entry;
127 }
128 openTypeHierarchyOpenButton.setEnabled(o != null);
129 });
130
131 // Last setup
132 JRootPane rootPane = openTypeHierarchyDialog.getRootPane();
133 rootPane.setDefaultButton(openTypeHierarchyOpenButton);
134 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "OpenTypeHierarchyView.cancel");
135 rootPane.getActionMap().put("OpenTypeHierarchyView.cancel", openTypeHierarchyCancelActionListener);
136
137 openTypeHierarchyDialog.setMinimumSize(openTypeHierarchyDialog.getSize());
138
139 // Prepare to display
140 openTypeHierarchyDialog.pack();
141 openTypeHierarchyDialog.setLocationRelativeTo(mainFrame);
142 });
143 }
144
145 public void show(Collection<Future<Indexes>> collectionOfFutureIndexes, Container.Entry entry, String typeName) {
146 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
147 SwingUtil.invokeLater(() -> {
148 updateTree(entry, typeName);
149 openTypeHierarchyDialog.setVisible(true);
150 openTypeHierarchyTree.requestFocus();
151 });
152 }
153
154 public boolean isVisible() { return openTypeHierarchyDialog.isVisible(); }
155
156 public void showWaitCursor() {
157 SwingUtil.invokeLater(() -> openTypeHierarchyDialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)));
158 }
159
160 public void hideWaitCursor() {
161 SwingUtil.invokeLater(() -> openTypeHierarchyDialog.setCursor(Cursor.getDefaultCursor()));
162 }
163
164 public void updateTree(Collection<Future<Indexes>> collectionOfFutureIndexes) {
165 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
166 TreeNode selectedTreeNode = (TreeNode)openTypeHierarchyTree.getLastSelectedPathComponent();
167
168 if (selectedTreeNode != null) {
169 updateTree(selectedTreeNode.entry, selectedTreeNode.typeName);
170 }
171 }
172
173 protected void updateTree(Container.Entry entry, String typeName) {
174 SwingUtil.invokeLater(() -> {
175 // Clear tree
176 DefaultTreeModel model = (DefaultTreeModel)openTypeHierarchyTree.getModel();
177 DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
178 root.removeAllChildren();
179
180 TreeNode selectedTreeNode = createTreeNode(entry, typeName);
181 TreeNode parentTreeNode = createParentTreeNode(selectedTreeNode);
182
183 root.add(parentTreeNode);
184 model.reload();
185
186 if (selectedTreeNode != null) {
187 TreePath path = new TreePath(selectedTreeNode.getPath());
188 // Expand
189 openTypeHierarchyTree.expandPath(path);
190 // Scroll to show tree node
191 openTypeHierarchyTree.makeVisible(path);
192 Rectangle bounds = openTypeHierarchyTree.getPathBounds(path);
193
194 if(bounds != null) {
195 bounds.x = 0;
196
197 Rectangle lastRowBounds = openTypeHierarchyTree.getRowBounds(openTypeHierarchyTree.getRowCount()-1);
198
199 if (lastRowBounds != null) {
200 bounds.y = Math.max(bounds.y-30, 0);
201 bounds.height = Math.min(bounds.height+bounds.y+60, lastRowBounds.height+lastRowBounds.y) - bounds.y;
202 }
203
204 openTypeHierarchyTree.scrollRectToVisible(bounds);
205 openTypeHierarchyTree.scrollPathToVisible(path);
206 openTypeHierarchyTree.fireVisibleDataPropertyChange();
207 }
208 // Select tree node
209 openTypeHierarchyTree.setSelectionPath(path);
210 }
211 });
212 }
213
214 protected TreeNode createTreeNode(Container.Entry entry, String typeName) {
215 Type type = api.getTypeFactory(entry).make(api, entry, typeName);
216
217 typeName = type.getName();
218
219 List<Container.Entry> entries = getEntries(typeName);
220 TreeNode treeNode = new TreeNode(entry, typeName, entries, new TreeNodeBean(type));
221 List<String> childTypeNames = getSubTypeNames(typeName);
222
223 if (childTypeNames != null) {
224 // Add dummy node
225 treeNode.add(new DefaultMutableTreeNode());
226 }
227
228 return treeNode;
229 }
230
231 /**
232 * Create parent and sibling tree nodes
233 */
234 protected TreeNode createParentTreeNode(TreeNode treeNode) {
235 Type type = api.getTypeFactory(treeNode.entry).make(api, treeNode.entry, treeNode.typeName);
236 String superTypeName = type.getSuperName();
237
238 if (superTypeName != null) {
239 List<Container.Entry> superEntries = getEntries(superTypeName);
240
241 // Search entry in the sane container of 'entry'
242 Container.Entry superEntry = null;
243
244 if ((superEntries != null) && !superEntries.isEmpty()) {
245 for (Container.Entry se : superEntries) {
246 if (se.getContainer() == treeNode.entry.getContainer()) {
247 superEntry = se;
248 break;
249 }
250 }
251
252 if (superEntry == null) {
253 // Not found -> Choose 1st one
254 superEntry = superEntries.get(0);
255 }
256 } else {
257 superEntry = null;
258 }
259
260 if (superEntry != null) {
261 // Create parent tree node
262 TreeNode superTreeNode = createTreeNode(superEntry, superTypeName);
263 // Populate parent tree node
264 populateTreeNode(superTreeNode, treeNode);
265 // Recursive call
266 return createParentTreeNode(superTreeNode);
267 } else {
268 // Entry not found --> Most probable hypothesis : Java type entry
269 int lastPackageSeparatorIndex = superTypeName.lastIndexOf('/');
270 String package_ = superTypeName.substring(0, lastPackageSeparatorIndex).replace('/', '.');
271 String name = superTypeName.substring(lastPackageSeparatorIndex + 1).replace('$', '.');
272 String label = (package_ != null) ? name + " - " + package_ : name;
273 Icon icon = ((type.getFlags() & Type.FLAG_INTERFACE) == 0) ? ROOT_CLASS_ICON : ROOT_INTERFACE_ICON;
274 TreeNode rootTreeNode = new TreeNode(null, superTypeName, null, new TreeNodeBean(label, icon));
275
276 if (package_.startsWith("java.")) {
277 // If root type is a JDK type, do not create a tree node for each child types
278 rootTreeNode.add(treeNode);
279 } else {
280 populateTreeNode(rootTreeNode, treeNode);
281 }
282
283 return rootTreeNode;
284 }
285 } else {
286 // super type undefined
287 return treeNode;
288 }
289 }
290
291 /**
292 * @param superTreeNode node to populate
293 * @param activeTreeNode active child node
294 */
295 protected void populateTreeNode(TreeNode superTreeNode, TreeNode activeTreeNode) {
296 superTreeNode.removeAllChildren();
297
298 // Search preferred container: if 'superTreeNode' is a root with an unknown super entry, uses the container of active child node
299 Container.Entry notNullEntry = superTreeNode.entry;
300
301 if (notNullEntry == null) {
302 notNullEntry = activeTreeNode.entry;
303 }
304
305 Container preferredContainer = notNullEntry.getContainer();
306 String activeTypName = null;
307
308 if (activeTreeNode != null) {
309 activeTypName = activeTreeNode.typeName;
310 }
311
312 List<String> subTypeNames = getSubTypeNames(superTreeNode.typeName);
313 ArrayList<TreeNode> treeNodes = new ArrayList<>();
314
315 for (String subTypeName : subTypeNames) {
316 if (subTypeName.equals(activeTypName)) {
317 treeNodes.add(activeTreeNode);
318 } else {
319 // Search entry in the sane container of 'superTreeNode.entry'
320 List<Container.Entry> entries = getEntries(subTypeName);
321 Container.Entry entry = null;
322
323 for (Container.Entry e : entries) {
324 if (e.getContainer() == preferredContainer) {
325 entry = e;
326 }
327 }
328
329 if (entry == null) {
330 // Not found -> Choose 1st one
331 entry = entries.get(0);
332 }
333 if (entry != null) {
334 // Create type
335 Type t = api.getTypeFactory(entry).make(api, entry, subTypeName);
336 if (t != null) {
337 // Create tree node
338 treeNodes.add(createTreeNode(entry, t.getName()));
339 }
340 }
341 }
342 }
343
344 treeNodes.sort(TREE_NODE_COMPARATOR);
345
346 for (TreeNode treeNode : treeNodes) {
347 superTreeNode.add(treeNode);
348 }
349 }
350
351 public void focus() {
352 SwingUtil.invokeLater(() -> openTypeHierarchyTree.requestFocus());
353 }
354
355 protected void onTypeSelected() {
356 TreeNode selectedTreeNode = (TreeNode)openTypeHierarchyTree.getLastSelectedPathComponent();
357
358 if (selectedTreeNode != null) {
359 TreePath path = new TreePath(selectedTreeNode.getPath());
360 Rectangle bounds = openTypeHierarchyTree.getPathBounds(path);
361 Point listLocation = openTypeHierarchyTree.getLocationOnScreen();
362 Point leftBottom = new Point(listLocation.x+bounds.x, listLocation.y+bounds.y+bounds.height);
363 selectedTypeCallback.accept(leftBottom, selectedTreeNode.entries, selectedTreeNode.typeName);
364 }
365 }
366
367 @SuppressWarnings("unchecked")
368 protected List<String> getSubTypeNames(String typeName) {
369 ArrayList<String> result = new ArrayList<>();
370
371 try {
372 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
373 if (futureIndexes.isDone()) {
374 Map<String, Collection> subTypeNames = futureIndexes.get().getIndex("subTypeNames");
375 if (subTypeNames != null) {
376 Collection<String> collection = subTypeNames.get(typeName);
377 if (collection != null) {
378 for (String tn : collection) {
379 if (tn != null) {
380 result.add(tn);
381 }
382 }
383 }
384 }
385 }
386 }
387 } catch (Exception e) {
388 assert ExceptionUtil.printStackTrace(e);
389 }
390
391 return result;
392 }
393
394 @SuppressWarnings("unchecked")
395 protected List<Container.Entry> getEntries(String typeName) {
396 ArrayList<Container.Entry> result = new ArrayList<>();
397
398 try {
399 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
400 if (futureIndexes.isDone()) {
401 Map<String, Collection> typeDeclarations = futureIndexes.get().getIndex("typeDeclarations");
402 if (typeDeclarations != null) {
403 Collection<Container.Entry> collection = typeDeclarations.get(typeName);
404 if (collection != null) {
405 for (Container.Entry e : collection) {
406 if (e != null) {
407 result.add(e);
408 }
409 }
410 }
411 }
412 }
413 }
414 } catch (Exception e) {
415 assert ExceptionUtil.printStackTrace(e);
416 }
417
418 return result;
419 }
420
421 protected static class TreeNode extends DefaultMutableTreeNode {
422 Container.Entry entry;
423 String typeName;
424 List<Container.Entry> entries;
425
426 TreeNode(Container.Entry entry, String typeName, List<Container.Entry> entries, Object userObject) {
427 super(userObject);
428 this.entry = entry;
429 this.typeName = typeName;
430 this.entries = entries;
431 }
432 }
433
434 // Graphic data for renderer
435 protected static class TreeNodeBean implements TreeNodeData {
436 String label;
437 String tip;
438 Icon icon;
439 Icon openIcon;
440
441 TreeNodeBean(Type type) {
442 this.label = (type.getDisplayPackageName() != null) ? type.getDisplayTypeName() + " - " + type.getDisplayPackageName() : type.getDisplayTypeName();
443 this.icon = type.getIcon();
444 }
445
446 TreeNodeBean(String label, Icon icon) {
447 this.label = label;
448 this.icon = icon;
449 }
450
451 @Override public String getLabel() { return label; }
452 @Override public String getTip() { return tip; }
453 @Override public Icon getIcon() { return icon; }
454 @Override public Icon getOpenIcon() { return openIcon; }
455 }
456
457 protected static class TreeNodeComparator implements Comparator<TreeNode> {
458 @Override
459 public int compare(TreeNode tn1, TreeNode tn2) {
460 return ((TreeNodeBean)tn1.getUserObject()).label.compareTo(((TreeNodeBean)tn2.getUserObject()).label);
461 }
462 }
463 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Type;
12 import org.jd.gui.util.exception.ExceptionUtil;
13 import org.jd.gui.util.function.TriConsumer;
14 import org.jd.gui.util.swing.SwingUtil;
15 import org.jd.gui.view.bean.OpenTypeListCellBean;
16 import org.jd.gui.view.renderer.OpenTypeListCellRenderer;
17
18 import javax.swing.*;
19 import javax.swing.event.DocumentEvent;
20 import javax.swing.event.DocumentListener;
21 import javax.swing.text.BadLocationException;
22 import java.awt.*;
23 import java.awt.event.*;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Comparator;
27 import java.util.Map;
28 import java.util.function.Consumer;
29
30 public class OpenTypeView {
31 protected static final int MAX_LINE_COUNT = 80;
32 protected static final TypeNameComparator TYPE_NAME_COMPARATOR = new TypeNameComparator();
33
34 protected API api;
35
36 protected JDialog openTypeDialog;
37 protected JTextField openTypeEnterTextField;
38 protected JLabel openTypeMatchLabel;
39 protected JList openTypeList;
40
41 @SuppressWarnings("unchecked")
42 public OpenTypeView(API api, JFrame mainFrame, Consumer<String> changedPatternCallback, TriConsumer<Point, Collection<Container.Entry>, String> selectedTypeCallback) {
43 this.api = api;
44 // Build GUI
45 SwingUtil.invokeLater(() -> {
46 openTypeDialog = new JDialog(mainFrame, "Open Type", false);
47
48 JPanel panel = new JPanel();
49 panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
50 panel.setLayout(new BorderLayout());
51 openTypeDialog.add(panel);
52
53 // Box for "Select a type to open"
54 Box vbox = Box.createVerticalBox();
55 panel.add(vbox, BorderLayout.NORTH);
56
57 Box hbox = Box.createHorizontalBox();
58 hbox.add(new JLabel("Select a type to open (* = any string, ? = any character, TZ = TimeZone):"));
59 hbox.add(Box.createHorizontalGlue());
60 vbox.add(hbox);
61
62 vbox.add(Box.createVerticalStrut(10));
63
64 // Text field
65 vbox.add(openTypeEnterTextField = new JTextField(30));
66 openTypeEnterTextField.addKeyListener(new KeyAdapter() {
67 @Override public void keyTyped(KeyEvent e) {
68 switch (e.getKeyChar()) {
69 case '=': case '(': case ')': case '{': case '}': case '[': case ']':
70 e.consume();
71 break;
72 default:
73 if (Character.isDigit(e.getKeyChar()) && (openTypeEnterTextField.getText().length() == 0)) {
74 // First character can not be a digit
75 e.consume();
76 }
77 break;
78 }
79 }
80 @Override public void keyPressed(KeyEvent e) {
81 if ((e.getKeyCode() == KeyEvent.VK_DOWN) && (openTypeList.getModel().getSize() > 0)) {
82 openTypeList.setSelectedIndex(0);
83 openTypeList.requestFocus();
84 e.consume();
85 }
86 }
87 });
88 openTypeEnterTextField.addFocusListener(new FocusListener() {
89 @Override public void focusGained(FocusEvent e) { openTypeList.clearSelection(); }
90 @Override public void focusLost(FocusEvent e) {}
91 });
92 openTypeEnterTextField.getDocument().addDocumentListener(new DocumentListener() {
93 @Override public void insertUpdate(DocumentEvent e) { call(e); }
94 @Override public void removeUpdate(DocumentEvent e) { call(e); }
95 @Override public void changedUpdate(DocumentEvent e) { call(e); }
96 protected void call(DocumentEvent e) {
97 try {
98 changedPatternCallback.accept(e.getDocument().getText(0, e.getDocument().getLength()));
99 } catch (BadLocationException ex) {
100 assert ExceptionUtil.printStackTrace(ex);
101 }
102 }
103 });
104
105 vbox.add(Box.createVerticalStrut(10));
106
107 hbox = Box.createHorizontalBox();
108 hbox.add(openTypeMatchLabel = new JLabel("Matching types:"));
109 hbox.add(Box.createHorizontalGlue());
110 vbox.add(hbox);
111
112 vbox.add(Box.createVerticalStrut(10));
113
114 // List of types
115 JScrollPane scrollPane = new JScrollPane(openTypeList = new JList());
116 openTypeList.addKeyListener(new KeyAdapter() {
117 @Override public void keyPressed(KeyEvent e) {
118 if ((e.getKeyCode() == KeyEvent.VK_UP) && (openTypeList.getSelectedIndex() == 0)) {
119 openTypeEnterTextField.requestFocus();
120 e.consume();
121 }
122 }
123 });
124 openTypeList.setModel(new DefaultListModel<OpenTypeListCellBean>());
125 openTypeList.setCellRenderer(new OpenTypeListCellRenderer());
126 openTypeList.addMouseListener(new MouseAdapter() {
127 @Override public void mouseClicked(MouseEvent e) {
128 if (e.getClickCount() == 2) {
129 onTypeSelected(selectedTypeCallback);
130 }
131 }
132 });
133 scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
134 scrollPane.setPreferredSize(new Dimension(400, 150));
135 panel.add(scrollPane, BorderLayout.CENTER);
136
137 // Buttons "Open" and "Cancel"
138 vbox = Box.createVerticalBox();
139 panel.add(vbox, BorderLayout.SOUTH);
140 vbox.add(Box.createVerticalStrut(25));
141 vbox.add(hbox = Box.createHorizontalBox());
142 hbox.add(Box.createHorizontalGlue());
143 JButton openTypeOpenButton = new JButton("Open");
144 hbox.add(openTypeOpenButton);
145 openTypeOpenButton.setEnabled(false);
146 openTypeOpenButton.addActionListener(e -> onTypeSelected(selectedTypeCallback));
147 hbox.add(Box.createHorizontalStrut(5));
148 JButton openTypeCancelButton = new JButton("Cancel");
149 hbox.add(openTypeCancelButton);
150 Action openTypeCancelActionListener = new AbstractAction() {
151 @Override public void actionPerformed(ActionEvent actionEvent) { openTypeDialog.setVisible(false); }
152 };
153 openTypeCancelButton.addActionListener(openTypeCancelActionListener);
154
155 // Last setup
156 JRootPane rootPane = openTypeDialog.getRootPane();
157 rootPane.setDefaultButton(openTypeOpenButton);
158 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "OpenTypeView.cancel");
159 rootPane.getActionMap().put("OpenTypeView.cancel", openTypeCancelActionListener);
160
161 openTypeList.addListSelectionListener(e -> openTypeOpenButton.setEnabled(openTypeList.getSelectedValue() != null));
162
163 openTypeDialog.setMinimumSize(openTypeDialog.getSize());
164
165 // Prepare to display
166 openTypeDialog.pack();
167 openTypeDialog.setLocationRelativeTo(mainFrame);
168 });
169 }
170
171 public void show() {
172 SwingUtil.invokeLater(() -> {
173 // Init
174 openTypeEnterTextField.selectAll();
175 // Show
176 openTypeDialog.setVisible(true);
177 openTypeEnterTextField.requestFocus();
178 });
179 }
180
181 public boolean isVisible() { return openTypeDialog.isVisible(); }
182
183 public String getPattern() { return openTypeEnterTextField.getText(); }
184
185 public void showWaitCursor() {
186 SwingUtil.invokeLater(() -> openTypeDialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)));
187 }
188
189 public void hideWaitCursor() {
190 SwingUtil.invokeLater(() -> openTypeDialog.setCursor(Cursor.getDefaultCursor()));
191 }
192
193 @SuppressWarnings("unchecked")
194 public void updateList(Map<String, Collection<Container.Entry>> map) {
195 SwingUtil.invokeLater(() -> {
196 DefaultListModel model = (DefaultListModel)openTypeList.getModel();
197 ArrayList<String> typeNames = new ArrayList<>(map.keySet());
198 int index = 0;
199
200 typeNames.sort(TYPE_NAME_COMPARATOR);
201
202 model.removeAllElements();
203
204 for (String typeName : typeNames) {
205 if (index < MAX_LINE_COUNT) {
206 Collection<Container.Entry> entries = map.get(typeName);
207 Container.Entry firstEntry = entries.iterator().next();
208 Type type = api.getTypeFactory(firstEntry).make(api, firstEntry, typeName);
209
210 if (type != null) {
211 model.addElement(new OpenTypeListCellBean(type.getDisplayTypeName(), type.getDisplayPackageName(), type.getIcon(), entries, typeName));
212 } else {
213 model.addElement(new OpenTypeListCellBean(typeName, entries, typeName));
214 }
215 } else if (index == MAX_LINE_COUNT) {
216 model.addElement(null);
217 }
218 }
219
220 int count = typeNames.size();
221
222 switch (count) {
223 case 0:
224 openTypeMatchLabel.setText("Matching types:");
225 break;
226 case 1:
227 openTypeMatchLabel.setText("1 matching type:");
228 break;
229 default:
230 openTypeMatchLabel.setText(count + " matching types:");
231 }
232 });
233 }
234
235 public void focus() {
236 SwingUtil.invokeLater(() -> {
237 openTypeList.requestFocus();
238 });
239 }
240
241 protected void onTypeSelected(TriConsumer<Point, Collection<Container.Entry>, String> selectedTypeCallback) {
242 SwingUtil.invokeLater(() -> {
243 int index = openTypeList.getSelectedIndex();
244
245 if (index != -1) {
246 OpenTypeListCellBean selectedCellBean = (OpenTypeListCellBean)openTypeList.getModel().getElementAt(index);
247 Point listLocation = openTypeList.getLocationOnScreen();
248 Rectangle cellBound = openTypeList.getCellBounds(index, index);
249 Point leftBottom = new Point(listLocation.x + cellBound.x, listLocation.y + cellBound.y + cellBound.height);
250 selectedTypeCallback.accept(leftBottom, selectedCellBean.entries, selectedCellBean.typeName);
251 }
252 });
253 }
254
255 protected static class TypeNameComparator implements Comparator<String> {
256 @Override
257 public int compare(String tn1, String tn2) {
258 int lasPackageSeparatorIndex = tn1.lastIndexOf('/');
259 String shortName1 = tn1.substring(lasPackageSeparatorIndex+1);
260
261 lasPackageSeparatorIndex = tn2.lastIndexOf('/');
262 String shortName2 = tn2.substring(lasPackageSeparatorIndex+1);
263
264 return shortName1.compareTo(shortName2);
265 }
266 }
267 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.model.configuration.Configuration;
10 import org.jd.gui.spi.PreferencesPanel;
11 import org.jd.gui.util.swing.SwingUtil;
12
13 import javax.swing.*;
14 import java.awt.*;
15 import java.awt.event.ActionEvent;
16 import java.awt.event.KeyEvent;
17 import java.util.*;
18
19 public class PreferencesView implements PreferencesPanel.PreferencesPanelChangeListener {
20 protected Map<String, String> preferences;
21 protected Collection<PreferencesPanel> panels;
22 protected HashMap<PreferencesPanel, Boolean> valids = new HashMap<>();
23
24 protected JDialog preferencesDialog;
25 protected JButton preferencesOkButton = new JButton();
26
27 protected Runnable okCallback;
28
29 public PreferencesView(Configuration configuration, JFrame mainFrame, Collection<PreferencesPanel> panels) {
30 this.preferences = configuration.getPreferences();
31 this.panels = panels;
32 // Build GUI
33 SwingUtil.invokeLater(() -> {
34 preferencesDialog = new JDialog(mainFrame, "Preferences", false);
35
36 JPanel panel = new JPanel();
37 panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
38 panel.setLayout(new BorderLayout());
39 preferencesDialog.add(panel);
40
41 // Box for preferences panels
42 Box preferencesPanels = Box.createVerticalBox();
43 preferencesPanels.setBackground(panel.getBackground());
44 preferencesPanels.setOpaque(true);
45 Color errorBackgroundColor = Color.decode(configuration.getPreferences().get("JdGuiPreferences.errorBackgroundColor"));
46
47 // Group "PreferencesPanel" by group name
48 HashMap<String, ArrayList<PreferencesPanel>> groups = new HashMap<>();
49 ArrayList<String> sortedGroupNames = new ArrayList<>();
50
51 for (PreferencesPanel pp : panels) {
52 ArrayList<PreferencesPanel> pps = groups.get(pp.getPreferencesGroupTitle());
53
54 pp.init(errorBackgroundColor);
55 pp.addPreferencesChangeListener(this);
56
57 if (pps == null) {
58 String groupNames = pp.getPreferencesGroupTitle();
59 groups.put(groupNames, pps=new ArrayList<>());
60 sortedGroupNames.add(groupNames);
61 }
62
63 pps.add(pp);
64 }
65
66 Collections.sort(sortedGroupNames);
67
68 // Add preferences panels
69 for (String groupName : sortedGroupNames) {
70 Box vbox = Box.createVerticalBox();
71 vbox.setBorder(BorderFactory.createTitledBorder(groupName));
72
73 ArrayList<PreferencesPanel> sortedPreferencesPanels = groups.get(groupName);
74 Collections.sort(sortedPreferencesPanels, new PreferencesPanelComparator());
75
76 for (PreferencesPanel pp : sortedPreferencesPanels) {
77 // Add title
78 Box hbox = Box.createHorizontalBox();
79 JLabel title = new JLabel(pp.getPreferencesPanelTitle());
80 title.setFont(title.getFont().deriveFont(Font.BOLD));
81 hbox.add(title);
82 hbox.add(Box.createHorizontalGlue());
83 hbox.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
84 vbox.add(hbox);
85 // Add panel
86 JComponent component = pp.getPanel();
87 component.setMaximumSize(new Dimension(component.getMaximumSize().width, component.getPreferredSize().height));
88 vbox.add(component);
89 }
90
91 preferencesPanels.add(vbox);
92 }
93
94 JScrollPane preferencesScrollPane = new JScrollPane(preferencesPanels);
95 preferencesScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
96 preferencesScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
97 panel.add(preferencesScrollPane, BorderLayout.CENTER);
98
99 Box vbox = Box.createVerticalBox();
100 panel.add(vbox, BorderLayout.SOUTH);
101
102 vbox.add(Box.createVerticalStrut(15));
103
104 // Buttons "Ok" and "Cancel"
105 Box hbox = Box.createHorizontalBox();
106 hbox.add(Box.createHorizontalGlue());
107 preferencesOkButton.setText(" Ok ");
108 preferencesOkButton.addActionListener(e -> {
109 for (PreferencesPanel pp : panels) {
110 pp.savePreferences(preferences);
111 }
112 preferencesDialog.setVisible(false);
113 okCallback.run();
114 });
115 hbox.add(preferencesOkButton);
116 hbox.add(Box.createHorizontalStrut(5));
117 JButton preferencesCancelButton = new JButton("Cancel");
118 Action preferencesCancelActionListener = new AbstractAction() {
119 public void actionPerformed(ActionEvent actionEvent) { preferencesDialog.setVisible(false); }
120 };
121 preferencesCancelButton.addActionListener(preferencesCancelActionListener);
122 hbox.add(preferencesCancelButton);
123 vbox.add(hbox);
124
125 // Last setup
126 JRootPane rootPane = preferencesDialog.getRootPane();
127 rootPane.setDefaultButton(preferencesOkButton);
128 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "PreferencesDescription.cancel");
129 rootPane.getActionMap().put("PreferencesDescription.cancel", preferencesCancelActionListener);
130
131 // Size of the screen
132 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
133 // Height of the task bar
134 Insets scnMax = Toolkit.getDefaultToolkit().getScreenInsets(preferencesDialog.getGraphicsConfiguration());
135 // screen height in pixels without taskbar
136 int taskBarHeight = scnMax.bottom + scnMax.top;
137 int maxHeight = screenSize.height - taskBarHeight;
138 int preferredHeight = preferencesPanels.getPreferredSize().height + 2;
139
140 if (preferredHeight > maxHeight) {
141 preferredHeight = maxHeight;
142 }
143
144 preferencesScrollPane.setPreferredSize(new Dimension(400, preferredHeight));
145 preferencesDialog.setMinimumSize(new Dimension(300, 200));
146
147 // Prepare to display
148 preferencesDialog.pack();
149 preferencesDialog.setLocationRelativeTo(mainFrame);
150 });
151 }
152
153 public void show(Runnable okCallback) {
154 this.okCallback = okCallback;
155
156 SwingUtilities.invokeLater(() -> {
157 // Init
158 for (PreferencesPanel pp : panels) {
159 pp.loadPreferences(preferences);
160 }
161 // Show
162 preferencesDialog.setVisible(true);
163 });
164 }
165
166 // --- PreferencesPanel.PreferencesChangeListener --- //
167 public void preferencesPanelChanged(PreferencesPanel source) {
168 SwingUtil.invokeLater(() -> {
169 boolean valid = source.arePreferencesValid();
170
171 valids.put(source, Boolean.valueOf(valid));
172
173 if (valid) {
174 for (PreferencesPanel pp : panels) {
175 if (valids.get(pp) == Boolean.FALSE) {
176 preferencesOkButton.setEnabled(false);
177 return;
178 }
179 }
180 preferencesOkButton.setEnabled(true);
181 } else {
182 preferencesOkButton.setEnabled(false);
183 }
184 });
185 }
186
187 protected static class PreferencesPanelComparator implements Comparator<PreferencesPanel> {
188 @Override
189 public int compare(PreferencesPanel pp1, PreferencesPanel pp2) {
190 return pp1.getPreferencesPanelTitle().compareTo(pp2.getPreferencesPanelTitle());
191 }
192 }
193 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.util.swing.SwingUtil;
10
11 import javax.swing.*;
12 import java.awt.event.ActionEvent;
13 import java.awt.event.KeyEvent;
14 import java.awt.event.WindowAdapter;
15 import java.awt.event.WindowEvent;
16 import java.io.File;
17
18 public class SaveAllSourcesView {
19 protected JDialog saveAllSourcesDialog;
20 protected JLabel saveAllSourcesLabel;
21 protected JProgressBar saveAllSourcesProgressBar;
22
23 public SaveAllSourcesView(JFrame mainFrame, Runnable cancelCallback) {
24 // Build GUI
25 SwingUtil.invokeLater(() -> {
26 saveAllSourcesDialog = new JDialog(mainFrame, "Save All Sources", false);
27 saveAllSourcesDialog.setResizable(false);
28 saveAllSourcesDialog.addWindowListener(new WindowAdapter() {
29 @Override public void windowClosing(WindowEvent e) {
30 cancelCallback.run();
31 }
32 });
33
34 Box vbox = Box.createVerticalBox();
35 vbox.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
36 saveAllSourcesDialog.add(vbox);
37
38 // First label "Saving 'file' ..."
39 Box hbox = Box.createHorizontalBox();
40 hbox.add(saveAllSourcesLabel = new JLabel());
41 hbox.add(Box.createHorizontalGlue());
42 vbox.add(hbox);
43
44 vbox.add(Box.createVerticalStrut(10));
45
46 vbox.add(saveAllSourcesProgressBar = new JProgressBar());
47
48 vbox.add(Box.createVerticalStrut(15));
49
50 // Button "Cancel"
51 hbox = Box.createHorizontalBox();
52 hbox.add(Box.createHorizontalGlue());
53 JButton saveAllSourcesCancelButton = new JButton("Cancel");
54 Action saveAllSourcesCancelActionListener = new AbstractAction() {
55 public void actionPerformed(ActionEvent actionEvent) {
56 cancelCallback.run();
57 saveAllSourcesDialog.setVisible(false);
58 }
59 };
60 saveAllSourcesCancelButton.addActionListener(saveAllSourcesCancelActionListener);
61 hbox.add(saveAllSourcesCancelButton);
62 vbox.add(hbox);
63
64 // Last setup
65 JRootPane rootPane = saveAllSourcesDialog.getRootPane();
66 rootPane.setDefaultButton(saveAllSourcesCancelButton);
67 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "SaveAllSourcesView.cancel");
68 rootPane.getActionMap().put("SaveAllSourcesView.cancel", saveAllSourcesCancelActionListener);
69
70 // Prepare to display
71 saveAllSourcesDialog.pack();
72 });
73 }
74
75 public void show(File file) {
76 SwingUtil.invokeLater(() -> {
77 // Init
78 saveAllSourcesLabel.setText("Saving '" + file.getAbsolutePath() + "'...");
79 saveAllSourcesProgressBar.setValue(0);
80 saveAllSourcesProgressBar.setMaximum(10);
81 saveAllSourcesProgressBar.setIndeterminate(true);
82 saveAllSourcesDialog.pack();
83 // Show
84 saveAllSourcesDialog.setLocationRelativeTo(saveAllSourcesDialog.getParent());
85 saveAllSourcesDialog.setVisible(true);
86 });
87 }
88
89 public boolean isVisible() { return saveAllSourcesDialog.isVisible(); }
90
91 public void setMaxValue(int maxValue) {
92 SwingUtil.invokeLater(() -> {
93 if (maxValue > 0) {
94 saveAllSourcesProgressBar.setMaximum(maxValue);
95 saveAllSourcesProgressBar.setIndeterminate(false);
96 } else {
97 saveAllSourcesProgressBar.setIndeterminate(true);
98 }
99 });
100 }
101
102 public void updateProgressBar(int value) {
103 SwingUtil.invokeLater(() -> {
104 saveAllSourcesProgressBar.setValue(value);
105 });
106 }
107
108 public void hide() {
109 SwingUtil.invokeLater(() -> {
110 saveAllSourcesDialog.setVisible(false);
111 });
112 }
113
114 public void showActionFailedDialog() {
115 SwingUtil.invokeLater(() -> {
116 JOptionPane.showMessageDialog(saveAllSourcesDialog, "'Save All Sources' action failed.", "Error", JOptionPane.ERROR_MESSAGE);
117 });
118 }
119 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.TreeNodeExpandable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.model.container.DelegatingFilterContainer;
15 import org.jd.gui.spi.TreeNodeFactory;
16 import org.jd.gui.util.function.TriConsumer;
17 import org.jd.gui.util.swing.SwingUtil;
18 import org.jd.gui.view.component.Tree;
19 import org.jd.gui.view.renderer.TreeNodeRenderer;
20
21 import javax.swing.*;
22 import javax.swing.event.DocumentEvent;
23 import javax.swing.event.DocumentListener;
24 import javax.swing.event.TreeExpansionEvent;
25 import javax.swing.event.TreeExpansionListener;
26 import javax.swing.tree.DefaultMutableTreeNode;
27 import javax.swing.tree.DefaultTreeModel;
28 import javax.swing.tree.TreePath;
29 import java.awt.*;
30 import java.awt.event.*;
31 import java.net.URI;
32 import java.util.*;
33 import java.util.function.BiConsumer;
34
35 public class SearchInConstantPoolsView<T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> {
36 protected static final ContainerComparator CONTAINER_COMPARATOR = new ContainerComparator();
37
38 public static final int SEARCH_TYPE = 1;
39 public static final int SEARCH_CONSTRUCTOR = 2;
40 public static final int SEARCH_METHOD = 4;
41 public static final int SEARCH_FIELD = 8;
42 public static final int SEARCH_STRING = 16;
43 public static final int SEARCH_MODULE = 32;
44 public static final int SEARCH_DECLARATION = 64;
45 public static final int SEARCH_REFERENCE = 128;
46
47 protected API api;
48 protected Set<URI> accepted = new HashSet<>();
49 protected Set<URI> expanded = new HashSet<>();
50
51 protected JDialog searchInConstantPoolsDialog;
52 protected JTextField searchInConstantPoolsEnterTextField;
53 protected JLabel searchInConstantPoolsLabel;
54 protected JCheckBox searchInConstantPoolsCheckBoxType;
55 protected JCheckBox searchInConstantPoolsCheckBoxField;
56 protected JCheckBox searchInConstantPoolsCheckBoxConstructor;
57 protected JCheckBox searchInConstantPoolsCheckBoxMethod;
58 protected JCheckBox searchInConstantPoolsCheckBoxString;
59 protected JCheckBox searchInConstantPoolsCheckBoxModule;
60 protected JCheckBox searchInConstantPoolsCheckBoxDeclarations;
61 protected JCheckBox searchInConstantPoolsCheckBoxReferences;
62 protected Tree searchInConstantPoolsTree;
63
64 @SuppressWarnings("unchecked")
65 public SearchInConstantPoolsView(
66 API api, JFrame mainFrame,
67 BiConsumer<String, Integer> changedPatternCallback,
68 TriConsumer<URI, String, Integer> selectedTypeCallback) {
69 this.api = api;
70 // Build GUI
71 SwingUtil.invokeLater(() -> {
72 searchInConstantPoolsDialog = new JDialog(mainFrame, "Search", false);
73
74 JPanel panel = new JPanel();
75 panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
76 panel.setLayout(new BorderLayout());
77 searchInConstantPoolsDialog.add(panel);
78
79 // Box for search criteria
80 Box vbox = Box.createVerticalBox();
81
82 Box hbox = Box.createHorizontalBox();
83 hbox.add(new JLabel("Search string (* = any string, ? = any character):"));
84 hbox.add(Box.createHorizontalGlue());
85 vbox.add(hbox);
86
87 vbox.add(Box.createVerticalStrut(10));
88
89 // Text field
90 vbox.add(searchInConstantPoolsEnterTextField = new JTextField(30));
91 searchInConstantPoolsEnterTextField.addKeyListener(new KeyAdapter() {
92 @Override public void keyTyped(KeyEvent e) {
93 switch (e.getKeyChar()) {
94 case '=': case '(': case ')': case '{': case '}': case '[': case ']':
95 e.consume();
96 break;
97 default:
98 if (Character.isDigit(e.getKeyChar()) && (searchInConstantPoolsEnterTextField.getText().length() == 0)) {
99 // First character can not be a digit
100 e.consume();
101 }
102 break;
103 }
104 }
105 @Override public void keyPressed(KeyEvent e) {
106 if (e.getKeyCode() == KeyEvent.VK_DOWN) {
107 DefaultMutableTreeNode root = (DefaultMutableTreeNode)searchInConstantPoolsTree.getModel().getRoot();
108 if (root.getChildCount() > 0) {
109 searchInConstantPoolsTree.requestFocus();
110 if (searchInConstantPoolsTree.getSelectionCount() == 0) {
111 searchInConstantPoolsTree.setSelectionPath(new TreePath(((DefaultMutableTreeNode)root.getChildAt(0)).getPath()));
112 }
113 e.consume();
114 }
115 }
116 }
117 });
118 searchInConstantPoolsEnterTextField.getDocument().addDocumentListener(new DocumentListener() {
119 @Override public void insertUpdate(DocumentEvent e) { call(); }
120 @Override public void removeUpdate(DocumentEvent e) { call(); }
121 @Override public void changedUpdate(DocumentEvent e) { call(); }
122 protected void call() { changedPatternCallback.accept(searchInConstantPoolsEnterTextField.getText(), getFlags()); }
123 });
124
125 vbox.add(Box.createVerticalStrut(10));
126
127 hbox = Box.createHorizontalBox();
128 vbox.add(hbox);
129
130 JPanel subpanel = new JPanel();
131 subpanel.setBorder(BorderFactory.createTitledBorder("Search For"));
132 subpanel.setLayout(new BorderLayout());
133 hbox.add(subpanel);
134
135 Box subhbox = Box.createHorizontalBox();
136 subpanel.add(subhbox, BorderLayout.WEST);
137
138 ItemListener checkBoxListener = (e) -> {
139 changedPatternCallback.accept(searchInConstantPoolsEnterTextField.getText(), getFlags());
140 searchInConstantPoolsEnterTextField.requestFocus();
141 };
142
143 JPanel subsubpanel = new JPanel();
144 subsubpanel.setLayout(new GridLayout(2, 1));
145 subsubpanel.add(searchInConstantPoolsCheckBoxType = new JCheckBox("Type", true));
146 searchInConstantPoolsCheckBoxType.addItemListener(checkBoxListener);
147 subsubpanel.add(searchInConstantPoolsCheckBoxField = new JCheckBox("Field"));
148 searchInConstantPoolsCheckBoxField.addItemListener(checkBoxListener);
149 subhbox.add(subsubpanel);
150
151 subsubpanel = new JPanel();
152 subsubpanel.setLayout(new GridLayout(2, 1));
153 subsubpanel.add(searchInConstantPoolsCheckBoxConstructor = new JCheckBox("Constructor"));
154 searchInConstantPoolsCheckBoxConstructor.addItemListener(checkBoxListener);
155 subsubpanel.add(searchInConstantPoolsCheckBoxMethod = new JCheckBox("Method"));
156 searchInConstantPoolsCheckBoxMethod.addItemListener(checkBoxListener);
157 subhbox.add(subsubpanel);
158
159 subsubpanel = new JPanel();
160 subsubpanel.setLayout(new GridLayout(2, 1));
161 subsubpanel.add(searchInConstantPoolsCheckBoxString = new JCheckBox("String Constant"));
162 searchInConstantPoolsCheckBoxString.addItemListener(checkBoxListener);
163 subsubpanel.add(searchInConstantPoolsCheckBoxModule = new JCheckBox("Java Module"));
164 searchInConstantPoolsCheckBoxModule.addItemListener(checkBoxListener);
165 subhbox.add(subsubpanel);
166
167 subpanel = new JPanel();
168 subpanel.setBorder(BorderFactory.createTitledBorder("Limit To"));
169 subpanel.setLayout(new BorderLayout());
170 hbox.add(subpanel);
171
172 subhbox = Box.createHorizontalBox();
173 subpanel.add(subhbox, BorderLayout.WEST);
174
175 subsubpanel = new JPanel();
176 subsubpanel.setLayout(new GridLayout(2, 1));
177 subsubpanel.add(searchInConstantPoolsCheckBoxDeclarations = new JCheckBox("Declarations", true));
178 searchInConstantPoolsCheckBoxDeclarations.addItemListener(checkBoxListener);
179 subsubpanel.add(searchInConstantPoolsCheckBoxReferences = new JCheckBox("References", true));
180 searchInConstantPoolsCheckBoxReferences.addItemListener(checkBoxListener);
181 subhbox.add(subsubpanel);
182
183 vbox.add(Box.createVerticalStrut(10));
184
185 hbox = Box.createHorizontalBox();
186 hbox.add(searchInConstantPoolsLabel = new JLabel("Matching types:"));
187 hbox.add(Box.createHorizontalGlue());
188 vbox.add(hbox);
189
190 vbox.add(Box.createVerticalStrut(10));
191 panel.add(vbox, BorderLayout.NORTH);
192
193 JScrollPane scrollPane = new JScrollPane(searchInConstantPoolsTree = new Tree());
194 searchInConstantPoolsTree.setShowsRootHandles(true);
195 searchInConstantPoolsTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
196 searchInConstantPoolsTree.setCellRenderer(new TreeNodeRenderer());
197 searchInConstantPoolsTree.addKeyListener(new KeyAdapter() {
198 @Override public void keyPressed(KeyEvent e) {
199 if (e.getKeyCode() == KeyEvent.VK_UP) {
200 if (searchInConstantPoolsTree.getLeadSelectionRow() == 0) {
201 searchInConstantPoolsEnterTextField.requestFocus();
202 e.consume();
203 }
204 }
205 }
206 });
207 searchInConstantPoolsTree.addMouseListener(new MouseAdapter() {
208 @Override public void mouseClicked(MouseEvent e) {
209 if (e.getClickCount() == 2) {
210 T node = (T)searchInConstantPoolsTree.getLastSelectedPathComponent();
211 if (node != null) {
212 selectedTypeCallback.accept(node.getUri(), searchInConstantPoolsEnterTextField.getText(), getFlags());
213 }
214 }
215 }
216 });
217 searchInConstantPoolsTree.addTreeExpansionListener(new TreeExpansionListener() {
218 @Override public void treeExpanded(TreeExpansionEvent e) {
219 DefaultTreeModel model = (DefaultTreeModel)searchInConstantPoolsTree.getModel();
220 T node = (T)e.getPath().getLastPathComponent();
221 // Expand node and find the first leaf
222 while (true) {
223 populate(model, node);
224 if (node.getChildCount() == 0) {
225 break;
226 }
227 node = (T)node.getChildAt(0);
228 }
229 searchInConstantPoolsTree.setSelectionPath(new TreePath(node.getPath()));
230 }
231 @Override public void treeCollapsed(TreeExpansionEvent e) {}
232 });
233 scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
234 scrollPane.setPreferredSize(new Dimension(400, 150));
235 panel.add(scrollPane, BorderLayout.CENTER);
236
237 vbox = Box.createVerticalBox();
238
239 vbox.add(Box.createVerticalStrut(25));
240
241 hbox = Box.createHorizontalBox();
242 hbox.add(Box.createHorizontalGlue());
243 JButton searchInConstantPoolsOpenButton = new JButton("Open");
244 hbox.add(searchInConstantPoolsOpenButton);
245 searchInConstantPoolsOpenButton.setEnabled(false);
246 Action searchInConstantPoolsOpenActionListener = new AbstractAction() {
247 @Override public void actionPerformed(ActionEvent actionEvent) {
248 T selectedTreeNode = (T)searchInConstantPoolsTree.getLastSelectedPathComponent();
249 if (selectedTreeNode != null) {
250 selectedTypeCallback.accept(selectedTreeNode.getUri(), searchInConstantPoolsEnterTextField.getText(), getFlags());
251 }
252 }
253 };
254 searchInConstantPoolsOpenButton.addActionListener(searchInConstantPoolsOpenActionListener);
255 hbox.add(Box.createHorizontalStrut(5));
256 JButton searchInConstantPoolsCancelButton = new JButton("Cancel");
257 hbox.add(searchInConstantPoolsCancelButton);
258 Action searchInConstantPoolsCancelActionListener = new AbstractAction() {
259 @Override public void actionPerformed(ActionEvent actionEvent) { searchInConstantPoolsDialog.setVisible(false); }
260 };
261 searchInConstantPoolsCancelButton.addActionListener(searchInConstantPoolsCancelActionListener);
262
263 vbox.add(hbox);
264
265 panel.add(vbox, BorderLayout.SOUTH);
266
267 // Last setup
268 JRootPane rootPane = searchInConstantPoolsDialog.getRootPane();
269 rootPane.setDefaultButton(searchInConstantPoolsOpenButton);
270 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "SearchInConstantPoolsView.cancel");
271 rootPane.getActionMap().put("SearchInConstantPoolsView.cancel", searchInConstantPoolsCancelActionListener);
272
273 searchInConstantPoolsDialog.setMinimumSize(searchInConstantPoolsDialog.getSize());
274
275 searchInConstantPoolsEnterTextField.addFocusListener(new FocusAdapter() {
276 @Override public void focusGained(FocusEvent e) {
277 searchInConstantPoolsTree.clearSelection();
278 searchInConstantPoolsOpenButton.setEnabled(false);
279 }
280 });
281
282 searchInConstantPoolsTree.addFocusListener(new FocusAdapter() {
283 @Override public void focusGained(FocusEvent e) {
284 searchInConstantPoolsOpenButton.setEnabled(searchInConstantPoolsTree.getSelectionCount() > 0);
285 }
286 });
287
288 // Prepare to display
289 searchInConstantPoolsDialog.pack();
290 searchInConstantPoolsDialog.setLocationRelativeTo(searchInConstantPoolsDialog.getParent());
291 });
292 }
293
294 @SuppressWarnings("unchecked")
295 protected void populate(DefaultTreeModel model, T node) {
296 // Populate node
297 populate(node);
298 // Populate children
299 int i = node.getChildCount();
300 while (i-- > 0) {
301 T child = (T)node.getChildAt(i);
302 if ((child instanceof TreeNodeExpandable) && !expanded.contains(child.getUri())) {
303 populate(child);
304 }
305 }
306 // Refresh
307 model.reload(node);
308 }
309
310 @SuppressWarnings("unchecked")
311 protected void populate(T node) {
312 if ((node instanceof TreeNodeExpandable) && !expanded.contains(node.getUri())) {
313 // Populate
314 ((TreeNodeExpandable)node).populateTreeNode(api);
315 expanded.add(node.getUri());
316 // Filter
317 int i = node.getChildCount();
318 while (i-- > 0) {
319 if (!accepted.contains(((T)node.getChildAt(i)).getUri())) {
320 node.remove(i);
321 }
322 }
323 }
324 }
325
326 public void show() {
327 SwingUtil.invokeLater(() -> {
328 searchInConstantPoolsEnterTextField.selectAll();
329 // Show
330 searchInConstantPoolsDialog.setVisible(true);
331 searchInConstantPoolsEnterTextField.requestFocus();
332 });
333 }
334
335 public boolean isVisible() { return searchInConstantPoolsDialog.isVisible(); }
336
337 public String getPattern() { return searchInConstantPoolsEnterTextField.getText(); }
338
339 public int getFlags() {
340 int flags = 0;
341
342 if (searchInConstantPoolsCheckBoxType.isSelected())
343 flags += SEARCH_TYPE;
344 if (searchInConstantPoolsCheckBoxConstructor.isSelected())
345 flags += SEARCH_CONSTRUCTOR;
346 if (searchInConstantPoolsCheckBoxMethod.isSelected())
347 flags += SEARCH_METHOD;
348 if (searchInConstantPoolsCheckBoxField.isSelected())
349 flags += SEARCH_FIELD;
350 if (searchInConstantPoolsCheckBoxString.isSelected())
351 flags += SEARCH_STRING;
352 if (searchInConstantPoolsCheckBoxModule.isSelected())
353 flags += SEARCH_MODULE;
354 if (searchInConstantPoolsCheckBoxDeclarations.isSelected())
355 flags += SEARCH_DECLARATION;
356 if (searchInConstantPoolsCheckBoxReferences.isSelected())
357 flags += SEARCH_REFERENCE;
358
359 return flags;
360 }
361
362 public void showWaitCursor() {
363 SwingUtil.invokeLater(() -> searchInConstantPoolsDialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)));
364 }
365
366 public void hideWaitCursor() {
367 SwingUtil.invokeLater(() -> searchInConstantPoolsDialog.setCursor(Cursor.getDefaultCursor()));
368 }
369
370 @SuppressWarnings("unchecked")
371 public void updateTree(Collection<DelegatingFilterContainer> containers, int matchingTypeCount) {
372 SwingUtil.invokeLater(() -> {
373 DefaultTreeModel model = (DefaultTreeModel)searchInConstantPoolsTree.getModel();
374 T root = (T)model.getRoot();
375
376 // Reset tree nodes
377 root.removeAllChildren();
378
379 accepted.clear();
380 expanded.clear();
381
382 if (containers != null) {
383 ArrayList<DelegatingFilterContainer> list = new ArrayList<>(containers);
384
385 list.sort(CONTAINER_COMPARATOR);
386
387 for (DelegatingFilterContainer container : list) {
388 // Init uri set
389 accepted.addAll(container.getUris());
390 // Populate tree
391 Container.Entry parentEntry = container.getRoot().getParent();
392 TreeNodeFactory treeNodeFactory = api.getTreeNodeFactory(parentEntry);
393
394 if (treeNodeFactory != null) {
395 root.add(treeNodeFactory.make(api, parentEntry));
396 }
397 }
398
399 // Expand node and find the first leaf
400 T node = root;
401 while (true) {
402 populate(model, node);
403 if (node.getChildCount() == 0) {
404 break;
405 }
406 node = (T)node.getChildAt(0);
407 }
408 searchInConstantPoolsTree.setSelectionPath(new TreePath(node.getPath()));
409 } else {
410 model.reload();
411 }
412
413 // Update matching item counter
414 switch (matchingTypeCount) {
415 case 0:
416 searchInConstantPoolsLabel.setText("Matching entries:");
417 break;
418 case 1:
419 searchInConstantPoolsLabel.setText("1 matching entry:");
420 break;
421 default:
422 searchInConstantPoolsLabel.setText(matchingTypeCount + " matching entries:");
423 }
424 });
425 }
426
427 protected static class ContainerComparator implements Comparator<Container> {
428 @Override
429 public int compare(Container c1, Container c2) {
430 return c1.getRoot().getUri().compareTo(c2.getRoot().getUri());
431 }
432 }
433 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.TreeNodeExpandable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.model.container.DelegatingFilterContainer;
15 import org.jd.gui.spi.TreeNodeFactory;
16 import org.jd.gui.util.swing.SwingUtil;
17 import org.jd.gui.view.component.Tree;
18 import org.jd.gui.view.renderer.TreeNodeRenderer;
19
20 import javax.swing.*;
21 import javax.swing.tree.DefaultMutableTreeNode;
22 import javax.swing.tree.DefaultTreeModel;
23 import javax.swing.tree.TreePath;
24 import java.awt.*;
25 import java.awt.event.*;
26 import java.net.URI;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Comparator;
30 import java.util.Set;
31 import java.util.function.Consumer;
32
33 public class SelectLocationView<T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> {
34 protected static final DelegatingFilterContainerComparator DELEGATING_FILTER_CONTAINER_COMPARATOR = new DelegatingFilterContainerComparator();
35
36 protected API api;
37
38 protected JDialog selectLocationDialog;
39 protected JLabel selectLocationLabel;
40 protected Tree selectLocationTree;
41
42 protected Consumer<URI> selectedEntryCallback;
43 protected Runnable closeCallback;
44
45 @SuppressWarnings("unchecked")
46 public SelectLocationView(API api, JFrame mainFrame) {
47 this.api = api;
48 // Build GUI
49 SwingUtil.invokeLater(() -> {
50 selectLocationDialog = new JDialog(mainFrame, "", false);
51 selectLocationDialog.setUndecorated(true);
52 selectLocationDialog.addWindowListener(new WindowAdapter() {
53 @Override public void windowDeactivated(WindowEvent e) { closeCallback.run(); }
54 });
55
56 Color bg = UIManager.getColor("ToolTip.background");
57
58 JPanel selectLocationPanel = new JPanel(new BorderLayout());
59 selectLocationPanel.setBorder(BorderFactory.createLineBorder(bg.darker()));
60 selectLocationPanel.setBackground(bg);
61 selectLocationDialog.add(selectLocationPanel);
62
63 selectLocationLabel = new JLabel();
64 selectLocationLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
65 selectLocationPanel.add(selectLocationLabel, BorderLayout.NORTH);
66
67 selectLocationTree = new Tree();
68 selectLocationTree.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
69 selectLocationTree.setOpaque(false);
70 selectLocationTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
71 selectLocationTree.setCellRenderer(new TreeNodeRenderer());
72 selectLocationTree.addKeyListener(new KeyAdapter() {
73 @Override public void keyPressed(KeyEvent e) {
74 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
75 onSelectedEntry();
76 }
77 }
78 });
79 selectLocationTree.addMouseListener(new MouseAdapter() {
80 @Override public void mouseClicked(MouseEvent e) {
81 if (e.getClickCount() > 0) {
82 onSelectedEntry();
83 }
84 }
85 });
86 selectLocationTree.addFocusListener(new FocusAdapter() {
87 @Override public void focusLost(FocusEvent e) { selectLocationDialog.setVisible(false); }
88 });
89 selectLocationPanel.add(selectLocationTree, BorderLayout.CENTER);
90
91 // Last setup
92 JRootPane rootPane = selectLocationDialog.getRootPane();
93 rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "SelectLocationView.cancel");
94 rootPane.getActionMap().put("SelectLocationView.cancel", new AbstractAction() {
95 @Override public void actionPerformed(ActionEvent e) { selectLocationDialog.setVisible(false); }
96 });
97 });
98 }
99
100 @SuppressWarnings("unchecked")
101 public void show(Point location, Collection<DelegatingFilterContainer> containers, int locationCount, Consumer<URI> selectedEntryCallback, Runnable closeCallback) {
102 this.selectedEntryCallback = selectedEntryCallback;
103 this.closeCallback = closeCallback;
104
105 SwingUtil.invokeLater(() -> {
106 // Init
107 T root = (T)selectLocationTree.getModel().getRoot();
108
109 // Reset tree nodes
110 root.removeAllChildren();
111
112 ArrayList<DelegatingFilterContainer> sortedContainers = new ArrayList<>(containers);
113 sortedContainers.sort(DELEGATING_FILTER_CONTAINER_COMPARATOR);
114
115 for (DelegatingFilterContainer container : sortedContainers) {
116 Container.Entry parentEntry = container.getRoot().getParent();
117 TreeNodeFactory factory = api.getTreeNodeFactory(parentEntry);
118
119 if (factory != null) {
120 T node = factory.make(api, parentEntry);
121
122 if (node != null) {
123 root.add(node);
124 populate(container.getUris(), node);
125 }
126 }
127 }
128
129 ((DefaultTreeModel)selectLocationTree.getModel()).reload();
130
131 // Expand all nodes
132 for (int row = 0; row < selectLocationTree.getRowCount(); row++) {
133 selectLocationTree.expandRow(row);
134 }
135
136 // Select first leaf
137 T node = root;
138 while (true) {
139 if (node.getChildCount() == 0) {
140 break;
141 }
142 node = (T)node.getChildAt(0);
143 }
144 selectLocationTree.setSelectionPath(new TreePath(node.getPath()));
145
146 // Reset preferred size
147 selectLocationTree.setPreferredSize(null);
148
149 // Resize
150 Dimension ps = selectLocationTree.getPreferredSize();
151 if (ps.width < 200)
152 ps.width = 200;
153 if (ps.height < 50)
154 ps.height = 50;
155 selectLocationTree.setPreferredSize(ps);
156
157 selectLocationLabel.setText("" + locationCount + " locations:");
158
159 selectLocationDialog.pack();
160 selectLocationDialog.setLocation(location);
161 // Show
162 selectLocationDialog.setVisible(true);
163 selectLocationTree.requestFocus();
164 });
165 }
166
167 @SuppressWarnings("unchecked")
168 protected void populate(Set<URI> uris, DefaultMutableTreeNode node) {
169 if (node instanceof TreeNodeExpandable) {
170 ((TreeNodeExpandable)node).populateTreeNode(api);
171
172 int i = node.getChildCount();
173
174 while (i-- > 0) {
175 T child = (T)node.getChildAt(i);
176
177 if (uris.contains(child.getUri())) {
178 populate(uris, child);
179 } else {
180 node.remove(i);
181 }
182 }
183 }
184 }
185
186 @SuppressWarnings("unchecked")
187 protected void onSelectedEntry() {
188 T node = (T)selectLocationTree.getLastSelectedPathComponent();
189
190 if (node != null) {
191 selectLocationDialog.setVisible(false);
192 selectedEntryCallback.accept(node.getUri());
193 }
194 }
195
196 protected static class DelegatingFilterContainerComparator implements Comparator<DelegatingFilterContainer> {
197 @Override
198 public int compare(DelegatingFilterContainer fcw1, DelegatingFilterContainer fcw2) {
199 return fcw1.getRoot().getUri().compareTo(fcw2.getRoot().getUri());
200 }
201 }
202 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.bean;
8
9 import org.jd.gui.api.model.Container;
10
11 import javax.swing.*;
12 import java.util.Collection;
13
14 public class OpenTypeListCellBean {
15 public String label;
16 public String packag;
17 public Icon icon;
18 public Collection<Container.Entry> entries;
19 public String typeName;
20
21 public OpenTypeListCellBean(String label, Collection<Container.Entry> entries, String typeName) {
22 this.label = label;
23 this.entries = entries;
24 this.typeName = typeName;
25 }
26
27 public OpenTypeListCellBean(String label, String packag, Icon icon, Collection<Container.Entry> entries, String typeName) {
28 this.label = label;
29 this.packag = packag;
30 this.icon = icon;
31 this.entries = entries;
32 this.typeName = typeName;
33 }
34 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import javax.swing.*;
10 import java.awt.*;
11
12 public class IconButton extends JButton {
13 protected static final Insets INSETS0 = new Insets(0, 0, 0, 0);
14
15 public IconButton(String text, Action action) {
16 setFocusPainted(false);
17 setBorderPainted(false);
18 setMargin(INSETS0);
19 setAction(action);
20 setText(text);
21 }
22
23 public IconButton(Action action) {
24 this(null, action);
25 }
26 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.jd.gui.api.model.TreeNodeData;
10
11 import javax.swing.*;
12 import javax.swing.tree.DefaultMutableTreeNode;
13 import java.awt.*;
14 import java.awt.event.KeyEvent;
15
16 public class List extends JList {
17
18 @SuppressWarnings("unchecked")
19 public List() {
20 super();
21
22 Toolkit toolkit = Toolkit.getDefaultToolkit();
23 KeyStroke ctrlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, toolkit.getMenuShortcutKeyMask());
24 KeyStroke ctrlC = KeyStroke.getKeyStroke(KeyEvent.VK_C, toolkit.getMenuShortcutKeyMask());
25 KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, toolkit.getMenuShortcutKeyMask());
26
27 InputMap inputMap = getInputMap();
28 inputMap.put(ctrlA, "none");
29 inputMap.put(ctrlC, "none");
30 inputMap.put(ctrlV, "none");
31
32 setCellRenderer(new Renderer());
33 }
34
35 protected class Renderer implements ListCellRenderer {
36 protected Color textSelectionColor;
37 protected Color backgroundSelectionColor;
38 protected Color textNonSelectionColor;
39 protected Color backgroundNonSelectionColor;
40
41 protected JLabel label;
42
43 public Renderer() {
44 label = new JLabel();
45 label.setOpaque(true);
46
47 textSelectionColor = UIManager.getColor("List.dropCellForeground");
48 backgroundSelectionColor = UIManager.getColor("List.dropCellBackground");
49 textNonSelectionColor = UIManager.getColor("List.foreground");
50 backgroundNonSelectionColor = UIManager.getColor("List.background");
51 Insets margins = UIManager.getInsets("List.contentMargins");
52
53 if (textSelectionColor == null)
54 textSelectionColor = List.this.getSelectionForeground();
55 if (backgroundSelectionColor == null)
56 backgroundSelectionColor = List.this.getSelectionBackground();
57
58 if (margins != null) {
59 label.setBorder(BorderFactory.createEmptyBorder(margins.top, margins.left, margins.bottom, margins.right));
60 } else {
61 label.setBorder(BorderFactory.createEmptyBorder(0, 2, 1, 2));
62 }
63 }
64
65 @Override
66 public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected, boolean hasFocus) {
67 Object data = ((DefaultMutableTreeNode)value).getUserObject();
68
69 if (data instanceof TreeNodeData) {
70 TreeNodeData tnd = (TreeNodeData)data;
71 label.setIcon(tnd.getIcon());
72 label.setText(tnd.getLabel());
73 } else {
74 label.setIcon(null);
75 label.setText("" + data);
76 }
77
78 if (selected) {
79 label.setForeground(textSelectionColor);
80 label.setBackground(backgroundSelectionColor);
81 } else {
82 label.setForeground(textNonSelectionColor);
83 label.setBackground(backgroundNonSelectionColor);
84 }
85
86 return label;
87 }
88 }
89 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import javax.swing.*;
10 import java.awt.*;
11 import java.awt.event.KeyEvent;
12
13 public class Tree extends JTree {
14 public Tree() {
15 Toolkit toolkit = Toolkit.getDefaultToolkit();
16 KeyStroke ctrlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, toolkit.getMenuShortcutKeyMask());
17 KeyStroke ctrlC = KeyStroke.getKeyStroke(KeyEvent.VK_C, toolkit.getMenuShortcutKeyMask());
18 KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, toolkit.getMenuShortcutKeyMask());
19
20 InputMap inputMap = getInputMap();
21 inputMap.put(ctrlA, "none");
22 inputMap.put(ctrlC, "none");
23 inputMap.put(ctrlV, "none");
24
25 setRootVisible(false);
26 }
27
28 public void fireVisibleDataPropertyChange() {
29 if (getAccessibleContext() != null) {
30 getAccessibleContext().firePropertyChange("AccessibleVisibleData", false, true);
31 }
32 }
33 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component.panel;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.*;
11 import org.jd.gui.service.platform.PlatformService;
12
13 import javax.swing.*;
14 import java.awt.*;
15 import java.net.URI;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.Map;
19
20 @SuppressWarnings("unchecked")
21 public class MainTabbedPanel<T extends JComponent & UriGettable> extends TabbedPanel<T> implements UriOpenable, PreferencesChangeListener, PageChangeListener {
22 protected ArrayList<PageChangeListener> pageChangedListeners = new ArrayList<>();
23 // Flag to prevent the event cascades
24 protected boolean pageChangedListenersEnabled = true;
25
26 public MainTabbedPanel(API api) {
27 super(api);
28 }
29
30 @Override
31 public void create() {
32 setLayout(cardLayout = new CardLayout());
33
34 Color bg = darker(getBackground());
35
36 if (PlatformService.getInstance().isWindows()) {
37 setBackground(bg);
38 }
39
40 // panel //
41 JPanel panel = new JPanel();
42 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
43 panel.setBackground(bg);
44
45 Color fontColor = panel.getBackground().darker();
46
47 panel.add(Box.createHorizontalGlue());
48
49 JPanel box = new JPanel();
50 box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
51 box.setBackground(panel.getBackground());
52 box.add(Box.createVerticalGlue());
53
54 JLabel title = newLabel("No files are open", fontColor);
55 title.setFont(title.getFont().deriveFont(Font.BOLD, title.getFont().getSize()+8));
56
57 box.add(title);
58 box.add(newLabel("Open a file with menu \"File > Open File...\"", fontColor));
59 box.add(newLabel("Open recent files with menu \"File > Recent Files\"", fontColor));
60 box.add(newLabel("Drag and drop files from " + getFileManagerLabel(), fontColor));
61 box.add(Box.createVerticalGlue());
62
63 panel.add(box);
64 panel.add(Box.createHorizontalGlue());
65 add("panel", panel);
66
67 // tabs //
68 tabbedPane = createTabPanel();
69 tabbedPane.addChangeListener(e -> {
70 if (pageChangedListenersEnabled) {
71 JComponent subPage = (JComponent)tabbedPane.getSelectedComponent();
72
73 if (subPage == null) {
74 // Fire page changed event
75 for (PageChangeListener listener : pageChangedListeners) {
76 listener.pageChanged(null);
77 }
78 } else {
79 T page = (T)subPage.getClientProperty("currentPage");
80
81 if (page == null) {
82 page = (T)tabbedPane.getSelectedComponent();
83 }
84 // Fire page changed event
85 for (PageChangeListener listener : pageChangedListeners) {
86 listener.pageChanged(page);
87 }
88 // Update current sub-page preferences
89 if (subPage instanceof PreferencesChangeListener) {
90 ((PreferencesChangeListener)subPage).preferencesChanged(preferences);
91 }
92 }
93 }
94 });
95 add("tabs", tabbedPane);
96
97 setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, darker(darker(bg))));
98 }
99
100 protected String getFileManagerLabel() {
101 switch (PlatformService.getInstance().getOs()) {
102 case Linux:
103 return "your file manager";
104 case MacOSX:
105 return "the Finder";
106 default:
107 return "Explorer";
108 }
109 }
110
111 protected JLabel newLabel(String text, Color fontColor) {
112 JLabel label = new JLabel(text);
113 label.setForeground(fontColor);
114 return label;
115 }
116
117 @Override
118 public void addPage(String title, Icon icon, String tip, T page) {
119 super.addPage(title, icon, tip, page);
120 if (page instanceof PageChangeable) {
121 ((PageChangeable)page).addPageChangeListener(this);
122 }
123 }
124
125 public List<T> getPages() {
126 int i = tabbedPane.getTabCount();
127 ArrayList<T> pages = new ArrayList<>(i);
128 while (i-- > 0) {
129 pages.add((T)tabbedPane.getComponentAt(i));
130 }
131 return pages;
132 }
133
134 public ArrayList<PageChangeListener> getPageChangedListeners() {
135 return pageChangedListeners;
136 }
137
138 // --- URIOpener --- //
139 @Override
140 public boolean openUri(URI uri) {
141 try {
142 // Disable page changed event
143 pageChangedListenersEnabled = false;
144 // Search & display main tab
145 T page = showPage(uri);
146
147 if (page != null) {
148 if (page instanceof UriOpenable) {
149 // Enable page changed event
150 pageChangedListenersEnabled = true;
151 // Search & display sub tab
152 return ((UriOpenable)page).openUri(uri);
153 }
154 return true;
155 }
156 } finally {
157 // Enable page changed event
158 pageChangedListenersEnabled = true;
159 }
160
161 return false;
162 }
163
164 // --- PageChangedListener --- //
165 @Override
166 public <T extends JComponent & UriGettable> void pageChanged(T page) {
167 // Store active page for current sub tabbed pane
168 Component subPage = tabbedPane.getSelectedComponent();
169
170 if (subPage != null) {
171 ((JComponent)subPage).putClientProperty("currentPage", page);
172 }
173
174 if (page == null) {
175 page = (T)subPage;
176 }
177
178 // Forward event
179 for (PageChangeListener listener : pageChangedListeners) {
180 listener.pageChanged(page);
181 }
182 }
183
184 // --- PreferencesChangeListener --- //
185 @Override
186 public void preferencesChanged(Map<String, String> preferences) {
187 super.preferencesChanged(preferences);
188
189 // Update current sub-page preferences
190 Component subPage = tabbedPane.getSelectedComponent();
191 if (subPage instanceof PreferencesChangeListener) {
192 ((PreferencesChangeListener)subPage).preferencesChanged(preferences);
193 }
194 }
195 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component.panel;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.PreferencesChangeListener;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.service.platform.PlatformService;
14
15 import javax.swing.*;
16 import javax.swing.event.ChangeEvent;
17 import javax.swing.event.ChangeListener;
18 import java.awt.*;
19 import java.awt.event.*;
20 import java.net.URI;
21 import java.util.Collection;
22 import java.util.Map;
23
24 public class TabbedPanel<T extends JComponent & UriGettable> extends JPanel implements PreferencesChangeListener {
25 protected static final ImageIcon CLOSE_ICON = new ImageIcon(TabbedPanel.class.getClassLoader().getResource("org/jd/gui/images/close.gif"));
26 protected static final ImageIcon CLOSE_ACTIVE_ICON = new ImageIcon(TabbedPanel.class.getClassLoader().getResource("org/jd/gui/images/close_active.gif"));
27
28 protected static final String TAB_LAYOUT = "UITabsPreferencesProvider.singleLineTabs";
29
30 protected API api;
31 protected CardLayout cardLayout;
32 protected JTabbedPane tabbedPane;
33 protected Map<String, String> preferences;
34
35 public TabbedPanel(API api) {
36 this.api = api;
37 create();
38 }
39
40 protected void create() {
41 setLayout(cardLayout = new CardLayout());
42 add("panel", new JPanel());
43 add("tabs", tabbedPane = createTabPanel());
44 }
45
46 protected JTabbedPane createTabPanel() {
47 JTabbedPane tabPanel = new JTabbedPane() {
48 @Override
49 public String getToolTipText(MouseEvent e) {
50 int index = indexAtLocation(e.getX(), e.getY());
51 if (index != -1) {
52 return ((JComponent)getTabComponentAt(index)).getToolTipText();
53 }
54 return super.getToolTipText(e);
55 }
56 };
57 ToolTipManager.sharedInstance().registerComponent(tabPanel);
58 tabPanel.addMouseListener(new MouseAdapter() {
59 @Override public void mousePressed(MouseEvent e) { showPopupTabMenu(e); }
60 @Override public void mouseReleased(MouseEvent e) { showPopupTabMenu(e); }
61 protected void showPopupTabMenu(MouseEvent e) {
62 if (e.isPopupTrigger()) {
63 int index = tabPanel.indexAtLocation(e.getX(), e.getY());
64 if (index != -1) {
65 new PopupTabMenu(tabPanel.getComponentAt(index)).show(e.getComponent(), e.getX(), e.getY());
66 }
67 }
68 }
69 });
70 return tabPanel;
71 }
72
73 protected static Color darker(Color c) {
74 return new Color(
75 Math.max((int)(c.getRed() *0.85), 0),
76 Math.max((int)(c.getGreen()*0.85), 0),
77 Math.max((int)(c.getBlue() *0.85), 0),
78 c.getAlpha());
79 }
80
81 public void addPage(String title, Icon icon, String tip, T page) {
82 // Add a new tab
83 JLabel tabCloseButton = new JLabel(CLOSE_ICON);
84 tabCloseButton.setToolTipText("Close this panel");
85 tabCloseButton.addMouseListener(new MouseListener() {
86 @Override public void mousePressed(MouseEvent e) {}
87 @Override public void mouseReleased(MouseEvent e) {}
88 @Override public void mouseEntered(MouseEvent e) { ((JLabel)e.getSource()).setIcon(CLOSE_ACTIVE_ICON); }
89 @Override public void mouseExited(MouseEvent e) { ((JLabel)e.getSource()).setIcon(CLOSE_ICON); }
90 @Override public void mouseClicked(MouseEvent e) { removeComponent(page); }
91 });
92
93 JPanel tab = new JPanel(new BorderLayout());
94 tab.setBorder(BorderFactory.createEmptyBorder(2, 0, 3, 0));
95 tab.setOpaque(false);
96 tab.setToolTipText(tip);
97 tab.add(new JLabel(title, icon, JLabel.LEADING), BorderLayout.CENTER);
98 tab.add(tabCloseButton, BorderLayout.EAST);
99 ToolTipManager.sharedInstance().unregisterComponent(tab);
100
101 int index = tabbedPane.getTabCount();
102 tabbedPane.addTab(title, page);
103 tabbedPane.setTabComponentAt(index, tab);
104 setSelectedIndex(index);
105
106 cardLayout.show(this, "tabs");
107 }
108
109 protected void setSelectedIndex(int index) {
110 if (index != -1) {
111 if (tabbedPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
112 // Ensure that the new page is visible (bug with SCROLL_TAB_LAYOUT)
113 ChangeEvent event = new ChangeEvent(tabbedPane);
114 for (ChangeListener listener : tabbedPane.getChangeListeners()) {
115 if (listener.getClass().getPackage().getName().startsWith("javax.")) {
116 listener.stateChanged(event);
117 }
118 }
119 }
120
121 tabbedPane.setSelectedIndex(index);
122 }
123 }
124
125 @SuppressWarnings("unchecked")
126 protected T showPage(URI uri) {
127 String u1 = uri.getPath();
128 int i = tabbedPane.getTabCount();
129
130 while (i-- > 0) {
131 T page = (T)tabbedPane.getComponentAt(i);
132 String u2 = page.getUri().getPath();
133 if (u1.startsWith(u2)) {
134 tabbedPane.setSelectedIndex(i);
135 return page;
136 }
137 }
138
139 return null;
140 }
141
142 protected class PopupTabMenu extends JPopupMenu {
143 public PopupTabMenu(Component component) {
144 // Add default popup menu entries
145 JMenuItem menuItem = new JMenuItem("Close", null);
146 menuItem.addActionListener(e -> removeComponent(component));
147 add(menuItem);
148
149 menuItem = new JMenuItem("Close Others", null);
150 menuItem.addActionListener(e -> removeOtherComponents(component));
151 add(menuItem);
152
153 menuItem = new JMenuItem("Close All", null);
154 menuItem.addActionListener(e -> removeAllComponents());
155 add(menuItem);
156
157 // Add "Select Tab" popup menu entry
158 if ((tabbedPane.getTabCount() > 1) && (PlatformService.getInstance().isMac() || "true".equals(preferences.get(TAB_LAYOUT)))) {
159 addSeparator();
160 JMenu menu = new JMenu("Select Tab");
161 int count = tabbedPane.getTabCount();
162
163 for (int i = 0; i < count; i++) {
164 JPanel tab = (JPanel) tabbedPane.getTabComponentAt(i);
165 JLabel label = (JLabel) tab.getComponent(0);
166 JMenuItem subMenuItem = new JMenuItem(label.getText(), label.getIcon());
167 subMenuItem.addActionListener(new SubMenuItemActionListener(i));
168 if (component == tabbedPane.getComponentAt(i)) {
169 subMenuItem.setFont(subMenuItem.getFont().deriveFont(Font.BOLD));
170 }
171 menu.add(subMenuItem);
172 }
173
174 add(menu);
175 }
176
177 // Add SPI popup menu entries
178 if (component instanceof ContainerEntryGettable) {
179 Collection<Action> actions = api.getContextualActions(((ContainerEntryGettable)component).getEntry(), null);
180
181 if (actions != null) {
182 addSeparator();
183
184 for (Action action : actions) {
185 if (action != null) {
186 add(action);
187 } else {
188 addSeparator();
189 }
190 }
191 }
192 }
193 }
194 }
195
196 public JTabbedPane getTabbedPane() {
197 return tabbedPane;
198 }
199
200 protected class SubMenuItemActionListener implements ActionListener {
201 protected int index;
202
203 public SubMenuItemActionListener(int index) {
204 this.index = index;
205 }
206
207 @Override
208 public void actionPerformed(ActionEvent e) {
209 tabbedPane.setSelectedIndex(index);
210 }
211 }
212
213
214 // --- Popup menu actions --- //
215 public void removeComponent(Component component) {
216 tabbedPane.remove(component);
217 if (tabbedPane.getTabCount() == 0) {
218 cardLayout.show(this, "panel");
219 }
220 }
221
222 protected void removeOtherComponents(Component component) {
223 int i = tabbedPane.getTabCount();
224 while (i-- > 0) {
225 Component c = tabbedPane.getComponentAt(i);
226 if (c != component) {
227 tabbedPane.remove(i);
228 }
229 }
230 if (tabbedPane.getTabCount() == 0) {
231 cardLayout.show(this, "panel");
232 }
233 }
234
235 protected void removeAllComponents() {
236 tabbedPane.removeAll();
237 if (tabbedPane.getTabCount() == 0) {
238 cardLayout.show(this, "panel");
239 }
240 }
241
242 // --- PreferencesChangeListener --- //
243 @Override
244 public void preferencesChanged(Map<String, String> preferences) {
245 // Store preferences
246 this.preferences = preferences;
247 // Update layout
248 if ("true".equals(preferences.get(TAB_LAYOUT))) {
249 tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
250 } else {
251 tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
252 }
253 setSelectedIndex(tabbedPane.getSelectedIndex());
254 }
255 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component.panel;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.*;
11 import org.jd.gui.api.model.TreeNodeData;
12 import org.jd.gui.util.exception.ExceptionUtil;
13 import org.jd.gui.view.component.Tree;
14 import org.jd.gui.view.renderer.TreeNodeRenderer;
15
16 import javax.swing.*;
17 import javax.swing.event.TreeExpansionEvent;
18 import javax.swing.event.TreeExpansionListener;
19 import javax.swing.tree.DefaultMutableTreeNode;
20 import javax.swing.tree.DefaultTreeModel;
21 import javax.swing.tree.TreeNode;
22 import javax.swing.tree.TreePath;
23 import java.awt.*;
24 import java.awt.event.MouseAdapter;
25 import java.awt.event.MouseEvent;
26 import java.net.URI;
27 import java.net.URISyntaxException;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Enumeration;
31 import java.util.Map;
32
33 public class TreeTabbedPanel<T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> extends JPanel implements UriGettable, UriOpenable, PageChangeable, PageClosable, PreferencesChangeListener {
34 protected API api;
35 protected URI uri;
36 protected Tree tree;
37 protected TabbedPanel tabbedPanel;
38 protected ArrayList<PageChangeListener> pageChangedListeners = new ArrayList<>();
39 // Flags to prevent the event cascades
40 protected boolean updateTreeMenuEnabled = true;
41 protected boolean openUriEnabled = true;
42 protected boolean treeNodeChangedEnabled = true;
43
44 @SuppressWarnings("unchecked")
45 public TreeTabbedPanel(API api, URI uri) {
46 this.api = api;
47 this.uri = uri;
48
49 tree = new Tree();
50 tree.setShowsRootHandles(true);
51 tree.setMinimumSize(new Dimension(150, 10));
52 tree.setExpandsSelectedPaths(true);
53 tree.setCellRenderer(new TreeNodeRenderer() {
54 @Override
55 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
56 // Always render the left tree with focus
57 return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, true);
58 }
59 });
60 tree.addTreeSelectionListener(e -> treeNodeChanged((T)tree.getLastSelectedPathComponent()));
61 tree.addTreeExpansionListener(new TreeExpansionListener() {
62 @Override
63 public void treeExpanded(TreeExpansionEvent e) {
64 TreeNode node = (TreeNode)e.getPath().getLastPathComponent();
65 if (node instanceof TreeNodeExpandable) {
66 TreeNodeExpandable tne = (TreeNodeExpandable)node;
67 int oldHashCode = createHashCode(node.children());
68 tne.populateTreeNode(api);
69 int newHashCode = createHashCode(node.children());
70 if (oldHashCode != newHashCode) {
71 ((DefaultTreeModel)tree.getModel()).reload(node);
72 }
73 }
74 }
75 @Override
76 public void treeCollapsed(TreeExpansionEvent e) {}
77 });
78 tree.addMouseListener(new MouseAdapter() {
79 @Override
80 public void mouseClicked(MouseEvent e) {
81 if (SwingUtilities.isRightMouseButton(e)) {
82 TreePath path = tree.getPathForLocation(e.getX(), e.getY());
83
84 if (path != null) {
85 tree.setSelectionPath(path);
86
87 T node = (T)path.getLastPathComponent();
88 Collection<Action> actions = api.getContextualActions(node.getEntry(), node.getUri().getFragment());
89
90 if (actions != null) {
91 JPopupMenu popup = new JPopupMenu();
92 for (Action action : actions) {
93 if (action != null) {
94 popup.add(action);
95 } else {
96 popup.addSeparator();
97 }
98 }
99 popup.show(e.getComponent(), e.getX(), e.getY());
100 }
101 }
102 }
103 }
104 });
105
106 tabbedPanel = new TabbedPanel(api);
107 tabbedPanel.setMinimumSize(new Dimension(150, 10));
108 tabbedPanel.tabbedPane.addChangeListener(e -> pageChanged());
109
110 setLayout(new BorderLayout());
111
112 JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(tree), tabbedPanel);
113 splitter.setResizeWeight(0.2);
114
115 add(splitter, BorderLayout.CENTER);
116 }
117
118 protected static int createHashCode(Enumeration enumeration) {
119 int hashCode = 1;
120
121 while (enumeration.hasMoreElements()) {
122 hashCode *= 31;
123
124 Object element = enumeration.nextElement();
125
126 if (element != null) {
127 hashCode += element.hashCode();
128 }
129 }
130
131 return hashCode;
132 }
133
134 @SuppressWarnings("unchecked")
135 protected void treeNodeChanged(T node) {
136 if (treeNodeChangedEnabled && (node != null)) {
137 try {
138 // Disable tabbedPane.changeListener
139 updateTreeMenuEnabled = false;
140
141 // Search base tree node
142 URI uri = node.getUri();
143
144 if ((uri.getFragment() == null) && (uri.getQuery() == null)) {
145 showPage(uri, uri, node);
146 } else {
147 URI baseUri = new URI(uri.getScheme(), uri.getHost(), uri.getPath(), null);
148 T baseNode = node;
149
150 while ((baseNode != null) && !baseNode.getUri().equals(baseUri)) {
151 baseNode = (T)baseNode.getParent();
152 }
153
154 if ((baseNode != null) && baseNode.getUri().equals(baseUri)) {
155 showPage(uri, baseUri, baseNode);
156 }
157 }
158 } catch (URISyntaxException e) {
159 assert ExceptionUtil.printStackTrace(e);
160 } finally {
161 // Enable tabbedPane.changeListener
162 updateTreeMenuEnabled = true;
163 }
164 }
165 }
166
167 @SuppressWarnings("unchecked")
168 protected <P extends JComponent & UriGettable> boolean showPage(URI uri, URI baseUri, DefaultMutableTreeNode baseNode) {
169 P page = (P)tabbedPanel.showPage(baseUri);
170
171 if ((page == null) && (baseNode instanceof PageCreator)) {
172 page = ((PageCreator)baseNode).createPage(api);
173 page.putClientProperty("node", baseNode);
174
175 String path = baseUri.getPath();
176 String label = path.substring(path.lastIndexOf('/')+1);
177 Object data = baseNode.getUserObject();
178
179 if (data instanceof TreeNodeData) {
180 TreeNodeData tnd = (TreeNodeData)data;
181 tabbedPanel.addPage(label, tnd.getIcon(), tnd.getTip(), page);
182 } else {
183 tabbedPanel.addPage(label, null, null, page);
184 }
185 }
186
187 if (openUriEnabled && page instanceof UriOpenable) {
188 ((UriOpenable)page).openUri(uri);
189 }
190
191 return (page != null);
192 }
193
194 @SuppressWarnings("unchecked")
195 protected <P extends JComponent & UriGettable> void pageChanged() {
196 try {
197 // Disable highlight
198 openUriEnabled = false;
199
200 P page = (P)tabbedPanel.tabbedPane.getSelectedComponent();
201
202 if (updateTreeMenuEnabled) {
203 // Synchronize tree
204 if (page != null) {
205 T node = (T)page.getClientProperty("node");
206 // Select tree node
207 TreePath treePath = new TreePath(node.getPath());
208 tree.setSelectionPath(treePath);
209 tree.scrollPathToVisible(treePath);
210 } else {
211 tree.clearSelection();
212 }
213 }
214 // Fire page changed event
215 for (PageChangeListener listener : pageChangedListeners) {
216 listener.pageChanged(page);
217 }
218 } finally {
219 // Enable highlight
220 openUriEnabled = true;
221 }
222 }
223
224 // --- URIGetter --- //
225 @Override public URI getUri() { return uri; }
226
227 // --- URIOpener --- //
228 @Override
229 public boolean openUri(URI uri) {
230 try {
231 URI baseUri = new URI(uri.getScheme(), uri.getHost(), uri.getPath(), null);
232
233 if (this.uri.equals(baseUri)) {
234 return true;
235 } else {
236 DefaultMutableTreeNode node = searchTreeNode(baseUri, (DefaultMutableTreeNode) tree.getModel().getRoot());
237
238 if (showPage(uri, baseUri, node)) {
239 DefaultMutableTreeNode childNode = searchTreeNode(uri, node);
240 if (childNode != null) {
241 node = childNode;
242 }
243 }
244
245 if (node != null) {
246 try {
247 // Disable tree node changed listener
248 treeNodeChangedEnabled = false;
249 // Populate and expand node
250 if (!(node instanceof PageCreator) && (node instanceof TreeNodeExpandable)) {
251 ((TreeNodeExpandable) node).populateTreeNode(api);
252 tree.expandPath(new TreePath(node.getPath()));
253 }
254 // Select tree node
255 TreePath treePath = new TreePath(node.getPath());
256 tree.setSelectionPath(treePath);
257 tree.scrollPathToVisible(treePath);
258 } finally {
259 // Enable tree node changed listener
260 treeNodeChangedEnabled = true;
261 }
262 return true;
263 }
264 }
265 } catch (URISyntaxException e) {
266 assert ExceptionUtil.printStackTrace(e);
267 }
268
269 return false;
270 }
271
272 @SuppressWarnings("unchecked")
273 protected DefaultMutableTreeNode searchTreeNode(URI uri, DefaultMutableTreeNode node) {
274 if (node instanceof TreeNodeExpandable) {
275 ((TreeNodeExpandable)node).populateTreeNode(api);
276 }
277
278 String u = uri.toString();
279 T child = null;
280 Enumeration enumeration = node.children();
281
282 while (enumeration.hasMoreElements()) {
283 T element = (T)enumeration.nextElement();
284 String childU = element.getUri().toString();
285
286 if (u.length() > childU.length()) {
287 if (u.startsWith(childU)) {
288 char c = u.charAt(childU.length());
289 if ((c == '/') || (c == '!')) {
290 child = element;
291 break;
292 }
293 }
294 } else if (u.equals(childU)) {
295 child = element;
296 break;
297 }
298 }
299
300 if (child != null) {
301 if (u.equals(child.getUri().toString())) {
302 return child;
303 } else {
304 // Parent tree node found -> Recursive call
305 return searchTreeNode(uri, child);
306 }
307 } else {
308 // Not found
309 return null;
310 }
311 }
312
313 // --- PageChanger --- //
314 @Override
315 public void addPageChangeListener(PageChangeListener listener) {
316 pageChangedListeners.add(listener);
317 }
318
319 // --- PageCloser --- //
320 @Override
321 public boolean closePage() {
322 Component component = tabbedPanel.tabbedPane.getSelectedComponent();
323
324 if (component != null) {
325 tabbedPanel.removeComponent(component);
326 return true;
327 } else {
328 return false;
329 }
330 }
331
332 // --- PreferencesChangeListener --- //
333 @Override
334 @SuppressWarnings("unchecked")
335 public void preferencesChanged(Map<String, String> preferences) {
336 tabbedPanel.preferencesChanged(preferences);
337 }
338 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.renderer;
8
9 import org.jd.gui.view.bean.OpenTypeListCellBean;
10
11 import javax.swing.*;
12 import java.awt.*;
13
14 public class OpenTypeListCellRenderer implements ListCellRenderer<OpenTypeListCellBean> {
15 protected Color textSelectionColor;
16 protected Color textNonSelectionColor;
17 protected Color infoSelectionColor;
18 protected Color infoNonSelectionColor;
19 protected Color backgroundSelectionColor;
20 protected Color backgroundNonSelectionColor;
21
22 protected JPanel panel;
23 protected JLabel label, info;
24
25 public OpenTypeListCellRenderer() {
26 textSelectionColor = UIManager.getColor("List.selectionForeground");
27 textNonSelectionColor = UIManager.getColor("List.foreground");
28 backgroundSelectionColor = UIManager.getColor("List.selectionBackground");
29 backgroundNonSelectionColor = UIManager.getColor("List.background");
30
31 infoSelectionColor = infoColor(textSelectionColor);
32 infoNonSelectionColor = infoColor(textNonSelectionColor);
33
34 panel = new JPanel(new BorderLayout());
35 panel.add(label = new JLabel(), BorderLayout.WEST);
36 panel.add(info = new JLabel(), BorderLayout.CENTER);
37 }
38
39 static protected Color infoColor(Color c) {
40 if (c.getRed() + c.getGreen() + c.getBlue() > (3*127)) {
41 return new Color(
42 (int)((c.getRed()-127) *0.7 + 127),
43 (int)((c.getGreen()-127)*0.7 + 127),
44 (int)((c.getBlue()-127) *0.7 + 127),
45 c.getAlpha());
46 } else {
47 return new Color(
48 (int)(127 - (127-c.getRed()) *0.7),
49 (int)(127 - (127-c.getGreen())*0.7),
50 (int)(127 - (127-c.getBlue()) *0.7),
51 c.getAlpha());
52 }
53 }
54
55 @Override
56 public Component getListCellRendererComponent(JList<? extends OpenTypeListCellBean> list, OpenTypeListCellBean value, int index, boolean selected, boolean hasFocus) {
57 if (value != null) {
58 // Display first level item
59 label.setText(value.label);
60 label.setIcon(value.icon);
61
62 info.setText((value.packag != null) ? " - "+value.packag : "");
63
64 if (selected) {
65 label.setForeground(textSelectionColor);
66 info.setForeground(infoSelectionColor);
67 panel.setBackground(backgroundSelectionColor);
68 } else {
69 label.setForeground(textNonSelectionColor);
70 info.setForeground(infoNonSelectionColor);
71 panel.setBackground(backgroundNonSelectionColor);
72 }
73 } else {
74 label.setText(" ...");
75 label.setIcon(null);
76 info.setText("");
77 label.setForeground(textNonSelectionColor);
78 panel.setBackground(backgroundNonSelectionColor);
79 }
80
81 return panel;
82 }
83 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.renderer;
8
9 import org.jd.gui.api.model.TreeNodeData;
10
11 import javax.swing.*;
12 import javax.swing.tree.DefaultMutableTreeNode;
13 import javax.swing.tree.TreeCellRenderer;
14 import java.awt.*;
15
16 public class TreeNodeRenderer implements TreeCellRenderer {
17 protected Color textSelectionColor;
18 protected Color backgroundSelectionColor;
19 protected Color textNonSelectionColor;
20 protected Color backgroundNonSelectionColor;
21 protected Color textDisabledColor;
22 protected Color backgroundDisabledColor;
23
24 protected JPanel panel;
25 protected JLabel icon, label;
26
27 public TreeNodeRenderer() {
28 panel = new JPanel(new BorderLayout());
29 panel.add(icon = new JLabel(), BorderLayout.WEST);
30 panel.add(label = new JLabel(), BorderLayout.CENTER);
31 panel.setOpaque(false);
32
33 textSelectionColor = UIManager.getColor("Tree.selectionForeground");
34 backgroundSelectionColor = UIManager.getColor("Tree.selectionBackground");
35 textNonSelectionColor = UIManager.getColor("Tree.textForeground");
36 backgroundNonSelectionColor = UIManager.getColor("Tree.textBackground");
37 textDisabledColor = UIManager.getColor("Tree.disabledText");
38 backgroundDisabledColor = UIManager.getColor("Tree.disabled");
39 Insets margins = UIManager.getInsets("Tree.rendererMargins");
40
41 icon.setForeground(textNonSelectionColor);
42 icon.setOpaque(false);
43 icon.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2));
44
45 label.setOpaque(false);
46
47 if (margins != null) {
48 label.setBorder(BorderFactory.createEmptyBorder(margins.top, margins.left, margins.bottom, margins.right));
49 } else {
50 label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4));
51 }
52 }
53
54 @Override
55 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
56 Object data = ((DefaultMutableTreeNode)value).getUserObject();
57
58 if (data instanceof TreeNodeData) {
59 TreeNodeData tnd = (TreeNodeData)data;
60 icon.setIcon(expanded && (tnd.getOpenIcon() != null) ? tnd.getOpenIcon() : tnd.getIcon());
61 label.setText(tnd.getLabel());
62 } else {
63 icon.setIcon(null);
64 label.setText("" + data);
65 }
66
67 if (selected) {
68 if (hasFocus) {
69 label.setForeground(textSelectionColor);
70 label.setBackground(backgroundSelectionColor);
71 } else {
72 label.setForeground(textDisabledColor);
73 label.setBackground(backgroundDisabledColor);
74 }
75 label.setOpaque(true);
76 } else {
77 label.setForeground(textNonSelectionColor);
78 label.setOpaque(false);
79 }
80
81 return panel;
82 }
83 }
0 org.jd.gui.service.mainpanel.ContainerPanelFactoryProvider
0 org.jd.gui.service.preferencespanel.UISingleInstancePreferencesProvider
1 org.jd.gui.service.preferencespanel.UITabsPreferencesProvider
0 buildscript {
1 repositories {
2 jcenter()
3 }
4 dependencies {
5 classpath 'com.netflix.nebula:gradle-ospackage-plugin:5.3.0' // RPM & DEB support
6 classpath 'edu.sc.seis.gradle:launch4j:2.4.4'
7 classpath 'net.sf.proguard:proguard-gradle:6.1.0'
8 }
9 }
10
11 apply plugin: 'java'
12 apply plugin: 'distribution'
13 apply plugin: 'edu.sc.seis.launch4j'
14 apply plugin: 'nebula.ospackage'
15
16 // Common configuration //
17 rootProject.version='1.6.6'
18 rootProject.ext.set('jdCoreVersion', '1.1.3')
19 targetCompatibility = '1.8'
20
21 allprojects {
22 apply plugin: 'eclipse'
23 apply plugin: 'idea'
24
25 tasks.withType(JavaCompile) {
26 sourceCompatibility = targetCompatibility = '1.8'
27 options.compilerArgs << '-Xlint:deprecation'
28 options.compilerArgs << '-Xlint:unchecked'
29 options.encoding = 'UTF-8'
30 }
31
32 repositories {
33 jcenter()
34 }
35
36 configurations {
37 provided
38 compile.extendsFrom provided
39 }
40 }
41
42 // 'cleanIdea' task extension //
43 cleanIdea.doFirst {
44 delete project.name + '.iws'
45 delete 'out'
46 followSymlinks = true
47 }
48
49 // All in one JAR file //
50 subprojects.each { subproject ->
51 evaluationDependsOn(subproject.path)
52 }
53
54 jar {
55 dependsOn subprojects.tasks['jar']
56
57 // Add SPI directory
58 def tmpSpiDir = file('build/tmp/spi')
59 from tmpSpiDir
60 // Add dependencies
61 def deps = []
62 subprojects.each { subproject ->
63 from subproject.sourceSets.main.output.classesDirs
64 from subproject.sourceSets.main.output.resourcesDir
65 deps += subproject.configurations.runtime - subproject.configurations.provided
66 }
67 subprojects.each { subproject ->
68 deps -= subproject.jar.archivePath
69 }
70 deps = deps.unique().collect { it.isDirectory() ? it : zipTree(it) }
71 from deps
72
73 manifest {
74 attributes 'Main-Class': 'org.jd.gui.App',
75 'SplashScreen-Image': 'org/jd/gui/images/jd_icon_128.png',
76 'JD-GUI-Version': project.version,
77 'JD-Core-Version': project.jdCoreVersion
78 }
79 exclude 'META-INF/licenses/**', 'META-INF/maven/**', 'META-INF/INDEX.LIST'
80 exclude '**/ErrorStrip_*.properties', '**/RSyntaxTextArea_*.properties', '**/RTextArea_*.properties'
81 exclude '**/FocusableTip_*.properties', '**/RSyntaxTextArea_License.txt'
82 duplicatesStrategy DuplicatesStrategy.EXCLUDE
83 doFirst {
84 // Create SPI directory
85 tmpSpiDir.deleteDir()
86 def tmpSpiServicesDir = file(tmpSpiDir.path + '/META-INF/services')
87 tmpSpiServicesDir.mkdirs()
88 // Copy and merge SPI config files
89 subprojects.each { subproject ->
90 def servicesDir = file(subproject.sourceSets.main.output.resourcesDir.path + '/META-INF/services')
91 if (servicesDir.exists()) {
92 servicesDir.eachFile { serviceFile ->
93 def target = file(tmpSpiServicesDir.path + '/' + serviceFile.name)
94 target << serviceFile.text
95 }
96 }
97 }
98 }
99 }
100
101 // Minify JAR file //
102 task proguard(type: proguard.gradle.ProGuardTask, dependsOn: 'jar') {
103 configuration 'src/proguard/resources/proguard.config.txt'
104 injars jar.archivePath
105 outjars 'build/libs/' + project.name + '-' + project.version + '-min.jar'
106 libraryjars System.getProperty('java.home') + '/lib/rt.jar'
107 libraryjars System.getProperty('java.home') + '/jmods/'
108 }
109
110 // Java executable wrapper for Windows //
111 launch4j {
112 createExe.dependsOn 'proguard'
113
114 version = textVersion = project.version
115 fileDescription = productName = 'JD-GUI'
116 errTitle 'JD-GUI Windows Wrapper'
117 copyright 'JD-GUI (C) 2008-2019 Emmanuel Dupuy'
118 icon projectDir.path + '/src/launch4j/resources/images/jd-gui.ico'
119 jar projectDir.path + '/' + proguard.outJarFiles[0]
120 bundledJrePath = '%JAVA_HOME%'
121 }
122
123 // Packages for Linux //
124 ospackage {
125 buildDeb.dependsOn 'proguard'
126 buildRpm.dependsOn 'proguard'
127
128 license = file('LICENSE')
129 maintainer 'Emmanuel Dupuy <[email protected]>'
130 os LINUX
131 packageDescription 'JD-GUI, a standalone graphical utility that displays Java sources from CLASS files'
132 packageGroup 'java'
133 packageName project.name
134 release '0'
135 summary 'A Java Decompiler'
136 url 'https://github.com/java-decompiler/jd-gui'
137
138 into '/opt/' + project.name
139 from (proguard.outJarFiles[0]) {
140 fileMode 0755
141 }
142 from ('src/linux/resources/') {
143 fileMode 0755
144 }
145 from 'LICENSE', 'NOTICE', 'README.md'
146
147 postInstall 'cd /opt/' + project.name + '; ln -s ./' + file(proguard.outJarFiles[0]).name + ' ./jd-gui.jar; xdg-icon-resource install --size 128 --novendor ./jd_icon_128.png jd-gui; xdg-desktop-menu install ./*.desktop'
148 preUninstall 'cd /opt/' + project.name + '; rm -f ./jd-gui.jar; rm -fr ./ext; xdg-desktop-menu uninstall ./*.desktop'
149 }
150
151 // Distributions for OSX and Windows //
152 distributions {
153 osx.contents {
154 into('JD-GUI.app/Contents') {
155 from('src/osx/resources') {
156 include 'Info.plist'
157 expand VERSION: project.version,
158 JAR: file(proguard.outJarFiles[0]).name
159 }
160 }
161 into('JD-GUI.app/Contents/MacOS') {
162 from('src/osx/resources') {
163 include 'universalJavaApplicationStub.sh'
164 fileMode 0755
165 }
166 }
167 into('JD-GUI.app/Contents/Resources/Java') {
168 from proguard.outJarFiles[0]
169 }
170 from 'LICENSE', 'NOTICE', 'README.md'
171 }
172 windows.contents {
173 from 'build/launch4j/jd-gui.exe'
174 from 'LICENSE', 'NOTICE', 'README.md'
175 }
176
177 installWindowsDist.dependsOn createExe
178 windowsDistTar.dependsOn createExe
179 windowsDistZip.dependsOn createExe
180
181 installOsxDist.dependsOn 'proguard'
182 osxDistTar.dependsOn 'proguard'
183 osxDistZip.dependsOn 'proguard'
184 }
185
186 build.finalizedBy buildDeb
187 build.finalizedBy buildRpm
0 #Sat Mar 02 11:11:32 CET 2019
1 distributionBase=GRADLE_USER_HOME
2 distributionPath=wrapper/dists
3 zipStoreBase=GRADLE_USER_HOME
4 zipStorePath=wrapper/dists
5 distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
0 #!/usr/bin/env bash
1
2 ##############################################################################
3 ##
4 ## Gradle start up script for UN*X
5 ##
6 ##############################################################################
7
8 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
9 DEFAULT_JVM_OPTS=""
10
11 APP_NAME="Gradle"
12 APP_BASE_NAME=`basename "$0"`
13
14 # Use the maximum available, or set MAX_FD != -1 to use that value.
15 MAX_FD="maximum"
16
17 warn ( ) {
18 echo "$*"
19 }
20
21 die ( ) {
22 echo
23 echo "$*"
24 echo
25 exit 1
26 }
27
28 # OS specific support (must be 'true' or 'false').
29 cygwin=false
30 msys=false
31 darwin=false
32 case "`uname`" in
33 CYGWIN* )
34 cygwin=true
35 ;;
36 Darwin* )
37 darwin=true
38 ;;
39 MINGW* )
40 msys=true
41 ;;
42 esac
43
44 # For Cygwin, ensure paths are in UNIX format before anything is touched.
45 if $cygwin ; then
46 [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
47 fi
48
49 # Attempt to set APP_HOME
50 # Resolve links: $0 may be a link
51 PRG="$0"
52 # Need this for relative symlinks.
53 while [ -h "$PRG" ] ; do
54 ls=`ls -ld "$PRG"`
55 link=`expr "$ls" : '.*-> \(.*\)$'`
56 if expr "$link" : '/.*' > /dev/null; then
57 PRG="$link"
58 else
59 PRG=`dirname "$PRG"`"/$link"
60 fi
61 done
62 SAVED="`pwd`"
63 cd "`dirname \"$PRG\"`/" >&-
64 APP_HOME="`pwd -P`"
65 cd "$SAVED" >&-
66
67 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68
69 # Determine the Java command to use to start the JVM.
70 if [ -n "$JAVA_HOME" ] ; then
71 if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 # IBM's JDK on AIX uses strange locations for the executables
73 JAVACMD="$JAVA_HOME/jre/sh/java"
74 else
75 JAVACMD="$JAVA_HOME/bin/java"
76 fi
77 if [ ! -x "$JAVACMD" ] ; then
78 die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79
80 Please set the JAVA_HOME variable in your environment to match the
81 location of your Java installation."
82 fi
83 else
84 JAVACMD="java"
85 which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86
87 Please set the JAVA_HOME variable in your environment to match the
88 location of your Java installation."
89 fi
90
91 # Increase the maximum file descriptors if we can.
92 if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
93 MAX_FD_LIMIT=`ulimit -H -n`
94 if [ $? -eq 0 ] ; then
95 if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 MAX_FD="$MAX_FD_LIMIT"
97 fi
98 ulimit -n $MAX_FD
99 if [ $? -ne 0 ] ; then
100 warn "Could not set maximum file descriptor limit: $MAX_FD"
101 fi
102 else
103 warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 fi
105 fi
106
107 # For Darwin, add options to specify how the application appears in the dock
108 if $darwin; then
109 GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 fi
111
112 # For Cygwin, switch paths to Windows format before running java
113 if $cygwin ; then
114 APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116
117 # We build the pattern for arguments to be converted via cygpath
118 ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
119 SEP=""
120 for dir in $ROOTDIRSRAW ; do
121 ROOTDIRS="$ROOTDIRS$SEP$dir"
122 SEP="|"
123 done
124 OURCYGPATTERN="(^($ROOTDIRS))"
125 # Add a user-defined pattern to the cygpath arguments
126 if [ "$GRADLE_CYGPATTERN" != "" ] ; then
127 OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
128 fi
129 # Now convert the arguments - kludge to limit ourselves to /bin/sh
130 i=0
131 for arg in "$@" ; do
132 CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
133 CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
134
135 if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
136 eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
137 else
138 eval `echo args$i`="\"$arg\""
139 fi
140 i=$((i+1))
141 done
142 case $i in
143 (0) set -- ;;
144 (1) set -- "$args0" ;;
145 (2) set -- "$args0" "$args1" ;;
146 (3) set -- "$args0" "$args1" "$args2" ;;
147 (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
148 (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
149 (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
150 (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
151 (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
152 (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
153 esac
154 fi
155
156 # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
157 function splitJvmOpts() {
158 JVM_OPTS=("$@")
159 }
160 eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
161 JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
162
163 exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
0 @if "%DEBUG%" == "" @echo off
1 @rem ##########################################################################
2 @rem
3 @rem Gradle startup script for Windows
4 @rem
5 @rem ##########################################################################
6
7 @rem Set local scope for the variables with windows NT shell
8 if "%OS%"=="Windows_NT" setlocal
9
10 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
11 set DEFAULT_JVM_OPTS=
12
13 set DIRNAME=%~dp0
14 if "%DIRNAME%" == "" set DIRNAME=.
15 set APP_BASE_NAME=%~n0
16 set APP_HOME=%DIRNAME%
17
18 @rem Find java.exe
19 if defined JAVA_HOME goto findJavaFromJavaHome
20
21 set JAVA_EXE=java.exe
22 %JAVA_EXE% -version >NUL 2>&1
23 if "%ERRORLEVEL%" == "0" goto init
24
25 echo.
26 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
27 echo.
28 echo Please set the JAVA_HOME variable in your environment to match the
29 echo location of your Java installation.
30
31 goto fail
32
33 :findJavaFromJavaHome
34 set JAVA_HOME=%JAVA_HOME:"=%
35 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
36
37 if exist "%JAVA_EXE%" goto init
38
39 echo.
40 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
41 echo.
42 echo Please set the JAVA_HOME variable in your environment to match the
43 echo location of your Java installation.
44
45 goto fail
46
47 :init
48 @rem Get command-line arguments, handling Windowz variants
49
50 if not "%OS%" == "Windows_NT" goto win9xME_args
51 if "%@eval[2+2]" == "4" goto 4NT_args
52
53 :win9xME_args
54 @rem Slurp the command line arguments.
55 set CMD_LINE_ARGS=
56 set _SKIP=2
57
58 :win9xME_args_slurp
59 if "x%~1" == "x" goto execute
60
61 set CMD_LINE_ARGS=%*
62 goto execute
63
64 :4NT_args
65 @rem Get arguments from the 4NT Shell from JP Software
66 set CMD_LINE_ARGS=%$
67
68 :execute
69 @rem Setup the command line
70
71 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72
73 @rem Execute Gradle
74 "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
75
76 :end
77 @rem End local scope for the variables with windows NT shell
78 if "%ERRORLEVEL%"=="0" goto mainEnd
79
80 :fail
81 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 rem the _cmd.exe /c_ return code!
83 if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 exit /b 1
85
86 :mainEnd
87 if "%OS%"=="Windows_NT" endlocal
88
89 :omega
jd-gui-1.6.3-min.jar less more
Binary diff not shown
+0
-8
jd-gui.desktop less more
0 [Desktop Entry]
1 Comment=Java Decompiler JD-GUI
2 Terminal=false
3 Name=JD-GUI
4 Exec=java -jar /opt/jd-gui/jd-gui.jar
5 Type=Application
6 Icon=jd-gui
7 MimeType=application/java;application/java-vm;application/java-archive
jd_icon_128.png less more
Binary diff not shown
0 apply plugin: 'java'
1
2 dependencies {
3 compile 'com.fifesoft:rsyntaxtextarea:3.0.4'
4 compile 'org.ow2.asm:asm:7.1'
5 compile 'org.jd:jd-core:' + parent.jdCoreVersion
6 compile project(':api')
7 testCompile 'junit:junit:4.12'
8 }
9
10 version = parent.version
11
12 // ANTLR //
13 ext.antlr4 = [
14 antlrSource: 'src/main/antlr',
15 destinationDir: 'src-generated/antlr/java',
16 grammarPackage: 'org.jd.gui.util.parser.antlr'
17 ]
18
19 configurations {
20 antlr4 {
21 description = "ANTLR4"
22 }
23 }
24
25 dependencies {
26 compile 'org.antlr:antlr4-runtime:4.5'
27 antlr4 'org.antlr:antlr4:4.5'
28 }
29
30 task antlr4OutputDir() {
31 mkdir antlr4.destinationDir
32 }
33
34 task antlr4GenerateGrammarSource(dependsOn: antlr4OutputDir, type: JavaExec) {
35 description = 'Generates Java sources from ANTLR4 grammars.'
36
37 inputs.dir file(antlr4.antlrSource)
38 outputs.dir file(antlr4.destinationDir)
39
40 def grammars = fileTree(antlr4.antlrSource).include('**/*.g4')
41 def pkg = antlr4.grammarPackage.replaceAll("\\.", "/")
42
43 main = 'org.antlr.v4.Tool'
44 classpath = configurations.antlr4
45 args = ['-o', "${antlr4.destinationDir}/${pkg}", '-package', antlr4.grammarPackage, grammars.files].flatten()
46 }
47
48 compileJava {
49 dependsOn antlr4GenerateGrammarSource
50 source antlr4.destinationDir
51 }
52
53 clean {
54 delete 'src-generated'
55 }
56
57 idea.module {
58 sourceDirs += file(antlr4.destinationDir)
59 }
60 ideaModule.dependsOn antlr4GenerateGrammarSource
61
62 eclipse.classpath.file.withXml { xml ->
63 def node = xml.asNode()
64 node.appendNode( 'classpathentry', [ kind: 'src', path: antlr4.destinationDir])
65 }
66 eclipseClasspath.dependsOn antlr4GenerateGrammarSource
0 /*
1 [The "BSD licence"]
2 Copyright (c) 2013 Terence Parr, Sam Harwell
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /** A Java 1.7 grammar for ANTLR v4 derived from ANTLR v3 Java grammar.
29 * Uses ANTLR v4's left-recursive expression notation.
30 * It parses ECJ, Netbeans, JDK etc...
31 *
32 * Sam Harwell cleaned this up significantly and updated to 1.7!
33 *
34 * You can test with
35 *
36 * $ antlr4 Java.g4
37 * $ javac *.java
38 * $ grun Java compilationUnit *.java
39 */
40 grammar Java;
41
42 // starting point for parsing a java file
43 compilationUnit
44 : packageDeclaration? importDeclaration* typeDeclaration* EOF
45 ;
46
47 packageDeclaration
48 : annotation* 'package' qualifiedName ';'
49 ;
50
51 importDeclaration
52 : 'import' 'static'? qualifiedName ('.' '*')? ';'
53 ;
54
55 typeDeclaration
56 : classOrInterfaceModifier* classDeclaration
57 | classOrInterfaceModifier* enumDeclaration
58 | classOrInterfaceModifier* interfaceDeclaration
59 | classOrInterfaceModifier* annotationTypeDeclaration
60 | ';'
61 ;
62
63 modifier
64 : classOrInterfaceModifier
65 | ( 'native'
66 | 'synchronized'
67 | 'transient'
68 | 'volatile'
69 )
70 ;
71
72 classOrInterfaceModifier
73 : annotation // class or interface
74 | ( 'public' // class or interface
75 | 'protected' // class or interface
76 | 'private' // class or interface
77 | 'static' // class or interface
78 | 'abstract' // class or interface
79 | 'final' // class only -- does not apply to interfaces
80 | 'strictfp' // class or interface
81 )
82 ;
83
84 variableModifier
85 : 'final'
86 | annotation
87 ;
88
89 classDeclaration
90 : 'class' Identifier typeParameters?
91 ('extends' type)?
92 ('implements' typeList)?
93 classBody
94 ;
95
96 typeParameters
97 : '<' typeParameter (',' typeParameter)* '>'
98 ;
99
100 typeParameter
101 : Identifier ('extends' typeBound)?
102 ;
103
104 typeBound
105 : type ('&' type)*
106 ;
107
108 enumDeclaration
109 : ENUM Identifier ('implements' typeList)?
110 '{' enumConstants? ','? enumBodyDeclarations? '}'
111 ;
112
113 enumConstants
114 : enumConstant (',' enumConstant)*
115 ;
116
117 enumConstant
118 : annotation* Identifier arguments? classBody?
119 ;
120
121 enumBodyDeclarations
122 : ';' classBodyDeclaration*
123 ;
124
125 interfaceDeclaration
126 : 'interface' Identifier typeParameters? ('extends' typeList)? interfaceBody
127 ;
128
129 typeList
130 : type (',' type)*
131 ;
132
133 classBody
134 : '{' classBodyDeclaration* '}'
135 ;
136
137 interfaceBody
138 : '{' interfaceBodyDeclaration* '}'
139 ;
140
141 classBodyDeclaration
142 : ';'
143 | 'static'? block
144 | modifier* memberDeclaration
145 ;
146
147 memberDeclaration
148 : methodDeclaration
149 | genericMethodDeclaration
150 | fieldDeclaration
151 | constructorDeclaration
152 | genericConstructorDeclaration
153 | interfaceDeclaration
154 | annotationTypeDeclaration
155 | classDeclaration
156 | enumDeclaration
157 ;
158
159 /* We use rule this even for void methods which cannot have [] after parameters.
160 This simplifies grammar and we can consider void to be a type, which
161 renders the [] matching as a context-sensitive issue or a semantic check
162 for invalid return type after parsing.
163 */
164 methodDeclaration
165 : (type|'void') Identifier formalParameters ('[' ']')*
166 ('throws' qualifiedNameList)?
167 ( methodBody
168 | ';'
169 )
170 ;
171
172 genericMethodDeclaration
173 : typeParameters methodDeclaration
174 ;
175
176 constructorDeclaration
177 : Identifier formalParameters ('throws' qualifiedNameList)?
178 constructorBody
179 ;
180
181 genericConstructorDeclaration
182 : typeParameters constructorDeclaration
183 ;
184
185 fieldDeclaration
186 : type variableDeclarators ';'
187 ;
188
189 interfaceBodyDeclaration
190 : modifier* interfaceMemberDeclaration
191 | ';'
192 ;
193
194 interfaceMemberDeclaration
195 : constDeclaration
196 | interfaceMethodDeclaration
197 | genericInterfaceMethodDeclaration
198 | interfaceDeclaration
199 | annotationTypeDeclaration
200 | classDeclaration
201 | enumDeclaration
202 ;
203
204 constDeclaration
205 : type constantDeclarator (',' constantDeclarator)* ';'
206 ;
207
208 constantDeclarator
209 : Identifier ('[' ']')* '=' variableInitializer
210 ;
211
212 // see matching of [] comment in methodDeclaratorRest
213 interfaceMethodDeclaration
214 : (type|'void') Identifier formalParameters ('[' ']')*
215 ('throws' qualifiedNameList)?
216 ';'
217 ;
218
219 genericInterfaceMethodDeclaration
220 : typeParameters interfaceMethodDeclaration
221 ;
222
223 variableDeclarators
224 : variableDeclarator (',' variableDeclarator)*
225 ;
226
227 variableDeclarator
228 : variableDeclaratorId ('=' variableInitializer)?
229 ;
230
231 variableDeclaratorId
232 : Identifier ('[' ']')*
233 ;
234
235 variableInitializer
236 : arrayInitializer
237 | expression
238 ;
239
240 arrayInitializer
241 : '{' (variableInitializer (',' variableInitializer)* (',')? )? '}'
242 ;
243
244 enumConstantName
245 : Identifier
246 ;
247
248 type
249 : classOrInterfaceType ('[' ']')*
250 | primitiveType ('[' ']')*
251 ;
252
253 classOrInterfaceType
254 : Identifier typeArguments? ('.' Identifier typeArguments? )*
255 ;
256
257 primitiveType
258 : 'boolean'
259 | 'char'
260 | 'byte'
261 | 'short'
262 | 'int'
263 | 'long'
264 | 'float'
265 | 'double'
266 ;
267
268 typeArguments
269 : '<' typeArgument (',' typeArgument)* '>'
270 ;
271
272 typeArgument
273 : type
274 | '?' (('extends' | 'super') type)?
275 ;
276
277 qualifiedNameList
278 : qualifiedName (',' qualifiedName)*
279 ;
280
281 formalParameters
282 : '(' formalParameterList? ')'
283 ;
284
285 formalParameterList
286 : formalParameter (',' formalParameter)* (',' lastFormalParameter)?
287 | lastFormalParameter
288 ;
289
290 formalParameter
291 : variableModifier* type variableDeclaratorId
292 ;
293
294 lastFormalParameter
295 : variableModifier* type '...' variableDeclaratorId
296 ;
297
298 methodBody
299 : block
300 ;
301
302 constructorBody
303 : block
304 ;
305
306 qualifiedName
307 : Identifier ('.' Identifier)*
308 ;
309
310 literal
311 : IntegerLiteral
312 | FloatingPointLiteral
313 | CharacterLiteral
314 | StringLiteral
315 | BooleanLiteral
316 | 'null'
317 ;
318
319 // ANNOTATIONS
320
321 annotation
322 : '@' annotationName ( '(' ( elementValuePairs | elementValue )? ')' )?
323 ;
324
325 annotationName : qualifiedName ;
326
327 elementValuePairs
328 : elementValuePair (',' elementValuePair)*
329 ;
330
331 elementValuePair
332 : Identifier '=' elementValue
333 ;
334
335 elementValue
336 : expression
337 | annotation
338 | elementValueArrayInitializer
339 ;
340
341 elementValueArrayInitializer
342 : '{' (elementValue (',' elementValue)*)? (',')? '}'
343 ;
344
345 annotationTypeDeclaration
346 : '@' 'interface' Identifier annotationTypeBody
347 ;
348
349 annotationTypeBody
350 : '{' (annotationTypeElementDeclaration)* '}'
351 ;
352
353 annotationTypeElementDeclaration
354 : modifier* annotationTypeElementRest
355 | ';' // this is not allowed by the grammar, but apparently allowed by the actual compiler
356 ;
357
358 annotationTypeElementRest
359 : type annotationMethodOrConstantRest ';'
360 | classDeclaration ';'?
361 | interfaceDeclaration ';'?
362 | enumDeclaration ';'?
363 | annotationTypeDeclaration ';'?
364 ;
365
366 annotationMethodOrConstantRest
367 : annotationMethodRest
368 | annotationConstantRest
369 ;
370
371 annotationMethodRest
372 : Identifier '(' ')' defaultValue?
373 ;
374
375 annotationConstantRest
376 : variableDeclarators
377 ;
378
379 defaultValue
380 : 'default' elementValue
381 ;
382
383 // STATEMENTS / BLOCKS
384
385 block
386 : '{' blockStatement* '}'
387 ;
388
389 blockStatement
390 : localVariableDeclarationStatement
391 | statement
392 | typeDeclaration
393 ;
394
395 localVariableDeclarationStatement
396 : localVariableDeclaration ';'
397 ;
398
399 localVariableDeclaration
400 : variableModifier* type variableDeclarators
401 ;
402
403 statement
404 : block
405 | ASSERT expression (':' expression)? ';'
406 | 'if' parExpression statement ('else' statement)?
407 | 'for' '(' forControl ')' statement
408 | 'while' parExpression statement
409 | 'do' statement 'while' parExpression ';'
410 | 'try' block (catchClause+ finallyBlock? | finallyBlock)
411 | 'try' resourceSpecification block catchClause* finallyBlock?
412 | 'switch' parExpression '{' switchBlockStatementGroup* switchLabel* '}'
413 | 'synchronized' parExpression block
414 | 'return' expression? ';'
415 | 'throw' expression ';'
416 | 'break' Identifier? ';'
417 | 'continue' Identifier? ';'
418 | ';'
419 | statementExpression ';'
420 | Identifier ':' statement
421 ;
422
423 catchClause
424 : 'catch' '(' variableModifier* catchType Identifier ')' block
425 ;
426
427 catchType
428 : qualifiedName ('|' qualifiedName)*
429 ;
430
431 finallyBlock
432 : 'finally' block
433 ;
434
435 resourceSpecification
436 : '(' resources ';'? ')'
437 ;
438
439 resources
440 : resource (';' resource)*
441 ;
442
443 resource
444 : variableModifier* classOrInterfaceType variableDeclaratorId '=' expression
445 ;
446
447 /** Matches cases then statements, both of which are mandatory.
448 * To handle empty cases at the end, we add switchLabel* to statement.
449 */
450 switchBlockStatementGroup
451 : switchLabel+ blockStatement+
452 ;
453
454 switchLabel
455 : 'case' constantExpression ':'
456 | 'case' enumConstantName ':'
457 | 'default' ':'
458 ;
459
460 forControl
461 : enhancedForControl
462 | forInit? ';' expression? ';' forUpdate?
463 ;
464
465 forInit
466 : localVariableDeclaration
467 | expressionList
468 ;
469
470 enhancedForControl
471 : variableModifier* type variableDeclaratorId ':' expression
472 ;
473
474 forUpdate
475 : expressionList
476 ;
477
478 // EXPRESSIONS
479
480 parExpression
481 : '(' expression ')'
482 ;
483
484 expressionList
485 : expression (',' expression)*
486 ;
487
488 statementExpression
489 : expression
490 ;
491
492 constantExpression
493 : expression
494 ;
495
496 expression
497 : primary
498 | expression '.' Identifier
499 | expression '.' 'this'
500 | expression '.' 'new' nonWildcardTypeArguments? innerCreator
501 | expression '.' 'super' superSuffix
502 | expression '.' explicitGenericInvocation
503 | expression '[' expression ']'
504 | expression '(' expressionList? ')'
505 | 'new' creator
506 | '(' type ')' expression
507 | expression ('++' | '--')
508 | ('+'|'-'|'++'|'--') expression
509 | ('~'|'!') expression
510 | expression ('*'|'/'|'%') expression
511 | expression ('+'|'-') expression
512 | expression ('<' '<' | '>' '>' '>' | '>' '>') expression
513 | expression ('<=' | '>=' | '>' | '<') expression
514 | expression 'instanceof' type
515 | expression ('==' | '!=') expression
516 | expression '&' expression
517 | expression '^' expression
518 | expression '|' expression
519 | expression '&&' expression
520 | expression '||' expression
521 | expression '?' expression ':' expression
522 | <assoc=right> expression
523 ( '='
524 | '+='
525 | '-='
526 | '*='
527 | '/='
528 | '&='
529 | '|='
530 | '^='
531 | '>>='
532 | '>>>='
533 | '<<='
534 | '%='
535 )
536 expression
537 ;
538
539 primary
540 : '(' expression ')'
541 | 'this'
542 | 'super'
543 | literal
544 | Identifier
545 | type '.' 'class'
546 | 'void' '.' 'class'
547 | nonWildcardTypeArguments (explicitGenericInvocationSuffix | 'this' arguments)
548 ;
549
550 creator
551 : nonWildcardTypeArguments createdName classCreatorRest
552 | createdName (arrayCreatorRest | classCreatorRest)
553 ;
554
555 createdName
556 : Identifier typeArgumentsOrDiamond? ('.' Identifier typeArgumentsOrDiamond?)*
557 | primitiveType
558 ;
559
560 innerCreator
561 : Identifier nonWildcardTypeArgumentsOrDiamond? classCreatorRest
562 ;
563
564 arrayCreatorRest
565 : '['
566 ( ']' ('[' ']')* arrayInitializer
567 | expression ']' ('[' expression ']')* ('[' ']')*
568 )
569 ;
570
571 classCreatorRest
572 : arguments classBody?
573 ;
574
575 explicitGenericInvocation
576 : nonWildcardTypeArguments explicitGenericInvocationSuffix
577 ;
578
579 nonWildcardTypeArguments
580 : '<' typeList '>'
581 ;
582
583 typeArgumentsOrDiamond
584 : '<' '>'
585 | typeArguments
586 ;
587
588 nonWildcardTypeArgumentsOrDiamond
589 : '<' '>'
590 | nonWildcardTypeArguments
591 ;
592
593 superSuffix
594 : arguments
595 | '.' Identifier arguments?
596 ;
597
598 explicitGenericInvocationSuffix
599 : 'super' superSuffix
600 | Identifier arguments
601 ;
602
603 arguments
604 : '(' expressionList? ')'
605 ;
606
607 // LEXER
608
609 // §3.9 Keywords
610
611 ABSTRACT : 'abstract';
612 ASSERT : 'assert';
613 BOOLEAN : 'boolean';
614 BREAK : 'break';
615 BYTE : 'byte';
616 CASE : 'case';
617 CATCH : 'catch';
618 CHAR : 'char';
619 CLASS : 'class';
620 CONST : 'const';
621 CONTINUE : 'continue';
622 DEFAULT : 'default';
623 DO : 'do';
624 DOUBLE : 'double';
625 ELSE : 'else';
626 ENUM : 'enum';
627 EXTENDS : 'extends';
628 FINAL : 'final';
629 FINALLY : 'finally';
630 FLOAT : 'float';
631 FOR : 'for';
632 IF : 'if';
633 GOTO : 'goto';
634 IMPLEMENTS : 'implements';
635 IMPORT : 'import';
636 INSTANCEOF : 'instanceof';
637 INT : 'int';
638 INTERFACE : 'interface';
639 LONG : 'long';
640 NATIVE : 'native';
641 NEW : 'new';
642 PACKAGE : 'package';
643 PRIVATE : 'private';
644 PROTECTED : 'protected';
645 PUBLIC : 'public';
646 RETURN : 'return';
647 SHORT : 'short';
648 STATIC : 'static';
649 STRICTFP : 'strictfp';
650 SUPER : 'super';
651 SWITCH : 'switch';
652 SYNCHRONIZED : 'synchronized';
653 THIS : 'this';
654 THROW : 'throw';
655 THROWS : 'throws';
656 TRANSIENT : 'transient';
657 TRY : 'try';
658 VOID : 'void';
659 VOLATILE : 'volatile';
660 WHILE : 'while';
661
662 // §3.10.1 Integer Literals
663
664 IntegerLiteral
665 : DecimalIntegerLiteral
666 | HexIntegerLiteral
667 | OctalIntegerLiteral
668 | BinaryIntegerLiteral
669 ;
670
671 fragment
672 DecimalIntegerLiteral
673 : DecimalNumeral IntegerTypeSuffix?
674 ;
675
676 fragment
677 HexIntegerLiteral
678 : HexNumeral IntegerTypeSuffix?
679 ;
680
681 fragment
682 OctalIntegerLiteral
683 : OctalNumeral IntegerTypeSuffix?
684 ;
685
686 fragment
687 BinaryIntegerLiteral
688 : BinaryNumeral IntegerTypeSuffix?
689 ;
690
691 fragment
692 IntegerTypeSuffix
693 : [lL]
694 ;
695
696 fragment
697 DecimalNumeral
698 : '0'
699 | NonZeroDigit (Digits? | Underscores Digits)
700 ;
701
702 fragment
703 Digits
704 : Digit (DigitOrUnderscore* Digit)?
705 ;
706
707 fragment
708 Digit
709 : '0'
710 | NonZeroDigit
711 ;
712
713 fragment
714 NonZeroDigit
715 : [1-9]
716 ;
717
718 fragment
719 DigitOrUnderscore
720 : Digit
721 | '_'
722 ;
723
724 fragment
725 Underscores
726 : '_'+
727 ;
728
729 fragment
730 HexNumeral
731 : '0' [xX] HexDigits
732 ;
733
734 fragment
735 HexDigits
736 : HexDigit (HexDigitOrUnderscore* HexDigit)?
737 ;
738
739 fragment
740 HexDigit
741 : [0-9a-fA-F]
742 ;
743
744 fragment
745 HexDigitOrUnderscore
746 : HexDigit
747 | '_'
748 ;
749
750 fragment
751 OctalNumeral
752 : '0' Underscores? OctalDigits
753 ;
754
755 fragment
756 OctalDigits
757 : OctalDigit (OctalDigitOrUnderscore* OctalDigit)?
758 ;
759
760 fragment
761 OctalDigit
762 : [0-7]
763 ;
764
765 fragment
766 OctalDigitOrUnderscore
767 : OctalDigit
768 | '_'
769 ;
770
771 fragment
772 BinaryNumeral
773 : '0' [bB] BinaryDigits
774 ;
775
776 fragment
777 BinaryDigits
778 : BinaryDigit (BinaryDigitOrUnderscore* BinaryDigit)?
779 ;
780
781 fragment
782 BinaryDigit
783 : [01]
784 ;
785
786 fragment
787 BinaryDigitOrUnderscore
788 : BinaryDigit
789 | '_'
790 ;
791
792 // §3.10.2 Floating-Point Literals
793
794 FloatingPointLiteral
795 : DecimalFloatingPointLiteral
796 | HexadecimalFloatingPointLiteral
797 ;
798
799 fragment
800 DecimalFloatingPointLiteral
801 : Digits '.' Digits? ExponentPart? FloatTypeSuffix?
802 | '.' Digits ExponentPart? FloatTypeSuffix?
803 | Digits ExponentPart FloatTypeSuffix?
804 | Digits FloatTypeSuffix
805 ;
806
807 fragment
808 ExponentPart
809 : ExponentIndicator SignedInteger
810 ;
811
812 fragment
813 ExponentIndicator
814 : [eE]
815 ;
816
817 fragment
818 SignedInteger
819 : Sign? Digits
820 ;
821
822 fragment
823 Sign
824 : [+-]
825 ;
826
827 fragment
828 FloatTypeSuffix
829 : [fFdD]
830 ;
831
832 fragment
833 HexadecimalFloatingPointLiteral
834 : HexSignificand BinaryExponent FloatTypeSuffix?
835 ;
836
837 fragment
838 HexSignificand
839 : HexNumeral '.'?
840 | '0' [xX] HexDigits? '.' HexDigits
841 ;
842
843 fragment
844 BinaryExponent
845 : BinaryExponentIndicator SignedInteger
846 ;
847
848 fragment
849 BinaryExponentIndicator
850 : [pP]
851 ;
852
853 // §3.10.3 Boolean Literals
854
855 BooleanLiteral
856 : 'true'
857 | 'false'
858 ;
859
860 // §3.10.4 Character Literals
861
862 CharacterLiteral
863 : '\'' SingleCharacter '\''
864 | '\'' EscapeSequence '\''
865 ;
866
867 fragment
868 SingleCharacter
869 : ~['\\]
870 ;
871
872 // §3.10.5 String Literals
873
874 StringLiteral
875 : '"' StringCharacters? '"'
876 ;
877
878 fragment
879 StringCharacters
880 : StringCharacter+
881 ;
882
883 fragment
884 StringCharacter
885 : ~["\\]
886 | EscapeSequence
887 ;
888
889 // §3.10.6 Escape Sequences for Character and String Literals
890
891 fragment
892 EscapeSequence
893 : '\\' [btnfr"'\\]
894 | OctalEscape
895 | UnicodeEscape
896 ;
897
898 fragment
899 OctalEscape
900 : '\\' OctalDigit
901 | '\\' OctalDigit OctalDigit
902 | '\\' ZeroToThree OctalDigit OctalDigit
903 ;
904
905 fragment
906 UnicodeEscape
907 : '\\' 'u' HexDigit HexDigit HexDigit HexDigit
908 ;
909
910 fragment
911 ZeroToThree
912 : [0-3]
913 ;
914
915 // §3.10.7 The Null Literal
916
917 NullLiteral
918 : 'null'
919 ;
920
921 // §3.11 Separators
922
923 LPAREN : '(';
924 RPAREN : ')';
925 LBRACE : '{';
926 RBRACE : '}';
927 LBRACK : '[';
928 RBRACK : ']';
929 SEMI : ';';
930 COMMA : ',';
931 DOT : '.';
932
933 // §3.12 Operators
934
935 ASSIGN : '=';
936 GT : '>';
937 LT : '<';
938 BANG : '!';
939 TILDE : '~';
940 QUESTION : '?';
941 COLON : ':';
942 EQUAL : '==';
943 LE : '<=';
944 GE : '>=';
945 NOTEQUAL : '!=';
946 AND : '&&';
947 OR : '||';
948 INC : '++';
949 DEC : '--';
950 ADD : '+';
951 SUB : '-';
952 MUL : '*';
953 DIV : '/';
954 BITAND : '&';
955 BITOR : '|';
956 CARET : '^';
957 MOD : '%';
958
959 ADD_ASSIGN : '+=';
960 SUB_ASSIGN : '-=';
961 MUL_ASSIGN : '*=';
962 DIV_ASSIGN : '/=';
963 AND_ASSIGN : '&=';
964 OR_ASSIGN : '|=';
965 XOR_ASSIGN : '^=';
966 MOD_ASSIGN : '%=';
967 LSHIFT_ASSIGN : '<<=';
968 RSHIFT_ASSIGN : '>>=';
969 URSHIFT_ASSIGN : '>>>=';
970
971 // §3.8 Identifiers (must appear after all keywords in the grammar)
972
973 Identifier
974 : JavaLetter JavaLetterOrDigit*
975 ;
976
977 fragment
978 JavaLetter
979 : [a-zA-Z$_] // these are the "java letters" below 0xFF
980 | // covers all characters above 0xFF which are not a surrogate
981 ~[\u0000-\u00FF\uD800-\uDBFF]
982 {Character.isJavaIdentifierStart(_input.LA(-1))}?
983 | // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
984 [\uD800-\uDBFF] [\uDC00-\uDFFF]
985 {Character.isJavaIdentifierStart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
986 ;
987
988 fragment
989 JavaLetterOrDigit
990 : [a-zA-Z0-9$_] // these are the "java letters or digits" below 0xFF
991 | // covers all characters above 0xFF which are not a surrogate
992 ~[\u0000-\u00FF\uD800-\uDBFF]
993 {Character.isJavaIdentifierPart(_input.LA(-1))}?
994 | // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
995 [\uD800-\uDBFF] [\uDC00-\uDFFF]
996 {Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
997 ;
998
999 //
1000 // Additional symbols not defined in the lexical specification
1001 //
1002
1003 AT : '@';
1004 ELLIPSIS : '...';
1005
1006 //
1007 // Whitespace and comments
1008 //
1009
1010 WS : [ \t\r\n\u000C]+ -> skip
1011 ;
1012
1013 COMMENT
1014 : '/*' .*? '*/' -> skip
1015 ;
1016
1017 LINE_COMMENT
1018 : '//' ~[\r\n]* -> skip
1019 ;
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.fife.ui.rtextarea;
8
9 import org.fife.ui.rsyntaxtextarea.DocumentRange;
10
11 import java.util.List;
12
13 /*
14 * An utility class to call the restricted access methods of 'RTextArea'.
15 *
16 * JD-GUI uses two workarounds for RSyntaxTextArea:
17 * - org.fife.ui.rtextarea.Marker
18 * - org.jd.gui.view.component.RoundMarkErrorStrip
19 */
20 public class Marker {
21 public static void markAll(RTextArea textArea, List<DocumentRange> ranges) {
22 textArea.markAll(ranges);
23 }
24
25 public static void clearMarkAllHighlights(RTextArea textArea) {
26 textArea.clearMarkAllHighlights();
27 }
28 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.model.Container;
10
11 import java.util.Comparator;
12
13 /**
14 * Directories before files, sorted by path
15 */
16 public class ContainerEntryComparator implements Comparator<Container.Entry> {
17 public static final ContainerEntryComparator COMPARATOR = new ContainerEntryComparator();
18
19 public int compare(Container.Entry e1, Container.Entry e2) {
20 if (e1.isDirectory()) {
21 if (!e2.isDirectory()) {
22 return -1;
23 }
24 } else {
25 if (e2.isDirectory()) {
26 return 1;
27 }
28 }
29 return e1.getPath().compareTo(e2.getPath());
30 }
31 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13
14 public class EarContainer extends GenericContainer {
15 public EarContainer(API api, Container.Entry parentEntry, Path rootPath) {
16 super(api, parentEntry, rootPath);
17 }
18
19 public String getType() { return "ear"; }
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.spi.ContainerFactory;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import java.io.File;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.net.URI;
18 import java.net.URISyntaxException;
19 import java.nio.file.*;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Iterator;
24
25 public class GenericContainer implements Container {
26 protected static final long TIMESTAMP = System.currentTimeMillis();
27
28 protected static long tmpFileCounter = 0;
29
30 protected API api;
31 protected int rootNameCount;
32 protected Container.Entry root;
33
34 public GenericContainer(API api, Container.Entry parentEntry, Path rootPath) {
35 try {
36 URI uri = parentEntry.getUri();
37
38 this.api = api;
39 this.rootNameCount = rootPath.getNameCount();
40 this.root = new Entry(parentEntry, rootPath, new URI(uri.getScheme(), uri.getHost(), uri.getPath() + "!/", null)) {
41 public Entry newChildEntry(Path fsPath) {
42 return new Entry(parent, fsPath, null);
43 }
44 };
45 } catch (URISyntaxException e) {
46 assert ExceptionUtil.printStackTrace(e);
47 }
48 }
49
50 public String getType() { return "generic"; }
51 public Container.Entry getRoot() { return root; }
52
53 protected class Entry implements Container.Entry {
54 protected Container.Entry parent;
55 protected Path fsPath;
56 protected String strPath;
57 protected URI uri;
58 protected Boolean isDirectory;
59 protected Collection<Container.Entry> children;
60
61 public Entry(Container.Entry parent, Path fsPath, URI uri) {
62 this.parent = parent;
63 this.fsPath = fsPath;
64 this.strPath = null;
65 this.uri = uri;
66 this.isDirectory = null;
67 this.children = null;
68 }
69
70 public Entry newChildEntry(Path fsPath) { return new Entry(this, fsPath, null); }
71
72 public Container getContainer() { return GenericContainer.this; }
73 public Container.Entry getParent() { return parent; }
74
75 public URI getUri() {
76 if (uri == null) {
77 try {
78 URI rootUri = root.getUri();
79 uri = new URI(rootUri.getScheme(), rootUri.getHost(), rootUri.getPath() + getPath(), null);
80 } catch (URISyntaxException e) {
81 assert ExceptionUtil.printStackTrace(e);
82 }
83 }
84 return uri;
85 }
86
87 public String getPath() {
88 if (strPath == null) {
89 int nameCount = fsPath.getNameCount();
90
91 if (rootNameCount == nameCount) {
92 strPath = "";
93 } else {
94 strPath = fsPath.subpath(rootNameCount, nameCount).toString().replace(fsPath.getFileSystem().getSeparator(), "/");
95
96 int strPathLength = strPath.length();
97
98 if ((strPathLength > 0) && strPath.charAt(strPathLength-1) == '/') {
99 // Cut last separator
100 strPath = strPath.substring(0, strPathLength-1);
101 }
102 }
103 }
104 return strPath;
105 }
106
107 public boolean isDirectory() {
108 if (isDirectory == null) {
109 isDirectory = Boolean.valueOf(Files.isDirectory(fsPath));
110 }
111 return isDirectory;
112 }
113
114 public long length() {
115 try {
116 return Files.size(fsPath);
117 } catch (IOException e) {
118 assert ExceptionUtil.printStackTrace(e);
119 return -1L;
120 }
121 }
122
123 public InputStream getInputStream() {
124 try {
125 return Files.newInputStream(fsPath);
126 } catch (IOException e) {
127 assert ExceptionUtil.printStackTrace(e);
128 return null;
129 }
130 }
131
132 public Collection<Container.Entry> getChildren() {
133 if (children == null) {
134 try {
135 if (Files.isDirectory(fsPath)) {
136 children = loadChildrenFromDirectoryEntry();
137 } else {
138 children = loadChildrenFromFileEntry();
139 }
140 } catch (IOException e) {
141 assert ExceptionUtil.printStackTrace(e);
142 }
143 }
144 return children;
145 }
146
147 protected Collection<Container.Entry> loadChildrenFromDirectoryEntry() throws IOException {
148 try (DirectoryStream<Path> stream = Files.newDirectoryStream(fsPath)) {
149 ArrayList<Container.Entry> children = new ArrayList<>();
150 int parentNameCount = fsPath.getNameCount();
151
152 for (Path subPath : stream) {
153 if (subPath.getNameCount() > parentNameCount) {
154 children.add(newChildEntry(subPath));
155 }
156 }
157
158 children.sort(ContainerEntryComparator.COMPARATOR);
159 return Collections.unmodifiableCollection(children);
160 }
161 }
162
163 protected Collection<Container.Entry> loadChildrenFromFileEntry() throws IOException {
164 StringBuilder suffix = new StringBuilder(".").append(TIMESTAMP).append('.').append(tmpFileCounter++).append('.').append(fsPath.getFileName().toString());
165 File tmpFile = File.createTempFile("jd-gui.tmp.", suffix.toString());
166 Path tmpPath = Paths.get(tmpFile.toURI());
167
168 tmpFile.delete();
169 tmpFile.deleteOnExit();
170 Files.copy(fsPath, tmpPath);
171
172 FileSystem subFileSystem = FileSystems.newFileSystem(tmpPath, null);
173
174 if (subFileSystem != null) {
175 Iterator<Path> rootDirectories = subFileSystem.getRootDirectories().iterator();
176
177 if (rootDirectories.hasNext()) {
178 Path rootPath = rootDirectories.next();
179 ContainerFactory containerFactory = api.getContainerFactory(rootPath);
180
181 if (containerFactory != null) {
182 Container container = containerFactory.make(api, this, rootPath);
183
184 if (container != null) {
185 return container.getRoot().getChildren();
186 }
187 }
188 }
189 }
190
191 tmpFile.delete();
192 return Collections.emptyList();
193 }
194 }
195 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13
14 public class JarContainer extends GenericContainer {
15 public JarContainer(API api, Container.Entry parentEntry, Path rootPath) {
16 super(api, parentEntry, rootPath);
17 }
18
19 public String getType() { return "jar"; }
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13
14 public class JavaModuleContainer extends GenericContainer {
15 public JavaModuleContainer(API api, Container.Entry parentEntry, Path rootPath) {
16 super(api, parentEntry, rootPath);
17 }
18
19 public String getType() { return "jmod"; }
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13
14 public class KarContainer extends GenericContainer {
15 public KarContainer(API api, Container.Entry parentEntry, Path rootPath) {
16 super(api, parentEntry, rootPath);
17 }
18
19 public String getType() { return "kar"; }
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.model.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11
12 import java.nio.file.Path;
13
14 public class WarContainer extends GenericContainer {
15 public WarContainer(API api, Container.Entry parentEntry, Path rootPath) {
16 super(api, parentEntry, rootPath);
17 }
18
19 public String getType() { return "war"; }
20 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.actions;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Type;
12 import org.jd.gui.spi.ContextualActionsFactory;
13 import org.jd.gui.spi.TypeFactory;
14
15 import javax.swing.*;
16 import java.awt.*;
17 import java.awt.datatransfer.StringSelection;
18 import java.awt.event.ActionEvent;
19 import java.util.Collection;
20 import java.util.Collections;
21
22 public class CopyQualifiedNameContextualActionsFactory implements ContextualActionsFactory {
23
24 public Collection<Action> make(API api, Container.Entry entry, String fragment) {
25 return Collections.<Action>singletonList(new CopyQualifiedNameAction(api, entry, fragment));
26 }
27
28 public static class CopyQualifiedNameAction extends AbstractAction {
29 protected static final ImageIcon ICON = new ImageIcon(CopyQualifiedNameAction.class.getClassLoader().getResource("org/jd/gui/images/cpyqual_menu.png"));
30
31 protected API api;
32 protected Container.Entry entry;
33 protected String fragment;
34
35 public CopyQualifiedNameAction(API api, Container.Entry entry, String fragment) {
36 this.api = api;
37 this.entry = entry;
38 this.fragment = fragment;
39
40 putValue(GROUP_NAME, "Edit > CutCopyPaste");
41 putValue(NAME, "Copy Qualified Name");
42 putValue(SMALL_ICON, ICON);
43 }
44
45 public void actionPerformed(ActionEvent e) {
46 TypeFactory typeFactory = api.getTypeFactory(entry);
47
48 if (typeFactory != null) {
49 Type type = typeFactory.make(api, entry, fragment);
50
51 if (type != null) {
52 StringBuilder sb = new StringBuilder(type.getDisplayPackageName());
53
54 if (sb.length() > 0) {
55 sb.append('.');
56 }
57
58 sb.append(type.getDisplayTypeName());
59
60 if (fragment != null) {
61 int dashIndex = fragment.indexOf('-');
62
63 if (dashIndex != -1) {
64 int lastDashIndex = fragment.lastIndexOf('-');
65
66 if (dashIndex == lastDashIndex) {
67 // See jd.gui.api.feature.UriOpenable
68 throw new InvalidFormatException("fragment: " + fragment);
69 } else {
70 String name = fragment.substring(dashIndex + 1, lastDashIndex);
71 String descriptor = fragment.substring(lastDashIndex + 1);
72
73 if (descriptor.startsWith("(")) {
74 for (Type.Method method : type.getMethods()) {
75 if (method.getName().equals(name) && method.getDescriptor().equals(descriptor)) {
76 sb.append('.').append(method.getDisplayName());
77 break;
78 }
79 }
80 } else {
81 for (Type.Field field : type.getFields()) {
82 if (field.getName().equals(name) && field.getDescriptor().equals(descriptor)) {
83 sb.append('.').append(field.getDisplayName());
84 break;
85 }
86 }
87 }
88 }
89 }
90 }
91
92 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(sb.toString()), null);
93 return;
94 }
95 }
96
97 // Create qualified name from URI
98 String path = entry.getUri().getPath();
99 String rootPath = entry.getContainer().getRoot().getUri().getPath();
100 String qualifiedName = path.substring(rootPath.length()).replace('/', '.');
101
102 if (qualifiedName.endsWith(".class")) {
103 qualifiedName = qualifiedName.substring(0, qualifiedName.length()-6);
104 }
105
106 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(qualifiedName), null);
107 }
108 }
109 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.actions;
8
9 public class InvalidFormatException extends RuntimeException{
10 public InvalidFormatException(String message) { super(message); }
11 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.model.container.EarContainer;
12 import org.jd.gui.spi.ContainerFactory;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import java.nio.file.Files;
16 import java.nio.file.InvalidPathException;
17 import java.nio.file.Path;
18
19 public class EarContainerFactoryProvider implements ContainerFactory {
20 @Override
21 public String getType() { return "ear"; }
22
23 @Override
24 public boolean accept(API api, Path rootPath) {
25 if (rootPath.toUri().toString().toLowerCase().endsWith(".ear!/")) {
26 return true;
27 } else {
28 // Extension: accept uncompressed EAR file containing a folder 'META-INF/application.xml'
29 try {
30 return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("META-INF/application.xml"));
31 } catch (InvalidPathException e) {
32 assert ExceptionUtil.printStackTrace(e);
33 return false;
34 }
35 }
36 }
37
38 @Override
39 public Container make(API api, Container.Entry parentEntry, Path rootPath) {
40 return new EarContainer(api, parentEntry, rootPath);
41 }
42 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.model.container.GenericContainer;
12 import org.jd.gui.spi.ContainerFactory;
13
14 import java.nio.file.Path;
15
16 public class GenericContainerFactoryProvider implements ContainerFactory {
17 @Override
18 public String getType() { return "generic"; }
19
20 @Override
21 public boolean accept(API api, Path rootPath) { return true; }
22
23 @Override
24 public Container make(API api, Container.Entry parentEntry, Path rootPath) {
25 return new GenericContainer(api, parentEntry, rootPath);
26 }
27 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.model.container.JarContainer;
12 import org.jd.gui.spi.ContainerFactory;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import java.nio.file.Files;
16 import java.nio.file.InvalidPathException;
17 import java.nio.file.Path;
18
19 public class JarContainerFactoryProvider implements ContainerFactory {
20 @Override
21 public String getType() { return "jar"; }
22
23 @Override
24 public boolean accept(API api, Path rootPath) {
25 if (rootPath.toUri().toString().toLowerCase().endsWith(".jar!/")) {
26 // Specification: http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html
27 return true;
28 } else {
29 // Extension: accept uncompressed JAR file containing a folder 'META-INF'
30 try {
31 return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("META-INF"));
32 } catch (InvalidPathException e) {
33 assert ExceptionUtil.printStackTrace(e);
34 return false;
35 }
36 }
37 }
38
39 @Override
40 public Container make(API api, Container.Entry parentEntry, Path rootPath) {
41 return new JarContainer(api, parentEntry, rootPath);
42 }
43 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.model.container.JavaModuleContainer;
12 import org.jd.gui.spi.ContainerFactory;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import java.nio.file.Files;
16 import java.nio.file.InvalidPathException;
17 import java.nio.file.Path;
18
19 public class JavaModuleContainerFactoryProvider implements ContainerFactory {
20 @Override
21 public String getType() { return "jmod"; }
22
23 @Override
24 public boolean accept(API api, Path rootPath) {
25 if (rootPath.toUri().toString().toLowerCase().endsWith(".jmod!/")) {
26 return true;
27 } else {
28 // Extension: accept uncompressed JMOD file containing a folder 'classes'
29 try {
30 return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("classes"));
31 } catch (InvalidPathException e) {
32 assert ExceptionUtil.printStackTrace(e);
33 return false;
34 }
35 }
36 }
37
38 @Override
39 public Container make(API api, Container.Entry parentEntry, Path rootPath) {
40 return new JavaModuleContainer(api, parentEntry, rootPath);
41 }
42 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.model.container.KarContainer;
12 import org.jd.gui.spi.ContainerFactory;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import java.nio.file.Files;
16 import java.nio.file.InvalidPathException;
17 import java.nio.file.Path;
18
19 public class KarContainerFactoryProvider implements ContainerFactory {
20 @Override
21 public String getType() { return "kar"; }
22
23 @Override
24 public boolean accept(API api, Path rootPath) {
25 if (rootPath.toUri().toString().toLowerCase().endsWith(".kar!/")) {
26 return true;
27 } else {
28 // Extension: accept uncompressed KAR file containing a folder 'repository'
29 try {
30 return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("repository"));
31 } catch (InvalidPathException e) {
32 assert ExceptionUtil.printStackTrace(e);
33 return false;
34 }
35 }
36 }
37
38 @Override
39 public Container make(API api, Container.Entry parentEntry, Path rootPath) {
40 return new KarContainer(api, parentEntry, rootPath);
41 }
42 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.container;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.model.container.WarContainer;
12 import org.jd.gui.spi.ContainerFactory;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import java.nio.file.Files;
16 import java.nio.file.InvalidPathException;
17 import java.nio.file.Path;
18
19 public class WarContainerFactoryProvider implements ContainerFactory {
20 @Override
21 public String getType() { return "war"; }
22
23 @Override
24 public boolean accept(API api, Path rootPath) {
25 if (rootPath.toUri().toString().toLowerCase().endsWith(".war!/")) {
26 return true;
27 } else {
28 // Extension: accept uncompressed WAR file containing a folder 'WEB-INF'
29 try {
30 return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("WEB-INF"));
31 } catch (InvalidPathException e) {
32 assert ExceptionUtil.printStackTrace(e);
33 return false;
34 }
35 }
36 }
37
38 @Override
39 public Container make(API api, Container.Entry parentEntry, Path rootPath) {
40 return new WarContainer(api, parentEntry, rootPath);
41 }
42 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public class AarFileLoaderProvider extends ZipFileLoaderProvider {
14 protected static final String[] EXTENSIONS = { "aar" };
15
16 @Override public String[] getExtensions() { return EXTENSIONS; }
17 @Override public String getDescription() { return "Android archive files (*.aar)"; }
18
19 @Override
20 public boolean accept(API api, File file) {
21 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".aar");
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.UriGettable;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.api.model.TreeNodeData;
13 import org.jd.gui.spi.ContainerFactory;
14 import org.jd.gui.spi.FileLoader;
15 import org.jd.gui.spi.PanelFactory;
16 import org.jd.gui.spi.TreeNodeFactory;
17 import org.jd.gui.util.exception.ExceptionUtil;
18
19 import javax.swing.*;
20 import java.io.*;
21 import java.net.URI;
22 import java.nio.file.Path;
23 import java.util.Collection;
24 import java.util.Collections;
25
26 public abstract class AbstractFileLoaderProvider implements FileLoader {
27 protected <T extends JComponent & UriGettable> T load(API api, File file, Path rootPath) {
28 ContainerEntry parentEntry = new ContainerEntry(file);
29 ContainerFactory containerFactory = api.getContainerFactory(rootPath);
30
31 if (containerFactory != null) {
32 Container container = containerFactory.make(api, parentEntry, rootPath);
33
34 if (container != null) {
35 parentEntry.setChildren(container.getRoot().getChildren());
36
37 PanelFactory panelFactory = api.getMainPanelFactory(container);
38
39 if (panelFactory != null) {
40 T mainPanel = panelFactory.make(api, container);
41
42 if (mainPanel != null) {
43 TreeNodeFactory treeNodeFactory = api.getTreeNodeFactory(parentEntry);
44 Object data = (treeNodeFactory != null) ? treeNodeFactory.make(api, parentEntry).getUserObject() : null;
45 Icon icon = (data instanceof TreeNodeData) ? ((TreeNodeData)data).getIcon() : null;
46 String location = file.getPath();
47
48 api.addPanel(file.getName(), icon, "Location: " + location, mainPanel);
49 return mainPanel;
50 }
51 }
52 }
53 }
54
55 return null;
56 }
57
58 protected static class ContainerEntry implements Container.Entry {
59 protected static final Container PARENT_CONTAINER = new Container() {
60 @Override public String getType() { return "generic"; }
61 @Override public Container.Entry getRoot() { return null; }
62 };
63
64 protected Collection<Container.Entry> children = Collections.emptyList();
65 protected File file;
66 protected URI uri;
67 protected String path;
68
69 public ContainerEntry(File file) {
70 this.file = file;
71 this.uri = file.toURI();
72 this.path = uri.getPath();
73
74 if (path.endsWith("/")) {
75 path = path.substring(0, path.length() - 1);
76 }
77 }
78
79 @Override public Container getContainer() { return PARENT_CONTAINER; }
80 @Override public Container.Entry getParent() { return null; }
81 @Override public URI getUri() { return uri; }
82 @Override public String getPath() { return path; }
83 @Override public boolean isDirectory() { return file.isDirectory(); }
84 @Override public long length() { return file.length(); }
85 @Override public Collection<Container.Entry> getChildren() { return children; }
86
87 @Override
88 public InputStream getInputStream() {
89 try {
90 return new BufferedInputStream(new FileInputStream(file));
91 } catch (FileNotFoundException e) {
92 assert ExceptionUtil.printStackTrace(e);
93 return null;
94 }
95 }
96
97 public void setChildren(Collection<Container.Entry> children) {
98 this.children = children;
99 }
100 }
101 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.UriOpenable;
11 import org.jd.gui.util.exception.ExceptionUtil;
12
13 import javax.swing.*;
14 import java.io.File;
15 import java.net.URI;
16 import java.net.URISyntaxException;
17 import java.nio.file.Paths;
18
19 public abstract class AbstractTypeFileLoaderProvider extends AbstractFileLoaderProvider {
20 protected boolean load(API api, File file, String pathInFile) {
21 // Search root path
22 String pathSuffix = pathInFile;
23 String path = file.getPath();
24
25 while (! path.endsWith(pathSuffix)) {
26 int index = pathSuffix.indexOf(File.separator);
27
28 if (index == -1) {
29 pathSuffix = "";
30 } else {
31 pathSuffix = pathSuffix.substring(index+1);
32 }
33 }
34
35 if (! pathSuffix.isEmpty()) {
36 // Init root file
37 File rootFile = file;
38 int index = pathSuffix.indexOf(File.separator);
39
40 while (index != -1) {
41 rootFile = rootFile.getParentFile();
42 pathSuffix = pathSuffix.substring(index+1);
43 index = pathSuffix.indexOf(File.separator);
44 }
45 rootFile = rootFile.getParentFile();
46
47 // Create panel
48 JComponent mainPanel = load(api, rootFile, Paths.get(rootFile.toURI()));
49
50 if (mainPanel instanceof UriOpenable) {
51 try {
52 // Open page
53 pathSuffix = file.getAbsolutePath().substring(rootFile.getAbsolutePath().length()).replace(File.separator, "/");
54 URI rootUri = rootFile.toURI();
55 URI uri = new URI(rootUri.getScheme(), rootUri.getHost(), rootUri.getPath() + '!' + pathSuffix, null);
56 ((UriOpenable)mainPanel).openUri(uri);
57 return true;
58 } catch (URISyntaxException e) {
59 assert ExceptionUtil.printStackTrace(e);
60 }
61 } else {
62 return mainPanel != null;
63 }
64 }
65
66 return false;
67 }
68 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.util.exception.ExceptionUtil;
11 import org.objectweb.asm.ClassReader;
12
13 import java.io.BufferedInputStream;
14 import java.io.File;
15 import java.io.FileInputStream;
16 import java.io.IOException;
17
18 public class ClassFileLoaderProvider extends AbstractTypeFileLoaderProvider {
19 protected static final String[] EXTENSIONS = { "class" };
20
21 @Override public String[] getExtensions() { return EXTENSIONS; }
22 @Override public String getDescription() { return "Class files (*.class)"; }
23
24 @Override
25 public boolean accept(API api, File file) {
26 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".class");
27 }
28
29 @Override
30 public boolean load(API api, File file) {
31 try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
32 ClassReader classReader = new ClassReader(bis);
33 String pathInFile = classReader.getClassName().replace("/", File.separator) + ".class";
34
35 return load(api, file, pathInFile);
36 } catch (IOException e) {
37 assert ExceptionUtil.printStackTrace(e);
38 return false;
39 }
40 }
41 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public class EarFileLoaderProvider extends ZipFileLoaderProvider {
14 protected static final String[] EXTENSIONS = { "ear" };
15
16 @Override public String[] getExtensions() { return EXTENSIONS; }
17 @Override public String getDescription() { return "Enterprise application archive files (*.ear)"; }
18
19 @Override
20 public boolean accept(API api, File file) {
21 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".ear");
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public class JarFileLoaderProvider extends ZipFileLoaderProvider {
14 protected static final String[] EXTENSIONS = { "jar" };
15
16 @Override public String[] getExtensions() { return EXTENSIONS; }
17 @Override public String getDescription() { return "Java archive files (*.jar)"; }
18
19 @Override
20 public boolean accept(API api, File file) {
21 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".jar");
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.util.io.TextReader;
11
12 import java.io.File;
13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern;
15
16 public class JavaFileLoaderProvider extends AbstractTypeFileLoaderProvider {
17 protected static final String[] EXTENSIONS = { "java" };
18
19 @Override public String[] getExtensions() { return EXTENSIONS; }
20 @Override public String getDescription() { return "Java files (*.java)"; }
21
22 @Override
23 public boolean accept(API api, File file) {
24 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".java");
25 }
26
27 @Override
28 public boolean load(API api, File file) {
29 String text = TextReader.getText(file);
30 Pattern pattern = Pattern.compile("(?s)(.*\\s)?package\\s+(\\S+)\\s*;.*");
31 Matcher matcher = pattern.matcher(text);
32
33 if (matcher.matches()) {
34 // Package name found
35 String pathInFile = matcher.group(2).replace(".", File.separator) + File.separator + file.getName();
36
37 return load(api, file, pathInFile);
38 } else {
39 // Package name not found
40 return load(api, file, file.getName());
41 }
42 }
43 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public class JavaModuleFileLoaderProvider extends ZipFileLoaderProvider {
14 protected static final String[] EXTENSIONS = { "jmod" };
15
16 @Override public String[] getExtensions() { return EXTENSIONS; }
17 @Override public String getDescription() { return "Java module files (*.jmod)"; }
18
19 @Override
20 public boolean accept(API api, File file) {
21 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".jmod");
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public class KarFileLoaderProvider extends ZipFileLoaderProvider {
14 protected static final String[] EXTENSIONS = { "kar" };
15
16 @Override public String[] getExtensions() { return EXTENSIONS; }
17 @Override public String getDescription() { return "Karaf archive files (*.kar)"; }
18
19 @Override
20 public boolean accept(API api, File file) {
21 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".kar");
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.util.io.TextReader;
11 import org.jd.gui.view.component.LogPage;
12
13 import java.io.File;
14
15 public class LogFileLoaderProvider extends ZipFileLoaderProvider {
16 protected static final String[] EXTENSIONS = { "log" };
17
18 @Override public String[] getExtensions() { return EXTENSIONS; }
19 @Override public String getDescription() { return "Log files (*.log)"; }
20
21 @Override
22 public boolean accept(API api, File file) {
23 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".log");
24 }
25
26 @Override
27 public boolean load(API api, File file) {
28 api.addPanel(file.getName(), null, "Location: " + file.getAbsolutePath(), new LogPage(api, file.toURI(), TextReader.getText(file)));
29 return true;
30 }
31 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10
11 import java.io.File;
12
13 public class WarFileLoaderProvider extends ZipFileLoaderProvider {
14 protected static final String[] EXTENSIONS = { "war" };
15
16 @Override public String[] getExtensions() { return EXTENSIONS; }
17 @Override public String getDescription() { return "Web application archive files (*.war)"; }
18
19 @Override
20 public boolean accept(API api, File file) {
21 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".war");
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.fileloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.util.exception.ExceptionUtil;
11
12 import java.io.File;
13 import java.io.IOException;
14 import java.net.URI;
15 import java.net.URISyntaxException;
16 import java.nio.file.FileSystem;
17 import java.nio.file.FileSystemNotFoundException;
18 import java.nio.file.FileSystems;
19 import java.nio.file.Path;
20 import java.util.Collections;
21 import java.util.Iterator;
22
23 public class ZipFileLoaderProvider extends AbstractFileLoaderProvider {
24 protected static final String[] EXTENSIONS = { "zip" };
25
26 @Override public String[] getExtensions() { return EXTENSIONS; }
27 @Override public String getDescription() { return "Zip files (*.zip)"; }
28
29 @Override
30 public boolean accept(API api, File file) {
31 return file.exists() && file.isFile() && file.canRead() && file.getName().toLowerCase().endsWith(".zip");
32 }
33
34 @Override
35 public boolean load(API api, File file) {
36 try {
37 URI fileUri = file.toURI();
38 URI uri = new URI("jar:" + fileUri.getScheme(), fileUri.getHost(), fileUri.getPath() + "!/", null);
39 FileSystem fileSystem;
40
41 try {
42 fileSystem = FileSystems.getFileSystem(uri);
43 } catch (FileSystemNotFoundException e) {
44 fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
45 }
46
47 if (fileSystem != null) {
48 Iterator<Path> rootDirectories = fileSystem.getRootDirectories().iterator();
49
50 if (rootDirectories.hasNext()) {
51 return load(api, file, rootDirectories.next()) != null;
52 }
53 }
54 } catch (URISyntaxException|IOException e) {
55 assert ExceptionUtil.printStackTrace(e);
56 }
57
58 return false;
59 }
60 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.api.model.Indexes;
11 import org.jd.gui.spi.Indexer;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.util.*;
17 import java.util.regex.Pattern;
18
19 public abstract class AbstractIndexerProvider implements Indexer {
20 protected List<String> externalSelectors;
21 protected Pattern externalPathPattern;
22
23 /**
24 * Initialize "selectors" and "pathPattern" with optional external properties file
25 */
26 public AbstractIndexerProvider() {
27 Properties properties = new Properties();
28 Class clazz = this.getClass();
29
30 try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".properties")) {
31 if (is != null) {
32 properties.load(is);
33 }
34 } catch (IOException e) {
35 assert ExceptionUtil.printStackTrace(e);
36 }
37
38 init(properties);
39 }
40
41 protected void init(Properties properties) {
42 String selectors = properties.getProperty("selectors");
43
44 if (selectors != null) {
45 externalSelectors = Arrays.asList(selectors.split(","));
46 }
47
48 String pathRegExp = properties.getProperty("pathRegExp");
49
50 if (pathRegExp != null) {
51 externalPathPattern = Pattern.compile(pathRegExp);
52 }
53 }
54
55 protected String[] appendSelectors(String selector) {
56 if (externalSelectors == null) {
57 return new String[] { selector };
58 } else {
59 int size = externalSelectors.size();
60 String[] array = new String[size+1];
61 externalSelectors.toArray(array);
62 array[size] = selector;
63 return array;
64 }
65 }
66
67 protected String[] appendSelectors(String... selectors) {
68 if (externalSelectors == null) {
69 return selectors;
70 } else {
71 int size = externalSelectors.size();
72 String[] array = new String[size+selectors.length];
73 externalSelectors.toArray(array);
74 System.arraycopy(selectors, 0, array, size, selectors.length);
75 return array;
76 }
77 }
78
79 @Override public Pattern getPathPattern() { return externalPathPattern; }
80
81 @SuppressWarnings("unchecked")
82 protected static void addToIndexes(Indexes indexes, String indexName, Set<String> set, Container.Entry entry) {
83 if (set.size() > 0) {
84 Map<String, Collection> index = indexes.getIndex(indexName);
85
86 for (String key : set) {
87 index.get(key).add(entry);
88 }
89 }
90 }
91 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.exception.ExceptionUtil;
13 import org.objectweb.asm.*;
14 import org.objectweb.asm.signature.SignatureReader;
15 import org.objectweb.asm.signature.SignatureVisitor;
16
17 import java.io.InputStream;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.Map;
21 import java.util.regex.Pattern;
22
23 import static org.objectweb.asm.ClassReader.*;
24
25 /**
26 * Unsafe thread implementation of class file indexer.
27 */
28 public class ClassFileIndexerProvider extends AbstractIndexerProvider {
29 protected HashSet<String> typeDeclarationSet = new HashSet<>();
30 protected HashSet<String> constructorDeclarationSet = new HashSet<>();
31 protected HashSet<String> methodDeclarationSet = new HashSet<>();
32 protected HashSet<String> fieldDeclarationSet = new HashSet<>();
33 protected HashSet<String> typeReferenceSet = new HashSet<>();
34 protected HashSet<String> constructorReferenceSet = new HashSet<>();
35 protected HashSet<String> methodReferenceSet = new HashSet<>();
36 protected HashSet<String> fieldReferenceSet = new HashSet<>();
37 protected HashSet<String> stringSet = new HashSet<>();
38 protected HashSet<String> superTypeNameSet = new HashSet<>();
39 protected HashSet<String> descriptorSet = new HashSet<>();
40
41 protected ClassIndexer classIndexer = new ClassIndexer();
42 protected SignatureIndexer signatureIndexer = new SignatureIndexer();
43
44 @Override public String[] getSelectors() { return appendSelectors("*:file:*.class"); }
45
46 @Override
47 public Pattern getPathPattern() {
48 if (externalPathPattern == null) {
49 return Pattern.compile("^((?!module-info\\.class).)*$");
50 } else {
51 return externalPathPattern;
52 }
53 }
54
55 @Override
56 @SuppressWarnings("unchecked")
57 public void index(API api, Container.Entry entry, Indexes indexes) {
58 // Cleaning sets...
59 typeDeclarationSet.clear();
60 constructorDeclarationSet.clear();
61 methodDeclarationSet.clear();
62 fieldDeclarationSet.clear();
63 typeReferenceSet.clear();
64 constructorReferenceSet.clear();
65 methodReferenceSet.clear();
66 fieldReferenceSet.clear();
67 stringSet.clear();
68 superTypeNameSet.clear();
69 descriptorSet.clear();
70
71 try (InputStream inputStream = entry.getInputStream()) {
72 // Index field, method, interfaces & super type
73 ClassReader classReader = new ClassReader(inputStream);
74 classReader.accept(classIndexer, SKIP_CODE|SKIP_DEBUG|SKIP_FRAMES);
75
76 // Index descriptors
77 for (String descriptor : descriptorSet) {
78 new SignatureReader(descriptor).accept(signatureIndexer);
79 }
80
81 // Index references
82 char[] buffer = new char[classReader.getMaxStringLength()];
83
84 for (int i=classReader.getItemCount()-1; i>0; i--) {
85 int startIndex = classReader.getItem(i);
86
87 if (startIndex != 0) {
88 int tag = classReader.readByte(startIndex-1);
89
90 switch (tag) {
91 case 7: // CONSTANT_Class
92 String className = classReader.readUTF8(startIndex, buffer);
93 if (className.startsWith("[")) {
94 new SignatureReader(className).acceptType(signatureIndexer);
95 } else {
96 typeReferenceSet.add(className);
97 }
98 break;
99 case 8: // CONSTANT_String
100 String str = classReader.readUTF8(startIndex, buffer);
101 stringSet.add(str);
102 break;
103 case 9: // CONSTANT_Fieldref
104 int nameAndTypeItem = classReader.readUnsignedShort(startIndex+2);
105 int nameAndTypeIndex = classReader.getItem(nameAndTypeItem);
106 tag = classReader.readByte(nameAndTypeIndex-1);
107 if (tag == 12) { // CONSTANT_NameAndType
108 String fieldName = classReader.readUTF8(nameAndTypeIndex, buffer);
109 fieldReferenceSet.add(fieldName);
110 }
111 break;
112 case 10: // CONSTANT_Methodref:
113 case 11: // CONSTANT_InterfaceMethodref:
114 nameAndTypeItem = classReader.readUnsignedShort(startIndex+2);
115 nameAndTypeIndex = classReader.getItem(nameAndTypeItem);
116 tag = classReader.readByte(nameAndTypeIndex-1);
117 if (tag == 12) { // CONSTANT_NameAndType
118 String methodName = classReader.readUTF8(nameAndTypeIndex, buffer);
119 if ("<init>".equals(methodName)) {
120 int classItem = classReader.readUnsignedShort(startIndex);
121 int classIndex = classReader.getItem(classItem);
122 className = classReader.readUTF8(classIndex, buffer);
123 constructorReferenceSet.add(className);
124 } else {
125 methodReferenceSet.add(methodName);
126 }
127 }
128 break;
129 }
130 }
131 }
132
133 String typeName = classIndexer.name;
134
135 // Append sets to indexes
136 addToIndexes(indexes, "typeDeclarations", typeDeclarationSet, entry);
137 addToIndexes(indexes, "constructorDeclarations", constructorDeclarationSet, entry);
138 addToIndexes(indexes, "methodDeclarations", methodDeclarationSet, entry);
139 addToIndexes(indexes, "fieldDeclarations", fieldDeclarationSet, entry);
140 addToIndexes(indexes, "typeReferences", typeReferenceSet, entry);
141 addToIndexes(indexes, "constructorReferences", constructorReferenceSet, entry);
142 addToIndexes(indexes, "methodReferences", methodReferenceSet, entry);
143 addToIndexes(indexes, "fieldReferences", fieldReferenceSet, entry);
144 addToIndexes(indexes, "strings", stringSet, entry);
145
146 // Populate map [super type name : [sub type name]]
147 if (superTypeNameSet.size() > 0) {
148 Map<String, Collection> index = indexes.getIndex("subTypeNames");
149
150 for (String superTypeName : superTypeNameSet) {
151 index.get(superTypeName).add(typeName);
152 }
153 }
154 } catch (Exception e) {
155 assert ExceptionUtil.printStackTrace(e);
156 }
157 }
158
159 protected class ClassIndexer extends ClassVisitor {
160 protected AnnotationIndexer annotationIndexer = new AnnotationIndexer();
161 protected FieldIndexer fieldIndexer = new FieldIndexer(annotationIndexer);
162 protected MethodIndexer methodIndexer = new MethodIndexer(annotationIndexer);
163
164 protected String name;
165
166 public ClassIndexer() { super(Opcodes.ASM7); }
167
168 @Override
169 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
170 this.name = name;
171 typeDeclarationSet.add(name);
172
173 if (superName != null) {
174 superTypeNameSet.add(superName);
175 }
176
177 if (interfaces != null) {
178 for (int i=interfaces.length-1; i>=0; i--) {
179 superTypeNameSet.add(interfaces[i]);
180 }
181 }
182 }
183
184 @Override
185 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
186 descriptorSet.add(desc);
187 return annotationIndexer;
188 }
189
190 @Override
191 public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
192 descriptorSet.add(desc);
193 return annotationIndexer;
194 }
195
196 @Override
197 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
198 fieldDeclarationSet.add(name);
199 descriptorSet.add(signature==null ? desc : signature);
200 return fieldIndexer;
201 }
202
203 @Override
204 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
205 if ("<init>".equals(name)) {
206 constructorDeclarationSet.add(this.name);
207 } else if (! "<clinit>".equals(name)) {
208 methodDeclarationSet.add(name);
209 }
210
211 descriptorSet.add(signature==null ? desc : signature);
212
213 if (exceptions != null) {
214 for (int i=exceptions.length-1; i>=0; i--) {
215 typeReferenceSet.add(exceptions[i]);
216 }
217 }
218 return methodIndexer;
219 }
220 }
221
222 protected class SignatureIndexer extends SignatureVisitor {
223 SignatureIndexer() { super(Opcodes.ASM7); }
224
225 @Override public void visitClassType(String name) { typeReferenceSet.add(name); }
226 }
227
228 protected class AnnotationIndexer extends AnnotationVisitor {
229 public AnnotationIndexer() { super(Opcodes.ASM7); }
230
231 @Override public void visitEnum(String name, String desc, String value) { descriptorSet.add(desc); }
232
233 @Override
234 public AnnotationVisitor visitAnnotation(String name, String desc) {
235 descriptorSet.add(desc);
236 return this;
237 }
238 }
239
240 protected class FieldIndexer extends FieldVisitor {
241 protected AnnotationIndexer annotationIndexer;
242
243 public FieldIndexer(AnnotationIndexer annotationIndexer) {
244 super(Opcodes.ASM7);
245 this.annotationIndexer = annotationIndexer;
246 }
247
248 @Override
249 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
250 descriptorSet.add(desc);
251 return annotationIndexer;
252 }
253
254 @Override
255 public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
256 descriptorSet.add(desc);
257 return annotationIndexer;
258 }
259 }
260
261 protected class MethodIndexer extends MethodVisitor {
262 protected AnnotationIndexer annotationIndexer;
263
264 public MethodIndexer(AnnotationIndexer annotationIndexer) {
265 super(Opcodes.ASM7);
266 this.annotationIndexer = annotationIndexer;
267 }
268
269 @Override
270 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
271 descriptorSet.add(desc);
272 return annotationIndexer;
273 }
274
275 @Override
276 public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
277 descriptorSet.add(desc);
278 return annotationIndexer;
279 }
280
281 @Override
282 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
283 descriptorSet.add(desc);
284 return annotationIndexer;
285 }
286 }
287 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.spi.Indexer;
13
14 public class DirectoryIndexerProvider extends AbstractIndexerProvider {
15
16 @Override public String[] getSelectors() { return appendSelectors("*:dir:*"); }
17
18 @Override
19 public void index(API api, Container.Entry entry, Indexes indexes) {
20 int depth = 15;
21
22 try {
23 depth = Integer.valueOf(api.getPreferences().get("DirectoryIndexerPreferences.maximumDepth"));
24 } catch (NumberFormatException ignore) {
25 }
26
27 index(api, entry, indexes, depth);
28 }
29
30 public void index(API api, Container.Entry entry, Indexes indexes, int depth) {
31 if (depth-- > 0) {
32 for (Container.Entry e : entry.getChildren()) {
33 if (e.isDirectory()) {
34 index(api, e, indexes, depth);
35 } else {
36 Indexer indexer = api.getIndexer(e);
37
38 if (indexer != null) {
39 indexer.index(api, e, indexes);
40 }
41 }
42 }
43 }
44 }
45 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.io.TextReader;
13 import org.jd.gui.util.xml.AbstractXmlPathFinder;
14
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Map;
18
19 public class EjbJarXmlFileIndexerProvider extends XmlBasedFileIndexerProvider {
20
21 @Override public String[] getSelectors() { return appendSelectors("*:file:META-INF/ejb-jar.xml"); }
22
23 @Override
24 public void index(API api, Container.Entry entry, Indexes indexes) {
25 super.index(api, entry, indexes);
26
27 new EjbJarXmlPathFinder(entry, indexes).find(TextReader.getText(entry.getInputStream()));
28 }
29
30 public static class EjbJarXmlPathFinder extends AbstractXmlPathFinder {
31 protected Container.Entry entry;
32 protected Map<String, Collection> index;
33
34 public EjbJarXmlPathFinder(Container.Entry entry, Indexes indexes) {
35 super(Arrays.asList(
36 "ejb-jar/assembly-descriptor/application-exception/exception-class",
37 "ejb-jar/assembly-descriptor/interceptor-binding/interceptor-class",
38
39 "ejb-jar/enterprise-beans/entity/home",
40 "ejb-jar/enterprise-beans/entity/remote",
41 "ejb-jar/enterprise-beans/entity/ejb-class",
42 "ejb-jar/enterprise-beans/entity/prim-key-class",
43
44 "ejb-jar/enterprise-beans/message-driven/ejb-class",
45 "ejb-jar/enterprise-beans/message-driven/messaging-type",
46 "ejb-jar/enterprise-beans/message-driven/resource-ref/injection-target/injection-target-class",
47 "ejb-jar/enterprise-beans/message-driven/resource-env-ref/injection-target/injection-target-class",
48
49 "ejb-jar/enterprise-beans/session/home",
50 "ejb-jar/enterprise-beans/session/local",
51 "ejb-jar/enterprise-beans/session/remote",
52 "ejb-jar/enterprise-beans/session/business-local",
53 "ejb-jar/enterprise-beans/session/business-remote",
54 "ejb-jar/enterprise-beans/session/service-endpoint",
55 "ejb-jar/enterprise-beans/session/ejb-class",
56 "ejb-jar/enterprise-beans/session/ejb-ref/home",
57 "ejb-jar/enterprise-beans/session/ejb-ref/remote",
58
59 "ejb-jar/interceptors/interceptor/around-invoke/class",
60 "ejb-jar/interceptors/interceptor/ejb-ref/home",
61 "ejb-jar/interceptors/interceptor/ejb-ref/remote",
62 "ejb-jar/interceptors/interceptor/interceptor-class"
63 ));
64 this.entry = entry;
65 this.index = indexes.getIndex("typeReferences");
66 }
67
68 @Override
69 @SuppressWarnings("unchecked")
70 public void handle(String path, String text, int position) {
71 index.get(text.replace(".", "/")).add(entry);
72 }
73 }
74 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.antlr.v4.runtime.ANTLRInputStream;
10 import org.antlr.v4.runtime.ParserRuleContext;
11 import org.antlr.v4.runtime.tree.ParseTree;
12 import org.antlr.v4.runtime.tree.TerminalNode;
13 import org.jd.gui.api.API;
14 import org.jd.gui.api.model.Container;
15 import org.jd.gui.api.model.Indexes;
16 import org.jd.gui.util.exception.ExceptionUtil;
17 import org.jd.gui.util.parser.antlr.ANTLRJavaParser;
18 import org.jd.gui.util.parser.antlr.AbstractJavaListener;
19 import org.jd.gui.util.parser.antlr.JavaParser;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.*;
24
25 /**
26 * Unsafe thread implementation of java file indexer.
27 */
28 public class JavaFileIndexerProvider extends AbstractIndexerProvider {
29
30 static {
31 // Early class loading
32 ANTLRJavaParser.parse(new ANTLRInputStream("class EarlyLoading{}"), new Listener(null));
33 }
34
35 @Override public String[] getSelectors() { return appendSelectors("*:file:*.java"); }
36
37 @Override
38 @SuppressWarnings("unchecked")
39 public void index(API api, Container.Entry entry, Indexes indexes) {
40 try (InputStream inputStream = entry.getInputStream()) {
41 Listener listener = new Listener(entry);
42 ANTLRJavaParser.parse(new ANTLRInputStream(inputStream), listener);
43
44 // Append sets to indexes
45 addToIndexes(indexes, "typeDeclarations", listener.getTypeDeclarationSet(), entry);
46 addToIndexes(indexes, "constructorDeclarations", listener.getConstructorDeclarationSet(), entry);
47 addToIndexes(indexes, "methodDeclarations", listener.getMethodDeclarationSet(), entry);
48 addToIndexes(indexes, "fieldDeclarations", listener.getFieldDeclarationSet(), entry);
49 addToIndexes(indexes, "typeReferences", listener.getTypeReferenceSet(), entry);
50 addToIndexes(indexes, "constructorReferences", listener.getConstructorReferenceSet(), entry);
51 addToIndexes(indexes, "methodReferences", listener.getMethodReferenceSet(), entry);
52 addToIndexes(indexes, "fieldReferences", listener.getFieldReferenceSet(), entry);
53 addToIndexes(indexes, "strings", listener.getStringSet(), entry);
54
55 // Populate map [super type name : [sub type name]]
56 Map<String, Collection> index = indexes.getIndex("subTypeNames");
57
58 for (Map.Entry<String, HashSet<String>> e : listener.getSuperTypeNamesMap().entrySet()) {
59 String typeName = e.getKey();
60
61 for (String superTypeName : e.getValue()) {
62 index.get(superTypeName).add(typeName);
63 }
64 }
65 } catch (IOException e) {
66 assert ExceptionUtil.printStackTrace(e);
67 }
68 }
69
70 protected static class Listener extends AbstractJavaListener {
71
72 protected HashSet<String> typeDeclarationSet = new HashSet<>();
73 protected HashSet<String> constructorDeclarationSet = new HashSet<>();
74 protected HashSet<String> methodDeclarationSet = new HashSet<>();
75 protected HashSet<String> fieldDeclarationSet = new HashSet<>();
76 protected HashSet<String> typeReferenceSet = new HashSet<>();
77 protected HashSet<String> constructorReferenceSet = new HashSet<>();
78 protected HashSet<String> methodReferenceSet = new HashSet<>();
79 protected HashSet<String> fieldReferenceSet = new HashSet<>();
80 protected HashSet<String> stringSet = new HashSet<>();
81 protected HashMap<String, HashSet<String>> superTypeNamesMap = new HashMap<>();
82
83 protected StringBuilder sbTypeDeclaration = new StringBuilder();
84
85 public Listener(Container.Entry entry) {
86 super(entry);
87 }
88
89 public HashSet<String> getTypeDeclarationSet() { return typeDeclarationSet; }
90 public HashSet<String> getConstructorDeclarationSet() { return constructorDeclarationSet; }
91 public HashSet<String> getMethodDeclarationSet() { return methodDeclarationSet; }
92 public HashSet<String> getFieldDeclarationSet() { return fieldDeclarationSet; }
93 public HashSet<String> getTypeReferenceSet() { return typeReferenceSet; }
94 public HashSet<String> getConstructorReferenceSet() { return constructorReferenceSet; }
95 public HashSet<String> getMethodReferenceSet() { return methodReferenceSet; }
96 public HashSet<String> getFieldReferenceSet() { return fieldReferenceSet; }
97 public HashSet<String> getStringSet() { return stringSet; }
98 public HashMap<String, HashSet<String>> getSuperTypeNamesMap() { return superTypeNamesMap; }
99
100 // --- ANTLR Listener --- //
101
102 public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
103 super.enterPackageDeclaration(ctx);
104
105 if (! packageName.isEmpty()) {
106 sbTypeDeclaration.append(packageName).append('/');
107 }
108 }
109
110 public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
111 public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
112
113 public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
114 public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
115
116 public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
117 public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
118
119 public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
120 public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
121
122 protected void enterTypeDeclaration(ParserRuleContext ctx) {
123 // Add type declaration
124 TerminalNode identifier = ctx.getToken(JavaParser.Identifier, 0);
125
126 if (identifier != null) {
127 String typeName = identifier.getText();
128 int length = sbTypeDeclaration.length();
129
130 if ((length == 0) || (sbTypeDeclaration.charAt(length - 1) == '/')) {
131 sbTypeDeclaration.append(typeName);
132 } else {
133 sbTypeDeclaration.append('$').append(typeName);
134 }
135
136 String internalTypeName = sbTypeDeclaration.toString();
137 typeDeclarationSet.add(internalTypeName);
138 nameToInternalTypeName.put(typeName, internalTypeName);
139
140 HashSet<String> superInternalTypeNameSet = new HashSet<>();
141
142 // Add super type reference
143 JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
144 if (superType != null) {
145 String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
146
147 if (superQualifiedTypeName.charAt(0) != '*')
148 superInternalTypeNameSet.add(superQualifiedTypeName);
149 }
150
151 // Add implementation references
152 JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0);
153 if (superInterfaces != null) {
154 for (JavaParser.TypeContext superInterface : superInterfaces.type()) {
155 String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier());
156
157 if (superQualifiedInterfaceName.charAt(0) != '*')
158 superInternalTypeNameSet.add(superQualifiedInterfaceName);
159 }
160 }
161
162 if (!superInternalTypeNameSet.isEmpty()) {
163 superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet);
164 }
165 }
166 }
167
168 protected void exitTypeDeclaration() {
169 int index = sbTypeDeclaration.lastIndexOf("$");
170
171 if (index == -1) {
172 index = sbTypeDeclaration.lastIndexOf("/") + 1;
173 }
174
175 if (index == -1) {
176 sbTypeDeclaration.setLength(0);
177 } else {
178 sbTypeDeclaration.setLength(index);
179 }
180 }
181
182 public void enterType(JavaParser.TypeContext ctx) {
183 // Add type reference
184 JavaParser.ClassOrInterfaceTypeContext classOrInterfaceType = ctx.classOrInterfaceType();
185
186 if (classOrInterfaceType != null) {
187 String internalTypeName = resolveInternalTypeName(classOrInterfaceType.Identifier());
188
189 if (internalTypeName.charAt(0) != '*')
190 typeReferenceSet.add(internalTypeName);
191 }
192 }
193
194 public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
195 for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
196 String name = constantDeclaratorContext.Identifier().getText();
197 fieldDeclarationSet.add(name);
198 }
199 }
200
201 public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
202 for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
203 TerminalNode identifier = declaration.variableDeclaratorId().Identifier();
204
205 if (identifier != null) {
206 String name = identifier.getText();
207 fieldDeclarationSet.add(name);
208 }
209 }
210 }
211
212 public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
213 TerminalNode identifier = ctx.Identifier();
214
215 if (identifier != null) {
216 String name = identifier.getText();
217 methodDeclarationSet.add(name);
218 }
219 }
220
221 public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
222 TerminalNode identifier = ctx.Identifier();
223
224 if (identifier != null) {
225 String name = identifier.getText();
226 methodDeclarationSet.add(name);
227 }
228 }
229
230 public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
231 String name = ctx.Identifier().getText();
232 constructorDeclarationSet.add(name);
233 }
234
235 public void enterCreatedName(JavaParser.CreatedNameContext ctx) {
236 String internalTypeName = resolveInternalTypeName(ctx.Identifier());
237
238 if ((internalTypeName != null) && (internalTypeName.charAt(0) != '*'))
239 constructorReferenceSet.add(internalTypeName);
240 }
241
242 public void enterExpression(JavaParser.ExpressionContext ctx) {
243 switch (ctx.getChildCount()) {
244 case 3:
245 if (getToken(ctx.children, 1, JavaParser.DOT) != null) {
246 // Search "expression '.' Identifier" : field
247 TerminalNode identifier3 = getToken(ctx.children, 2, JavaParser.Identifier);
248
249 if (identifier3 != null) {
250 String fieldName = identifier3.getText();
251 fieldReferenceSet.add(fieldName);
252 }
253 } else if (getToken(ctx.children, 1, JavaParser.LPAREN) != null) {
254 // Search "expression '(' ')'" : method
255 if (getToken(ctx.children, 2, JavaParser.RPAREN) != null) {
256 TerminalNode identifier0 = getRightTerminalNode(ctx.children.get(0));
257
258 if (identifier0 != null) {
259 String methodName = identifier0.getText();
260 methodReferenceSet.add(methodName);
261 }
262 }
263 }
264 break;
265 case 4:
266 if (getToken(ctx.children, 1, JavaParser.LPAREN) != null) {
267 // Search "expression '(' expressionList ')'" : method
268 if (getToken(ctx.children, 3, JavaParser.RPAREN) != null) {
269 JavaParser.ExpressionListContext expressionListContext = ctx.expressionList();
270
271 if ((expressionListContext != null) && (expressionListContext == ctx.children.get(2))) {
272 TerminalNode identifier0 = getRightTerminalNode(ctx.children.get(0));
273
274 if (identifier0 != null) {
275 String methodName = identifier0.getText();
276 methodReferenceSet.add(methodName);
277 }
278 }
279 }
280 }
281 break;
282 }
283 }
284
285 protected TerminalNode getToken(List<ParseTree> children, int i, int type) {
286 ParseTree pt = children.get(i);
287
288 if (pt instanceof TerminalNode) {
289 if (((TerminalNode)pt).getSymbol().getType() == type) {
290 return (TerminalNode)pt;
291 }
292 }
293
294 return null;
295 }
296
297 protected TerminalNode getRightTerminalNode(ParseTree pt) {
298 if (pt instanceof ParserRuleContext) {
299 List<ParseTree> children = ((ParserRuleContext)pt).children;
300
301 if (children != null) {
302 int size = children.size();
303
304 if (size > 0) {
305 ParseTree last = children.get(size - 1);
306
307 if (last instanceof TerminalNode) {
308 return (TerminalNode) last;
309 } else {
310 return getRightTerminalNode(last);
311 }
312 }
313 }
314 }
315
316 return null;
317 }
318
319 public void enterLiteral(JavaParser.LiteralContext ctx) {
320 TerminalNode stringLiteral = ctx.StringLiteral();
321 if (stringLiteral != null) {
322 stringSet.add(stringLiteral.getSymbol().getText());
323 }
324 }
325 }
326 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.spi.Indexer;
13
14 import java.util.Collection;
15 import java.util.Map;
16
17 public class JavaModuleFileIndexerProvider extends AbstractIndexerProvider {
18
19 @Override public String[] getSelectors() { return appendSelectors("*:file:*.jmod"); }
20
21 @Override
22 public void index(API api, Container.Entry entry, Indexes indexes) {
23 for (Container.Entry e : entry.getChildren()) {
24 if (e.isDirectory() && e.getPath().equals("classes")) {
25 Map<String, Collection> packageDeclarationIndex = indexes.getIndex("packageDeclarations");
26
27 // Index module-info, packages and CLASS files
28 index(api, e, indexes, packageDeclarationIndex);
29 break;
30 }
31 }
32 }
33
34 @SuppressWarnings("unchecked")
35 protected static void index(API api, Container.Entry entry, Indexes indexes, Map<String, Collection> packageDeclarationIndex) {
36 for (Container.Entry e : entry.getChildren()) {
37 if (e.isDirectory()) {
38 String path = e.getPath();
39
40 if (!path.startsWith("classes/META-INF")) {
41 packageDeclarationIndex.get(path.substring(8)).add(e); // 8 = "classes/".length()
42 }
43
44 index(api, e, indexes, packageDeclarationIndex);
45 } else {
46 Indexer indexer = api.getIndexer(e);
47
48 if (indexer != null) {
49 indexer.index(api, e, indexes);
50 }
51 }
52 }
53 }
54 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.exception.ExceptionUtil;
13 import org.objectweb.asm.*;
14
15 import java.io.InputStream;
16 import java.util.HashSet;
17
18 import static org.objectweb.asm.ClassReader.*;
19
20 /**
21 * Unsafe thread implementation of class file indexer.
22 */
23 public class JavaModuleInfoFileIndexerProvider extends AbstractIndexerProvider {
24 protected HashSet<String> javaModuleDeclarationSet = new HashSet<>();
25 protected HashSet<String> javaModuleReferenceSet = new HashSet<>();
26 protected HashSet<String> typeReferenceSet = new HashSet<>();
27
28 protected ClassIndexer classIndexer = new ClassIndexer();
29
30 @Override public String[] getSelectors() { return appendSelectors("jmod:file:classes/module-info.class"); }
31
32 @Override
33 @SuppressWarnings("unchecked")
34 public void index(API api, Container.Entry entry, Indexes indexes) {
35 // Cleaning sets...
36 javaModuleDeclarationSet.clear();
37 javaModuleReferenceSet.clear();
38 typeReferenceSet.clear();
39
40 try (InputStream inputStream = entry.getInputStream()) {
41 // Index field, method, interfaces & super type
42 ClassReader classReader = new ClassReader(inputStream);
43 classReader.accept(classIndexer, SKIP_CODE|SKIP_DEBUG|SKIP_FRAMES);
44
45 // Append sets to indexes
46 addToIndexes(indexes, "javaModuleDeclarations", javaModuleDeclarationSet, entry);
47 addToIndexes(indexes, "javaModuleReferences", javaModuleReferenceSet, entry);
48 addToIndexes(indexes, "typeReferences", typeReferenceSet, entry);
49 } catch (Exception e) {
50 assert ExceptionUtil.printStackTrace(e);
51 }
52 }
53
54 protected class ClassIndexer extends ClassVisitor {
55 protected ModuleIndexer moduleIndexer = new ModuleIndexer();
56
57 public ClassIndexer() { super(Opcodes.ASM7); }
58
59 @Override
60 public ModuleVisitor visitModule(String moduleName, int moduleFlags, String moduleVersion) {
61 javaModuleDeclarationSet.add(moduleName);
62 return moduleIndexer;
63 }
64 }
65
66 protected class ModuleIndexer extends ModuleVisitor {
67 public ModuleIndexer() { super(Opcodes.ASM7); }
68
69 @Override public void visitMainClass(final String mainClass) { typeReferenceSet.add(mainClass); }
70 @Override public void visitRequire(final String module, final int access, final String version) { javaModuleReferenceSet.add(module); }
71 @Override public void visitUse(final String service) { typeReferenceSet.add(service); }
72
73 @Override
74 public void visitExport(final String packaze, final int access, final String... modules) {
75 if (modules != null) {
76 for (String module : modules) {
77 javaModuleReferenceSet.add(module);
78 }
79 }
80 }
81
82 @Override
83 public void visitOpen(final String packaze, final int access, final String... modules) {
84 if (modules != null) {
85 for (String module : modules) {
86 javaModuleReferenceSet.add(module);
87 }
88 }
89 }
90
91 @Override
92 public void visitProvide(final String service, final String... providers) {
93 typeReferenceSet.add(service);
94
95 if (providers != null) {
96 for (String provider : providers) {
97 typeReferenceSet.add(provider);
98 }
99 }
100 }
101 }
102 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import java.io.BufferedReader;
15 import java.io.IOException;
16 import java.io.InputStreamReader;
17 import java.util.Collection;
18 import java.util.Map;
19 import java.util.regex.Pattern;
20
21 public class MetainfServiceFileIndexerProvider extends AbstractIndexerProvider {
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*"); }
24
25 @Override public Pattern getPathPattern() { return (externalPathPattern != null) ? externalPathPattern : Pattern.compile("META-INF\\/services\\/[^\\/]+"); }
26
27 @Override
28 @SuppressWarnings("unchecked")
29 public void index(API api, Container.Entry entry, Indexes indexes) {
30 Map<String, Collection> index = indexes.getIndex("typeReferences");
31
32 try (BufferedReader br = new BufferedReader(new InputStreamReader(entry.getInputStream()))) {
33 String line;
34
35 while ((line = br.readLine()) != null) {
36 String trim = line.trim();
37
38 if (!trim.isEmpty() && (trim.charAt(0) != '#')) {
39 String internalTypeName = trim.replace(".", "/");
40
41 index.get(internalTypeName).add(entry);
42 }
43 }
44 } catch (IOException e) {
45 assert ExceptionUtil.printStackTrace(e);
46 }
47 }
48 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.io.TextReader;
13
14 public class TextFileIndexerProvider extends AbstractIndexerProvider {
15
16 @Override public String[] getSelectors() {
17 return appendSelectors(
18 "*:file:*.txt", "*:file:*.html", "*:file:*.xhtml", "*:file:*.js", "*:file:*.jsp", "*:file:*.jspf",
19 "*:file:*.xml", "*:file:*.xsl", "*:file:*.xslt", "*:file:*.xsd", "*:file:*.properties", "*:file:*.sql",
20 "*:file:*.yaml", "*:file:*.yml", "*:file:*.json");
21 }
22
23 @Override
24 @SuppressWarnings("unchecked")
25 public void index(API api, Container.Entry entry, Indexes indexes) {
26 indexes.getIndex("strings").get(TextReader.getText(entry.getInputStream())).add(entry);
27 }
28 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.io.TextReader;
13 import org.jd.gui.util.xml.AbstractXmlPathFinder;
14
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Map;
18
19 public class WebXmlFileIndexerProvider extends XmlBasedFileIndexerProvider {
20
21 @Override public String[] getSelectors() { return appendSelectors("*:file:WEB-INF/web.xml"); }
22
23 @Override
24 public void index(API api, Container.Entry entry, Indexes indexes) {
25 super.index(api, entry, indexes);
26
27 new WebXmlPathFinder(entry, indexes).find(TextReader.getText(entry.getInputStream()));
28 }
29
30 protected static class WebXmlPathFinder extends AbstractXmlPathFinder {
31 Container.Entry entry;
32 Map<String, Collection> index;
33
34 public WebXmlPathFinder(Container.Entry entry, Indexes indexes) {
35 super(Arrays.asList(
36 "web-app/filter/filter-class",
37 "web-app/listener/listener-class",
38 "web-app/servlet/servlet-class"
39 ));
40 this.entry = entry;
41 this.index = indexes.getIndex("typeReferences");
42 }
43
44 @Override
45 @SuppressWarnings("unchecked")
46 public void handle(String path, String text, int position) {
47 index.get(text.replace(".", "/")).add(entry);
48 }
49 }
50 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import javax.xml.stream.XMLInputFactory;
15 import javax.xml.stream.XMLStreamConstants;
16 import javax.xml.stream.XMLStreamException;
17 import javax.xml.stream.XMLStreamReader;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.Map;
21
22 public class XmlBasedFileIndexerProvider extends AbstractIndexerProvider {
23 protected XMLInputFactory factory;
24
25 public XmlBasedFileIndexerProvider() {
26 factory = XMLInputFactory.newInstance();
27 factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
28 }
29
30 @Override public String[] getSelectors() { return appendSelectors("*:file:*.xsl", "*:file:*.xslt", "*:file:*.xsd"); }
31
32 @Override
33 @SuppressWarnings("unchecked")
34 public void index(API api, Container.Entry entry, Indexes indexes) {
35 HashSet<String> stringSet = new HashSet<>();
36 XMLStreamReader reader = null;
37
38 try {
39 reader = factory.createXMLStreamReader(entry.getInputStream());
40
41 stringSet.add(reader.getVersion());
42 stringSet.add(reader.getEncoding());
43 stringSet.add(reader.getCharacterEncodingScheme());
44
45 while (reader.hasNext()) {
46 switch (reader.next()) {
47 case XMLStreamConstants.START_ELEMENT:
48 stringSet.add(reader.getLocalName());
49 for (int i = reader.getAttributeCount() - 1; i >= 0; i--) {
50 stringSet.add(reader.getAttributeLocalName(i));
51 stringSet.add(reader.getAttributeValue(i));
52 }
53 for (int i = reader.getNamespaceCount() - 1; i >= 0; i--) {
54 stringSet.add(reader.getNamespacePrefix(i));
55 stringSet.add(reader.getNamespaceURI(i));
56 }
57 break;
58 case XMLStreamConstants.PROCESSING_INSTRUCTION:
59 stringSet.add(reader.getPITarget());
60 stringSet.add(reader.getPIData());
61 break;
62 case XMLStreamConstants.START_DOCUMENT:
63 stringSet.add(reader.getVersion());
64 stringSet.add(reader.getEncoding());
65 stringSet.add(reader.getCharacterEncodingScheme());
66 break;
67 case XMLStreamConstants.ENTITY_REFERENCE:
68 stringSet.add(reader.getLocalName());
69 stringSet.add(reader.getText());
70 break;
71 case XMLStreamConstants.ATTRIBUTE:
72 stringSet.add(reader.getPrefix());
73 stringSet.add(reader.getNamespaceURI());
74 stringSet.add(reader.getLocalName());
75 stringSet.add(reader.getText());
76 break;
77 case XMLStreamConstants.COMMENT:
78 case XMLStreamConstants.DTD:
79 case XMLStreamConstants.CDATA:
80 case XMLStreamConstants.CHARACTERS:
81 stringSet.add(reader.getText().trim());
82 break;
83 case XMLStreamConstants.NAMESPACE:
84 for (int i = reader.getNamespaceCount() - 1; i >= 0; i--) {
85 stringSet.add(reader.getNamespacePrefix(i));
86 stringSet.add(reader.getNamespaceURI(i));
87 }
88 break;
89 }
90 }
91 } catch (Exception e) {
92 assert ExceptionUtil.printStackTrace(e);
93 } finally {
94 if (reader != null) {
95 try {
96 reader.close();
97 } catch (XMLStreamException e) {
98 assert ExceptionUtil.printStackTrace(e);
99 }
100 }
101 }
102
103 Map<String, Collection> stringIndex = indexes.getIndex("strings");
104
105 for (String string : stringSet) {
106 if ((string != null) && !string.isEmpty()) {
107 stringIndex.get(string).add(entry);
108 }
109 }
110 }
111 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import javax.xml.stream.XMLInputFactory;
15 import javax.xml.stream.XMLStreamConstants;
16 import javax.xml.stream.XMLStreamException;
17 import javax.xml.stream.XMLStreamReader;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.Map;
21
22 public class XmlFileIndexerProvider extends AbstractIndexerProvider {
23 protected XMLInputFactory factory;
24
25 public XmlFileIndexerProvider() {
26 factory = XMLInputFactory.newInstance();
27 factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
28 }
29
30 @Override public String[] getSelectors() { return appendSelectors("*:file:*.xml"); }
31
32 @Override
33 @SuppressWarnings("unchecked")
34 public void index(API api, Container.Entry entry, Indexes indexes) {
35 HashSet<String> stringSet = new HashSet<>();
36 HashSet<String> typeReferenceSet = new HashSet<>();
37 XMLStreamReader reader = null;
38
39 try {
40 reader = factory.createXMLStreamReader(entry.getInputStream());
41
42 stringSet.add(reader.getVersion());
43 stringSet.add(reader.getEncoding());
44 stringSet.add(reader.getCharacterEncodingScheme());
45
46 while (reader.hasNext()) {
47 switch (reader.next()) {
48 case XMLStreamConstants.START_ELEMENT:
49 boolean beanFlag = reader.getLocalName().equals("bean");
50
51 stringSet.add(reader.getLocalName());
52 for (int i = reader.getAttributeCount() - 1; i >= 0; i--) {
53 String attributeName = reader.getAttributeLocalName(i);
54
55 stringSet.add(attributeName);
56
57 if (beanFlag && attributeName.equals("class")) {
58 // String bean reference
59 typeReferenceSet.add(reader.getAttributeValue(i).replace(".", "/"));
60 } else {
61 stringSet.add(reader.getAttributeValue(i));
62 }
63 }
64 for (int i = reader.getNamespaceCount() - 1; i >= 0; i--) {
65 stringSet.add(reader.getNamespacePrefix(i));
66 stringSet.add(reader.getNamespaceURI(i));
67 }
68 break;
69 case XMLStreamConstants.PROCESSING_INSTRUCTION:
70 stringSet.add(reader.getPITarget());
71 stringSet.add(reader.getPIData());
72 break;
73 case XMLStreamConstants.START_DOCUMENT:
74 stringSet.add(reader.getVersion());
75 stringSet.add(reader.getEncoding());
76 stringSet.add(reader.getCharacterEncodingScheme());
77 break;
78 case XMLStreamConstants.ENTITY_REFERENCE:
79 stringSet.add(reader.getLocalName());
80 stringSet.add(reader.getText());
81 break;
82 case XMLStreamConstants.ATTRIBUTE:
83 stringSet.add(reader.getPrefix());
84 stringSet.add(reader.getNamespaceURI());
85 stringSet.add(reader.getLocalName());
86 stringSet.add(reader.getText());
87 break;
88 case XMLStreamConstants.COMMENT:
89 case XMLStreamConstants.DTD:
90 case XMLStreamConstants.CDATA:
91 case XMLStreamConstants.CHARACTERS:
92 stringSet.add(reader.getText().trim());
93 break;
94 case XMLStreamConstants.NAMESPACE:
95 for (int i = reader.getNamespaceCount() - 1; i >= 0; i--) {
96 stringSet.add(reader.getNamespacePrefix(i));
97 stringSet.add(reader.getNamespaceURI(i));
98 }
99 break;
100 }
101 }
102 } catch (Exception e) {
103 assert ExceptionUtil.printStackTrace(e);
104 } finally {
105 if (reader != null) {
106 try {
107 reader.close();
108 } catch (XMLStreamException e) {
109 assert ExceptionUtil.printStackTrace(e);
110 }
111 }
112 }
113
114 Map<String, Collection> stringIndex = indexes.getIndex("strings");
115 Map<String, Collection> typeReferenceIndex = indexes.getIndex("typeReferences");
116
117 for (String string : stringSet) {
118 if ((string != null) && !string.isEmpty()) {
119 stringIndex.get(string).add(entry);
120 }
121 }
122
123 for (String ref : typeReferenceSet) {
124 if ((ref != null) && !ref.isEmpty()) {
125 typeReferenceIndex.get(ref).add(entry);
126 }
127 }
128 }
129 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.indexer;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Indexes;
12 import org.jd.gui.spi.Indexer;
13
14 public class ZipFileIndexerProvider extends AbstractIndexerProvider {
15
16 @Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.jar", "*:file:*.war", "*:file:*.ear", "*:file:*.aar", "*:file:*.kar"); }
17
18 @Override
19 public void index(API api, Container.Entry entry, Indexes indexes) {
20 for (Container.Entry e : entry.getChildren()) {
21 if (e.isDirectory()) {
22 index(api, e, indexes);
23 } else {
24 Indexer indexer = api.getIndexer(e);
25
26 if (indexer != null) {
27 indexer.index(api, e, indexes);
28 }
29 }
30 }
31 }
32 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.pastehandler;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.spi.PasteHandler;
11 import org.jd.gui.view.component.LogPage;
12
13 import java.net.URI;
14
15 public class LogPasteHandler implements PasteHandler {
16 protected static int counter = 0;
17
18 public boolean accept(Object obj) { return obj instanceof String; }
19
20 public void paste(API api, Object obj) {
21 String title = "clipboard-" + (++counter) + ".log";
22 URI uri = URI.create("memory://" + title);
23 String content = (obj == null) ? null : obj.toString();
24 api.addPanel(title, null, null, new LogPage(api, uri, content));
25 }
26 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.spi.PreferencesPanel;
10
11 import javax.swing.*;
12 import java.awt.*;
13 import java.util.Map;
14
15 public class ClassFileDecompilerPreferencesProvider extends JPanel implements PreferencesPanel {
16 protected static final String ESCAPE_UNICODE_CHARACTERS = "ClassFileDecompilerPreferences.escapeUnicodeCharacters";
17 protected static final String REALIGN_LINE_NUMBERS = "ClassFileDecompilerPreferences.realignLineNumbers";
18
19 protected PreferencesPanel.PreferencesPanelChangeListener listener = null;
20 protected JCheckBox escapeUnicodeCharactersCheckBox;
21 protected JCheckBox realignLineNumbersCheckBox;
22
23 public ClassFileDecompilerPreferencesProvider() {
24 super(new GridLayout(0,1));
25
26 escapeUnicodeCharactersCheckBox = new JCheckBox("Escape unicode characters");
27 realignLineNumbersCheckBox = new JCheckBox("Realign line numbers");
28
29 add(escapeUnicodeCharactersCheckBox);
30 add(realignLineNumbersCheckBox);
31 }
32
33 // --- PreferencesPanel --- //
34 @Override public String getPreferencesGroupTitle() { return "Decompiler"; }
35 @Override public String getPreferencesPanelTitle() { return "Class file"; }
36 @Override public JComponent getPanel() { return this; }
37
38 @Override public void init(Color errorBackgroundColor) {}
39
40 @Override public boolean isActivated() { return true; }
41
42 @Override
43 public void loadPreferences(Map<String, String> preferences) {
44 escapeUnicodeCharactersCheckBox.setSelected("true".equals(preferences.get(ESCAPE_UNICODE_CHARACTERS)));
45 realignLineNumbersCheckBox.setSelected("true".equals(preferences.get(REALIGN_LINE_NUMBERS)));
46 }
47
48 @Override
49 public void savePreferences(Map<String, String> preferences) {
50 preferences.put(ESCAPE_UNICODE_CHARACTERS, Boolean.toString(escapeUnicodeCharactersCheckBox.isSelected()));
51 preferences.put(REALIGN_LINE_NUMBERS, Boolean.toString(realignLineNumbersCheckBox.isSelected()));
52 }
53
54 @Override public boolean arePreferencesValid() { return true; }
55
56 @Override public void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {}
57 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.spi.PreferencesPanel;
10
11 import javax.swing.*;
12 import java.awt.*;
13 import java.util.Map;
14
15 public class ClassFileSaverPreferencesProvider extends JPanel implements PreferencesPanel {
16 protected static final String WRITE_LINE_NUMBERS = "ClassFileSaverPreferences.writeLineNumbers";
17 protected static final String WRITE_METADATA = "ClassFileSaverPreferences.writeMetadata";
18
19 protected JCheckBox writeLineNumbersCheckBox;
20 protected JCheckBox writeMetadataCheckBox;
21
22 public ClassFileSaverPreferencesProvider() {
23 super(new GridLayout(0,1));
24
25 writeLineNumbersCheckBox = new JCheckBox("Write original line numbers");
26 writeMetadataCheckBox = new JCheckBox("Write metadata");
27
28 add(writeLineNumbersCheckBox);
29 add(writeMetadataCheckBox);
30 }
31
32 // --- PreferencesPanel --- //
33 @Override public String getPreferencesGroupTitle() { return "Source Saver"; }
34 @Override public String getPreferencesPanelTitle() { return "Class file"; }
35 @Override public JComponent getPanel() { return this; }
36
37 @Override public void init(Color errorBackgroundColor) {}
38
39 @Override public boolean isActivated() { return true; }
40
41 @Override
42 public void loadPreferences(Map<String, String> preferences) {
43 writeLineNumbersCheckBox.setSelected(!"false".equals(preferences.get(WRITE_LINE_NUMBERS)));
44 writeMetadataCheckBox.setSelected(!"false".equals(preferences.get(WRITE_METADATA)));
45 }
46
47 @Override
48 public void savePreferences(Map<String, String> preferences) {
49 preferences.put(WRITE_LINE_NUMBERS, Boolean.toString(writeLineNumbersCheckBox.isSelected()));
50 preferences.put(WRITE_METADATA, Boolean.toString(writeMetadataCheckBox.isSelected()));
51 }
52
53 @Override public boolean arePreferencesValid() { return true; }
54
55 @Override public void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {}
56 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.spi.PreferencesPanel;
10 import org.jd.gui.util.exception.ExceptionUtil;
11
12 import javax.swing.*;
13 import javax.swing.event.DocumentEvent;
14 import javax.swing.event.DocumentListener;
15 import java.awt.*;
16 import java.util.Map;
17
18 public class DirectoryIndexerPreferencesProvider extends JPanel implements PreferencesPanel, DocumentListener {
19 protected static final int MAX_VALUE = 30;
20 protected static final String MAXIMUM_DEPTH_KEY = "DirectoryIndexerPreferences.maximumDepth";
21
22 protected PreferencesPanel.PreferencesPanelChangeListener listener = null;
23 protected JTextField maximumDepthTextField;
24 protected Color errorBackgroundColor = Color.RED;
25 protected Color defaultBackgroundColor;
26
27 public DirectoryIndexerPreferencesProvider() {
28 super(new BorderLayout());
29
30 add(new JLabel("Maximum depth (1.." + MAX_VALUE + "): "), BorderLayout.WEST);
31
32 maximumDepthTextField = new JTextField();
33 maximumDepthTextField.getDocument().addDocumentListener(this);
34 add(maximumDepthTextField, BorderLayout.CENTER);
35
36 defaultBackgroundColor = maximumDepthTextField.getBackground();
37 }
38
39 // --- PreferencesPanel --- //
40 @Override public String getPreferencesGroupTitle() { return "Indexer"; }
41 @Override public String getPreferencesPanelTitle() { return "Directory exploration"; }
42 @Override public JComponent getPanel() { return this; }
43
44 @Override public void init(Color errorBackgroundColor) {
45 this.errorBackgroundColor = errorBackgroundColor;
46 }
47
48 @Override public boolean isActivated() { return true; }
49
50 @Override public void loadPreferences(Map<String, String> preferences) {
51 String preference = preferences.get(MAXIMUM_DEPTH_KEY);
52
53 maximumDepthTextField.setText((preference != null) ? preference : "15");
54 maximumDepthTextField.setCaretPosition(maximumDepthTextField.getText().length());
55 }
56
57 @Override
58 public void savePreferences(Map<String, String> preferences) {
59 preferences.put(MAXIMUM_DEPTH_KEY, maximumDepthTextField.getText());
60 }
61
62 @Override
63 public boolean arePreferencesValid() {
64 try {
65 int i = Integer.valueOf(maximumDepthTextField.getText());
66 return (i > 0) && (i <= MAX_VALUE);
67 } catch (NumberFormatException e) {
68 assert ExceptionUtil.printStackTrace(e);
69 return false;
70 }
71 }
72
73 @Override
74 public void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {
75 this.listener = listener;
76 }
77
78 // --- DocumentListener --- //
79 @Override public void insertUpdate(DocumentEvent e) { onTextChange(); }
80 @Override public void removeUpdate(DocumentEvent e) { onTextChange(); }
81 @Override public void changedUpdate(DocumentEvent e) { onTextChange(); }
82
83 public void onTextChange() {
84 maximumDepthTextField.setBackground(arePreferencesValid() ? defaultBackgroundColor : errorBackgroundColor);
85
86 if (listener != null) {
87 listener.preferencesPanelChanged(this);
88 }
89 }
90 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.jd.gui.spi.PreferencesPanel;
10
11 import javax.swing.*;
12 import javax.swing.event.DocumentEvent;
13 import javax.swing.event.DocumentListener;
14 import java.awt.*;
15 import java.awt.event.ActionEvent;
16 import java.awt.event.ActionListener;
17 import java.util.Map;
18 import java.util.regex.Pattern;
19
20 public class MavenOrgSourceLoaderPreferencesProvider extends JPanel implements PreferencesPanel, DocumentListener, ActionListener {
21 public static final String ACTIVATED = "MavenOrgSourceLoaderPreferencesProvider.activated";
22 public static final String FILTERS = "MavenOrgSourceLoaderPreferencesProvider.filters";
23
24 public static final String DEFAULT_FILTERS_VALUE =
25 "+org +com.google +com.springsource +com.sun -com +java +javax +sun +sunw " +
26 "+spring +springframework +springmodules +tomcat +maven +edu";
27
28 protected static final Pattern CONTROL_PATTERN = Pattern.compile("([+-][a-zA-Z_0-9$_.]+(\\s+[+-][a-zA-Z_0-9$_.]+)*)?\\s*");
29
30 protected JCheckBox enableCheckBox;
31 protected JTextArea filtersTextArea;
32 protected JButton resetButton;
33 protected Color errorBackgroundColor = Color.RED;
34 protected Color defaultBackgroundColor;
35
36 protected PreferencesPanel.PreferencesPanelChangeListener listener;
37
38 public MavenOrgSourceLoaderPreferencesProvider() {
39 super(new BorderLayout());
40
41 enableCheckBox = new JCheckBox("Search source code on maven.org for:");
42 enableCheckBox.addActionListener(this);
43
44 filtersTextArea = new JTextArea();
45 filtersTextArea.setFont(getFont());
46 filtersTextArea.setLineWrap(true);
47 filtersTextArea.getDocument().addDocumentListener(this);
48 defaultBackgroundColor = filtersTextArea.getBackground();
49
50 JComponent spacer = new JComponent() {};
51 JScrollPane scrollPane = new JScrollPane(filtersTextArea);
52
53 String osName = System.getProperty("os.name").toLowerCase();
54
55 if (osName.contains("windows")) {
56 spacer.setPreferredSize(new Dimension(22, -1));
57 scrollPane.setPreferredSize(new Dimension(-1, 50));
58 } else if (osName.contains("mac os")) {
59 spacer.setPreferredSize(new Dimension(28, -1));
60 scrollPane.setPreferredSize(new Dimension(-1, 56));
61 } else {
62 spacer.setPreferredSize(new Dimension(22, -1));
63 scrollPane.setPreferredSize(new Dimension(-1, 56));
64 }
65
66 resetButton = new JButton("Reset");
67 resetButton.addActionListener(this);
68
69 JPanel southPanel = new JPanel(new BorderLayout());
70 southPanel.add(resetButton, BorderLayout.EAST);
71
72 add(enableCheckBox, BorderLayout.NORTH);
73 add(spacer, BorderLayout.WEST);
74 add(scrollPane, BorderLayout.CENTER);
75 add(southPanel, BorderLayout.SOUTH);
76 }
77
78 // --- PreferencesPanel --- //
79 @Override public String getPreferencesGroupTitle() { return "Source loader"; }
80 @Override public String getPreferencesPanelTitle() { return "maven.org"; }
81 @Override public JComponent getPanel() { return this; }
82
83 @Override
84 public void init(Color errorBackgroundColor) {
85 this.errorBackgroundColor = errorBackgroundColor;
86 }
87
88 @Override public boolean isActivated() { return true; }
89
90 @Override
91 public void loadPreferences(Map<String, String> preferences) {
92 boolean enabled = !"false".equals(preferences.get(ACTIVATED));
93
94 enableCheckBox.setSelected(enabled);
95 filtersTextArea.setEnabled(enabled);
96 resetButton.setEnabled(enabled);
97
98 String filters = preferences.get(FILTERS);
99
100 filtersTextArea.setText((filters == null) || filters.isEmpty() ? DEFAULT_FILTERS_VALUE : filters);
101 }
102
103 @Override
104 public void savePreferences(Map<String, String> preferences) {
105 preferences.put(ACTIVATED, Boolean.toString(enableCheckBox.isSelected()));
106 preferences.put(FILTERS, filtersTextArea.getText().trim());
107 }
108
109 @Override public boolean arePreferencesValid() {
110 return CONTROL_PATTERN.matcher(filtersTextArea.getText()).matches();
111 }
112
113 @Override public void addPreferencesChangeListener(PreferencesPanelChangeListener listener) {
114 this.listener = listener;
115 }
116
117
118 // --- DocumentListener --- //
119 @Override public void insertUpdate(DocumentEvent e) { onTextChange(); }
120 @Override public void removeUpdate(DocumentEvent e) { onTextChange(); }
121 @Override public void changedUpdate(DocumentEvent e) { onTextChange(); }
122
123 protected void onTextChange() {
124 filtersTextArea.setBackground(arePreferencesValid() ? defaultBackgroundColor : errorBackgroundColor);
125
126 if (listener != null) {
127 listener.preferencesPanelChanged(this);
128 }
129 }
130
131 // --- ActionListener --- //
132 @Override
133 public void actionPerformed(ActionEvent e) {
134 if (e.getSource() == enableCheckBox) {
135 boolean enabled = enableCheckBox.isSelected();
136 filtersTextArea.setEnabled(enabled);
137 resetButton.setEnabled(enabled);
138 } else {
139 // Reset button
140 filtersTextArea.setText(DEFAULT_FILTERS_VALUE);
141 filtersTextArea.requestFocus();
142 }
143 }
144 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.preferencespanel;
8
9 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
10 import org.fife.ui.rsyntaxtextarea.Theme;
11 import org.jd.gui.spi.PreferencesPanel;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import javax.swing.*;
15 import javax.swing.event.DocumentEvent;
16 import javax.swing.event.DocumentListener;
17 import java.awt.*;
18 import java.io.IOException;
19 import java.util.Map;
20
21 public class ViewerPreferencesProvider extends JPanel implements PreferencesPanel, DocumentListener {
22 protected static final int MIN_VALUE = 2;
23 protected static final int MAX_VALUE = 40;
24 protected static final String FONT_SIZE_KEY = "ViewerPreferences.fontSize";
25
26 protected PreferencesPanel.PreferencesPanelChangeListener listener = null;
27 protected JTextField fontSizeTextField;
28 protected Color errorBackgroundColor = Color.RED;
29 protected Color defaultBackgroundColor;
30
31 public ViewerPreferencesProvider() {
32 super(new BorderLayout());
33
34 add(new JLabel("Font size (" + MIN_VALUE + ".." + MAX_VALUE + "): "), BorderLayout.WEST);
35
36 fontSizeTextField = new JTextField();
37 fontSizeTextField.getDocument().addDocumentListener(this);
38 add(fontSizeTextField, BorderLayout.CENTER);
39
40 defaultBackgroundColor = fontSizeTextField.getBackground();
41 }
42
43 // --- PreferencesPanel --- //
44 @Override public String getPreferencesGroupTitle() { return "Viewer"; }
45 @Override public String getPreferencesPanelTitle() { return "Appearance"; }
46 @Override public JComponent getPanel() { return this; }
47
48 @Override public void init(Color errorBackgroundColor) {
49 this.errorBackgroundColor = errorBackgroundColor;
50 }
51
52 @Override public boolean isActivated() { return true; }
53
54 @Override
55 public void loadPreferences(Map<String, String> preferences) {
56 String fontSize = preferences.get(FONT_SIZE_KEY);
57
58 if (fontSize == null) {
59 // Search default value for the current platform
60 RSyntaxTextArea textArea = new RSyntaxTextArea();
61
62 try {
63 Theme theme = Theme.load(getClass().getClassLoader().getResourceAsStream("rsyntaxtextarea/themes/eclipse.xml"));
64 theme.apply(textArea);
65 } catch (IOException e) {
66 assert ExceptionUtil.printStackTrace(e);
67 }
68
69 fontSize = String.valueOf(textArea.getFont().getSize());
70 }
71
72 fontSizeTextField.setText(fontSize);
73 fontSizeTextField.setCaretPosition(fontSizeTextField.getText().length());
74 }
75
76 @Override
77 public void savePreferences(Map<String, String> preferences) {
78 preferences.put(FONT_SIZE_KEY, fontSizeTextField.getText());
79 }
80
81 @Override
82 public boolean arePreferencesValid() {
83 try {
84 int i = Integer.valueOf(fontSizeTextField.getText());
85 return (i >= MIN_VALUE) && (i <= MAX_VALUE);
86 } catch (NumberFormatException e) {
87 assert ExceptionUtil.printStackTrace(e);
88 return false;
89 }
90 }
91
92 @Override
93 public void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {
94 this.listener = listener;
95 }
96
97 // --- DocumentListener --- //
98 @Override public void insertUpdate(DocumentEvent e) { onTextChange(); }
99 @Override public void removeUpdate(DocumentEvent e) { onTextChange(); }
100 @Override public void changedUpdate(DocumentEvent e) { onTextChange(); }
101
102 public void onTextChange() {
103 fontSizeTextField.setBackground(arePreferencesValid() ? defaultBackgroundColor : errorBackgroundColor);
104
105 if (listener != null) {
106 listener.preferencesPanelChanged(this);
107 }
108 }
109 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourceloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.service.preferencespanel.MavenOrgSourceLoaderPreferencesProvider;
12 import org.jd.gui.spi.SourceLoader;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import javax.xml.stream.XMLInputFactory;
16 import javax.xml.stream.XMLStreamConstants;
17 import javax.xml.stream.XMLStreamReader;
18 import java.io.*;
19 import java.net.URL;
20 import java.security.DigestInputStream;
21 import java.security.MessageDigest;
22 import java.util.*;
23 import java.util.zip.ZipEntry;
24 import java.util.zip.ZipInputStream;
25
26 public class MavenOrgSourceLoaderProvider implements SourceLoader {
27 protected static final String MAVENORG_SEARCH_URL_PREFIX = "https://search.maven.org/solrsearch/select?q=1:%22";
28 protected static final String MAVENORG_SEARCH_URL_SUFFIX = "%22&rows=20&wt=xml";
29
30 protected static final String MAVENORG_LOAD_URL_PREFIX = "https://search.maven.org/classic/remotecontent?filepath=";
31 protected static final String MAVENORG_LOAD_URL_SUFFIX = "-sources.jar";
32
33 protected HashSet<Container.Entry> failed = new HashSet<>();
34 protected HashMap<Container.Entry, File> cache = new HashMap<>();
35
36 @Override
37 public String getSource(API api, Container.Entry entry) {
38 if (isActivated(api)) {
39 String filters = api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.FILTERS);
40
41 if ((filters == null) || filters.isEmpty()) {
42 filters = MavenOrgSourceLoaderPreferencesProvider.DEFAULT_FILTERS_VALUE;
43 }
44
45 if (accepted(filters, entry.getPath())) {
46 return searchSource(entry, cache.get(entry.getContainer().getRoot().getParent()));
47 }
48 }
49
50 return null;
51 }
52
53 @Override
54 public String loadSource(API api, Container.Entry entry) {
55 if (isActivated(api)) {
56 String filters = api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.FILTERS);
57
58 if ((filters == null) || filters.isEmpty()) {
59 filters = MavenOrgSourceLoaderPreferencesProvider.DEFAULT_FILTERS_VALUE;
60 }
61
62 if (accepted(filters, entry.getPath())) {
63 return searchSource(entry, downloadSourceJarFile(entry.getContainer().getRoot().getParent()));
64 }
65 }
66
67 return null;
68 }
69
70 @Override
71 public File loadSourceFile(API api, Container.Entry entry) {
72 return isActivated(api) ? downloadSourceJarFile(entry) : null;
73 }
74
75 private static boolean isActivated(API api) {
76 return !"false".equals(api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.ACTIVATED));
77 }
78
79 protected String searchSource(Container.Entry entry, File sourceJarFile) {
80 if (sourceJarFile != null) {
81 byte[] buffer = new byte[1024 * 2];
82
83 try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(sourceJarFile)))) {
84 ZipEntry ze = zis.getNextEntry();
85 String name = entry.getPath();
86
87 name = name.substring(0, name.length()-6) + ".java"; // 6 = ".class".length()
88
89 while (ze != null) {
90 if (ze.getName().equals(name)) {
91 ByteArrayOutputStream out = new ByteArrayOutputStream();
92 int read = zis.read(buffer);
93
94 while (read > 0) {
95 out.write(buffer, 0, read);
96 read = zis.read(buffer);
97 }
98
99 return new String(out.toByteArray(), "UTF-8");
100 }
101
102 ze = zis.getNextEntry();
103 }
104
105 zis.closeEntry();
106 } catch (IOException e) {
107 assert ExceptionUtil.printStackTrace(e);
108 }
109 }
110
111 return null;
112 }
113
114 protected File downloadSourceJarFile(Container.Entry entry) {
115 if (cache.containsKey(entry)) {
116 return cache.get(entry);
117 }
118
119 if (!entry.isDirectory() && !failed.contains(entry)) {
120 try {
121 // SHA-1
122 MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
123 byte[] buffer = new byte[1024 * 2];
124
125 try (DigestInputStream is = new DigestInputStream(entry.getInputStream(), messageDigest)) {
126 while (is.read(buffer) > -1);
127 }
128
129 byte[] array = messageDigest.digest();
130 StringBuilder sb = new StringBuilder();
131
132 for (byte b : array) {
133 sb.append(hexa((b & 255) >> 4));
134 sb.append(hexa(b & 15));
135 }
136
137 String sha1 = sb.toString();
138
139 // Search artifact on maven.org
140 URL searchUrl = new URL(MAVENORG_SEARCH_URL_PREFIX + sha1 + MAVENORG_SEARCH_URL_SUFFIX);
141 boolean sourceAvailable = false;
142 String id = null;
143 String numFound = null;
144
145 try (InputStream is = searchUrl.openStream()) {
146 XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(is);
147 String name = "";
148
149 while (reader.hasNext()) {
150 switch (reader.next()) {
151 case XMLStreamConstants.START_ELEMENT:
152 if ("str".equals(reader.getLocalName())) {
153 if ("id".equals(reader.getAttributeValue(null, "name"))) {
154 name = "id";
155 } else {
156 name = "str";
157 }
158 } else if ("result".equals(reader.getLocalName())) {
159 numFound = reader.getAttributeValue(null, "numFound");
160 } else {
161 name = "";
162 }
163 break;
164 case XMLStreamConstants.CHARACTERS:
165 switch (name) {
166 case "id":
167 id = reader.getText().trim();
168 break;
169 case "str":
170 sourceAvailable |= "-sources.jar".equals(reader.getText().trim());
171 break;
172 }
173 break;
174 }
175 }
176
177 reader.close();
178 }
179
180 String groupId=null, artifactId=null, version=null;
181
182 if ("0".equals(numFound)) {
183 // File not indexed by Apache Solr of maven.org -> Try to found groupId, artifactId, version in 'pom.properties'
184 Properties pomProperties = getPomProperties(entry);
185
186 if (pomProperties != null) {
187 groupId = pomProperties.getProperty("groupId");
188 artifactId = pomProperties.getProperty("artifactId");
189 version = pomProperties.getProperty("version");
190 }
191 } else if ("1".equals(numFound) && sourceAvailable) {
192 int index1 = id.indexOf(':');
193 int index2 = id.lastIndexOf(':');
194
195 groupId = id.substring(0, index1);
196 artifactId = id.substring(index1+1, index2);
197 version = id.substring(index2+1);
198 }
199
200 if (artifactId != null) {
201 // Load source
202 String filePath = groupId.replace('.', '/') + '/' + artifactId + '/' + version + '/' + artifactId + '-' + version;
203 URL loadUrl = new URL(MAVENORG_LOAD_URL_PREFIX + filePath + MAVENORG_LOAD_URL_SUFFIX);
204 File tmpFile = File.createTempFile("jd-gui.tmp.", '.' + groupId + '_' + artifactId + '_' + version + "-sources.jar");
205
206 tmpFile.delete();
207 tmpFile.deleteOnExit();
208
209 try (InputStream is = new BufferedInputStream(loadUrl.openStream()); OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile))) {
210 int read = is.read(buffer);
211 while (read > 0) {
212 os.write(buffer, 0, read);
213 read = is.read(buffer);
214 }
215 }
216
217 cache.put(entry, tmpFile);
218 return tmpFile;
219 }
220 } catch (Exception e) {
221 assert ExceptionUtil.printStackTrace(e);
222 }
223 }
224
225 failed.add(entry);
226 return null;
227 }
228
229 private static Properties getPomProperties(Container.Entry parent) {
230 // Search 'META-INF/maven/*/*/pom.properties'
231 for (Container.Entry child1 : parent.getChildren()) {
232 if (child1.isDirectory() && child1.getPath().equals("META-INF")) {
233 for (Container.Entry child2 : child1.getChildren()) {
234 if (child2.isDirectory() && child2.getPath().equals("META-INF/maven")) {
235 if (child2.isDirectory()) {
236 Collection<Container.Entry> children = child2.getChildren();
237 if (children.size() == 1) {
238 Container.Entry entry = children.iterator().next();
239 if (entry.isDirectory()) {
240 children = entry.getChildren();
241 if (children.size() == 1) {
242 entry = children.iterator().next();
243 for (Container.Entry child3 : entry.getChildren()) {
244 if (!child3.isDirectory() && child3.getPath().endsWith("/pom.properties")) {
245 // Load properties
246 try (InputStream is = child3.getInputStream()) {
247 Properties properties = new Properties();
248 properties.load(is);
249 return properties;
250 } catch (Exception e) {
251 assert ExceptionUtil.printStackTrace(e);
252 }
253 }
254 }
255 }
256 }
257 }
258 }
259 }
260 }
261 }
262 }
263
264 return null;
265 }
266
267 private static char hexa(int i) { return (char)( (i <= 9) ? ('0' + i) : (('a' - 10) + i) ); }
268
269 protected boolean accepted(String filters, String path) {
270 // 'filters' example : '+org +com.google +com.ibm +com.jcraft +com.springsource +com.sun -com +java +javax +sun +sunw'
271 StringTokenizer tokenizer = new StringTokenizer(filters);
272
273 while (tokenizer.hasMoreTokens()) {
274 String filter = tokenizer.nextToken();
275
276 if (filter.length() > 1) {
277 String prefix = filter.substring(1).replace('.', '/');
278
279 if (prefix.charAt(prefix.length() - 1) != '/') {
280 prefix += '/';
281 }
282
283 if (path.startsWith(prefix)) {
284 return (filter.charAt(0) == '+');
285 }
286 }
287 }
288
289 return false;
290 }
291 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.gui.spi.SourceSaver;
10 import org.jd.gui.util.exception.ExceptionUtil;
11
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.util.Arrays;
15 import java.util.List;
16 import java.util.Properties;
17 import java.util.regex.Pattern;
18
19 public abstract class AbstractSourceSaverProvider implements SourceSaver {
20 protected List<String> externalSelectors;
21 protected Pattern externalPathPattern;
22
23 /**
24 * Initialize "selectors" and "pathPattern" with optional external properties file
25 */
26 public AbstractSourceSaverProvider() {
27 Properties properties = new Properties();
28 Class clazz = this.getClass();
29
30 try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".properties")) {
31 if (is != null) {
32 properties.load(is);
33 }
34 } catch (IOException e) {
35 assert ExceptionUtil.printStackTrace(e);
36 }
37
38 init(properties);
39 }
40
41 protected void init(Properties properties) {
42 String selectors = properties.getProperty("selectors");
43
44 if (selectors != null) {
45 externalSelectors = Arrays.asList(selectors.split(","));
46 }
47
48 String pathRegExp = properties.getProperty("pathRegExp");
49
50 if (pathRegExp != null) {
51 externalPathPattern = Pattern.compile(pathRegExp);
52 }
53 }
54
55 protected String[] appendSelectors(String selector) {
56 if (externalSelectors == null) {
57 return new String[] { selector };
58 } else {
59 int size = externalSelectors.size();
60 String[] array = new String[size+1];
61 externalSelectors.toArray(array);
62 array[size] = selector;
63 return array;
64 }
65 }
66
67 protected String[] appendSelectors(String... selectors) {
68 if (externalSelectors == null) {
69 return selectors;
70 } else {
71 int size = externalSelectors.size();
72 String[] array = new String[size+selectors.length];
73 externalSelectors.toArray(array);
74 System.arraycopy(selectors, 0, array, size, selectors.length);
75 return array;
76 }
77 }
78
79 public Pattern getPathPattern() { return externalPathPattern; }
80 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.util.decompiler.ContainerLoader;
13 import org.jd.gui.util.decompiler.LineNumberStringBuilderPrinter;
14 import org.jd.gui.util.exception.ExceptionUtil;
15 import org.jd.gui.util.io.NewlineOutputStream;
16
17 import java.io.*;
18 import java.nio.charset.Charset;
19 import java.nio.file.Files;
20 import java.nio.file.Path;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 public class ClassFileSourceSaverProvider extends AbstractSourceSaverProvider {
25 protected static final String ESCAPE_UNICODE_CHARACTERS = "ClassFileDecompilerPreferences.escapeUnicodeCharacters";
26 protected static final String REALIGN_LINE_NUMBERS = "ClassFileDecompilerPreferences.realignLineNumbers";
27 protected static final String WRITE_LINE_NUMBERS = "ClassFileSaverPreferences.writeLineNumbers";
28 protected static final String WRITE_METADATA = "ClassFileSaverPreferences.writeMetadata";
29 protected static final String JD_CORE_VERSION = "JdGuiPreferences.jdCoreVersion";
30
31 protected static final ClassFileToJavaSourceDecompiler DECOMPILER = new ClassFileToJavaSourceDecompiler();
32
33 protected ContainerLoader loader = new ContainerLoader();
34 protected LineNumberStringBuilderPrinter printer = new LineNumberStringBuilderPrinter();
35
36 @Override public String[] getSelectors() { return appendSelectors("*:file:*.class"); }
37
38 @Override
39 public String getSourcePath(Container.Entry entry) {
40 String path = entry.getPath();
41 int index = path.lastIndexOf('.');
42 String prefix = (index == -1) ? path : path.substring(0, index);
43 return prefix + ".java";
44 }
45
46 @Override
47 public int getFileCount(API api, Container.Entry entry) {
48 if (entry.getPath().indexOf('$') == -1) {
49 return 1;
50 } else {
51 return 0;
52 }
53 }
54
55 @Override
56 public void save(API api, Controller controller, Listener listener, Path rootPath, Container.Entry entry) {
57 String sourcePath = getSourcePath(entry);
58 Path path = rootPath.resolve(sourcePath);
59
60 saveContent(api, controller, listener, rootPath, path, entry);
61 }
62
63 @Override
64 public void saveContent(API api, Controller controller, Listener listener, Path rootPath, Path path, Container.Entry entry) {
65 try {
66 // Call listener
67 if (path.toString().indexOf('$') == -1) {
68 listener.pathSaved(path);
69 }
70 // Init preferences
71 Map<String, String> preferences = api.getPreferences();
72 boolean realignmentLineNumbers = getPreferenceValue(preferences, REALIGN_LINE_NUMBERS, true);
73 boolean unicodeEscape = getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false);
74 boolean showLineNumbers = getPreferenceValue(preferences, WRITE_LINE_NUMBERS, true);
75
76 Map<String, Object> configuration = new HashMap<>();
77 configuration.put("realignLineNumbers", realignmentLineNumbers);
78
79 // Init loader
80 loader.setEntry(entry);
81
82 // Init printer
83 printer.setRealignmentLineNumber(realignmentLineNumbers);
84 printer.setUnicodeEscape(unicodeEscape);
85 printer.setShowLineNumbers(showLineNumbers);
86
87 // Format internal name
88 String entryPath = entry.getPath();
89 assert entryPath.endsWith(".class");
90 String entryInternalName = entryPath.substring(0, entryPath.length() - 6); // 6 = ".class".length()
91
92 // Decompile class file
93 DECOMPILER.decompile(loader, printer, entryInternalName, configuration);
94
95 StringBuilder stringBuffer = printer.getStringBuffer();
96
97 // Metadata
98 if (getPreferenceValue(preferences, WRITE_METADATA, true)) {
99 // Add location
100 String location =
101 new File(entry.getUri()).getPath()
102 // Escape "\ u" sequence to prevent "Invalid unicode" errors
103 .replaceAll("(^|[^\\\\])\\\\u", "\\\\\\\\u");
104 stringBuffer.append("\n\n/* Location: ");
105 stringBuffer.append(location);
106 // Add Java compiler version
107 int majorVersion = printer.getMajorVersion();
108
109 if (majorVersion >= 45) {
110 stringBuffer.append("\n * Java compiler version: ");
111
112 if (majorVersion >= 49) {
113 stringBuffer.append(majorVersion - (49 - 5));
114 } else {
115 stringBuffer.append(majorVersion - (45 - 1));
116 }
117
118 stringBuffer.append(" (");
119 stringBuffer.append(majorVersion);
120 stringBuffer.append('.');
121 stringBuffer.append(printer.getMinorVersion());
122 stringBuffer.append(')');
123 }
124 // Add JD-Core version
125 stringBuffer.append("\n * JD-Core Version: ");
126 stringBuffer.append(preferences.get(JD_CORE_VERSION));
127 stringBuffer.append("\n */");
128 }
129
130 try (PrintStream ps = new PrintStream(new NewlineOutputStream(Files.newOutputStream(path)), true, "UTF-8")) {
131 ps.print(stringBuffer.toString());
132 } catch (IOException e) {
133 assert ExceptionUtil.printStackTrace(e);
134 }
135 } catch (Throwable t) {
136 assert ExceptionUtil.printStackTrace(t);
137
138 try (BufferedWriter writer = Files.newBufferedWriter(path, Charset.defaultCharset())) {
139 writer.write("// INTERNAL ERROR //");
140 } catch (IOException ee) {
141 assert ExceptionUtil.printStackTrace(ee);
142 }
143 }
144 }
145
146 protected static boolean getPreferenceValue(Map<String, String> preferences, String key, boolean defaultValue) {
147 String v = preferences.get(key);
148 return (v == null) ? defaultValue : Boolean.valueOf(v);
149 }
150 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.spi.SourceSaver;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import java.io.IOException;
15 import java.nio.file.Files;
16 import java.nio.file.Path;
17 import java.util.Collection;
18
19 public class DirectorySourceSaverProvider extends AbstractSourceSaverProvider {
20
21 @Override public String[] getSelectors() { return appendSelectors("*:dir:*"); }
22
23 @Override public String getSourcePath(Container.Entry entry) { return entry.getPath() + ".src.zip"; }
24
25 @Override public int getFileCount(API api, Container.Entry entry) { return getFileCount(api, entry.getChildren()); }
26
27 protected int getFileCount(API api, Collection<Container.Entry> entries) {
28 int count = 0;
29
30 for (Container.Entry e : entries) {
31 SourceSaver sourceSaver = api.getSourceSaver(e);
32
33 if (sourceSaver != null) {
34 count += sourceSaver.getFileCount(api, e);
35 }
36 }
37
38 return count;
39 }
40
41 @Override
42 public void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path rootPath, Container.Entry entry) {
43 Path path = rootPath.resolve(entry.getPath());
44
45 try {
46 Files.createDirectories(path);
47 saveContent(api, controller, listener, rootPath, path, entry);
48 } catch (IOException e) {
49 assert ExceptionUtil.printStackTrace(e);
50 }
51 }
52
53 @Override
54 public void saveContent(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path rootPath, Path path, Container.Entry entry) {
55 for (Container.Entry e : getChildren(entry)) {
56 if (controller.isCancelled()) {
57 break;
58 }
59
60 SourceSaver sourceSaver = api.getSourceSaver(e);
61
62 if (sourceSaver != null) {
63 sourceSaver.save(api, controller, listener, rootPath, e);
64 }
65 }
66 }
67
68 protected Collection<Container.Entry> getChildren(Container.Entry entry) { return entry.getChildren(); }
69 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.spi.SourceSaver;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import java.io.BufferedWriter;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.nio.charset.Charset;
18 import java.nio.file.Files;
19 import java.nio.file.Path;
20 import java.nio.file.StandardCopyOption;
21
22 public class FileSourceSaverProvider extends AbstractSourceSaverProvider {
23
24 @Override public String[] getSelectors() { return appendSelectors("*:file:*"); }
25
26 @Override public String getSourcePath(Container.Entry entry) { return entry.getPath(); }
27
28 @Override public int getFileCount(API api, Container.Entry entry) { return 1; }
29
30 @Override
31 public void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path rootPath, Container.Entry entry) {
32 saveContent(api, controller, listener, rootPath, rootPath.resolve(entry.getPath()), entry);
33 }
34
35 @Override
36 public void saveContent(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path rootPath, Path path, Container.Entry entry) {
37 listener.pathSaved(path);
38
39 try (InputStream is = entry.getInputStream()) {
40 Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING);
41 } catch (IOException e) {
42 assert ExceptionUtil.printStackTrace(e);
43
44 try (BufferedWriter writer = Files.newBufferedWriter(path, Charset.defaultCharset())) {
45 writer.write("// INTERNAL ERROR //");
46 } catch (IOException ee) {
47 assert ExceptionUtil.printStackTrace(ee);
48 }
49 }
50 }
51 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.util.container.JarContainerEntryUtil;
11
12 import java.util.Collection;
13
14 public class PackageSourceSaverProvider extends DirectorySourceSaverProvider {
15
16 @Override public String[] getSelectors() { return appendSelectors("jar:dir:*", "war:dir:*", "ear:dir:*"); }
17
18 @Override
19 protected Collection<Container.Entry> getChildren(Container.Entry entry) {
20 return JarContainerEntryUtil.removeInnerTypeEntries(entry.getChildren());
21 }
22 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.sourcesaver;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.spi.SourceSaver;
12 import org.jd.gui.util.exception.ExceptionUtil;
13
14 import java.io.File;
15 import java.net.URI;
16 import java.nio.file.FileSystem;
17 import java.nio.file.FileSystems;
18 import java.nio.file.Files;
19 import java.nio.file.Path;
20 import java.util.HashMap;
21
22 public class ZipFileSourceSaverProvider extends DirectorySourceSaverProvider {
23
24 @Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.jar", "*:file:*.war", "*:file:*.ear", "*:file:*.aar", "*:file:*.jmod", "*:file:*.kar"); }
25
26 @Override
27 public void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path rootPath, Container.Entry entry) {
28 try {
29 String sourcePath = getSourcePath(entry);
30 Path path = rootPath.resolve(sourcePath);
31 Path parentPath = path.getParent();
32
33 if ((parentPath != null) && !Files.exists(parentPath)) {
34 Files.createDirectories(parentPath);
35 }
36
37 File tmpSourceFile = api.loadSourceFile(entry);
38
39 if (tmpSourceFile != null) {
40 Files.copy(tmpSourceFile.toPath(), path);
41 } else {
42 File tmpFile = File.createTempFile("jd-gui.", ".tmp.zip");
43
44 tmpFile.delete();
45 tmpFile.deleteOnExit();
46
47 URI tmpFileUri = tmpFile.toURI();
48 URI tmpArchiveUri = new URI("jar:" + tmpFileUri.getScheme(), tmpFileUri.getHost(), tmpFileUri.getPath() + "!/", null);
49
50 HashMap<String, String> env = new HashMap<>();
51 env.put("create", "true");
52
53 FileSystem tmpArchiveFs = FileSystems.newFileSystem(tmpArchiveUri, env);
54 Path tmpArchiveRootPath = tmpArchiveFs.getPath("/");
55
56 saveContent(api, controller, listener, tmpArchiveRootPath, tmpArchiveRootPath, entry);
57
58 tmpArchiveFs.close();
59
60 Files.move(tmpFile.toPath(), path);
61 }
62 } catch (Exception e) {
63 assert ExceptionUtil.printStackTrace(e);
64 }
65 }
66 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.spi.TreeNodeFactory;
10 import org.jd.gui.util.exception.ExceptionUtil;
11
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.util.Arrays;
15 import java.util.List;
16 import java.util.Properties;
17 import java.util.regex.Pattern;
18
19 public abstract class AbstractTreeNodeFactoryProvider implements TreeNodeFactory {
20 protected List<String> externalSelectors;
21 protected Pattern externalPathPattern;
22
23 /**
24 * Initialize "selectors" and "pathPattern" with optional external properties file
25 */
26 public AbstractTreeNodeFactoryProvider() {
27 Properties properties = new Properties();
28 Class clazz = this.getClass();
29
30 try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".properties")) {
31 if (is != null) {
32 properties.load(is);
33 }
34 } catch (IOException e) {
35 assert ExceptionUtil.printStackTrace(e);
36 }
37
38 init(properties);
39 }
40
41 protected void init(Properties properties) {
42 String selectors = properties.getProperty("selectors");
43
44 if (selectors != null) {
45 externalSelectors = Arrays.asList(selectors.split(","));
46 }
47
48 String pathRegExp = properties.getProperty("pathRegExp");
49
50 if (pathRegExp != null) {
51 externalPathPattern = Pattern.compile(pathRegExp);
52 }
53 }
54
55 protected String[] appendSelectors(String selector) {
56 if (externalSelectors == null) {
57 return new String[] { selector };
58 } else {
59 int size = externalSelectors.size();
60 String[] array = new String[size+1];
61 externalSelectors.toArray(array);
62 array[size] = selector;
63 return array;
64 }
65 }
66
67 protected String[] appendSelectors(String... selectors) {
68 if (externalSelectors == null) {
69 return selectors;
70 } else {
71 int size = externalSelectors.size();
72 String[] array = new String[size+selectors.length];
73 externalSelectors.toArray(array);
74 System.arraycopy(selectors, 0, array, size, selectors.length);
75 return array;
76 }
77 }
78
79 @Override public Pattern getPathPattern() { return externalPathPattern; }
80 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.PageCreator;
12 import org.jd.gui.api.feature.TreeNodeExpandable;
13 import org.jd.gui.api.feature.UriGettable;
14 import org.jd.gui.api.model.Container;
15 import org.jd.gui.api.model.Type;
16 import org.jd.gui.spi.TypeFactory;
17 import org.jd.gui.util.exception.ExceptionUtil;
18 import org.jd.gui.view.data.TreeNodeBean;
19
20 import javax.swing.*;
21 import javax.swing.tree.DefaultMutableTreeNode;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Comparator;
27
28 public abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeFactoryProvider {
29 protected static final TypeComparator TYPE_COMPARATOR = new TypeComparator();
30 protected static final FieldOrMethodBeanComparator FIELD_OR_METHOD_BEAN_COMPARATOR = new FieldOrMethodBeanComparator();
31
32 public static class BaseTreeNode extends DefaultMutableTreeNode implements ContainerEntryGettable, UriGettable, PageCreator {
33 protected Container.Entry entry;
34 protected PageAndTipFactory factory;
35 protected URI uri;
36
37 public BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
38 super(userObject);
39 this.entry = entry;
40 this.factory = factory;
41
42 if (fragment != null) {
43 try {
44 URI uri = entry.getUri();
45 this.uri = new URI(uri.getScheme(), uri.getHost(), uri.getPath(), fragment);
46 } catch (URISyntaxException e) {
47 assert ExceptionUtil.printStackTrace(e);
48 }
49 } else {
50 this.uri = entry.getUri();
51 }
52 }
53
54 // --- ContainerEntryGettable --- //
55 @Override public Container.Entry getEntry() { return entry; }
56
57 // --- UriGettable --- //
58 @Override public URI getUri() { return uri; }
59
60 // --- PageCreator --- //
61 @Override
62 public <T extends JComponent & UriGettable> T createPage(API api) {
63 // Lazy 'tip' initialization
64 ((TreeNodeBean)userObject).setTip(factory.makeTip(api, entry));
65 return factory.makePage(api, entry);
66 }
67 }
68
69 protected static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable {
70 protected boolean initialized;
71
72 public FileTreeNode(Container.Entry entry, Object userObject, PageAndTipFactory pageAndTipFactory) {
73 this(entry, null, userObject, pageAndTipFactory);
74 }
75
76 public FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
77 super(entry, fragment, userObject, factory);
78 initialized = false;
79 // Add dummy node
80 add(new DefaultMutableTreeNode());
81 }
82
83 // --- TreeNodeExpandable --- //
84 @Override
85 public void populateTreeNode(API api) {
86 if (!initialized) {
87 removeAllChildren();
88 // Create type node
89 TypeFactory typeFactory = api.getTypeFactory(entry);
90
91 if (typeFactory != null) {
92 Collection<Type> types = typeFactory.make(api, entry);
93
94 for (Type type : types) {
95 add(new TypeTreeNode(entry, type, new TreeNodeBean(type.getDisplayTypeName(), type.getIcon()), factory));
96 }
97 }
98
99 initialized = true;
100 }
101 }
102 }
103
104 protected static class TypeTreeNode extends BaseTreeNode implements TreeNodeExpandable {
105 protected boolean initialized;
106 protected Type type;
107
108 public TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageAndTipFactory factory) {
109 super(entry, type.getName(), userObject, factory);
110 this.initialized = false;
111 this.type = type;
112 // Add dummy node
113 add(new DefaultMutableTreeNode());
114 }
115
116 // --- TreeNodeExpandable --- //
117 @Override
118 public void populateTreeNode(API api) {
119 if (!initialized) {
120 removeAllChildren();
121
122 String typeName = type.getName();
123
124 // Create inner types
125 Collection<Type> innerTypes = type.getInnerTypes();
126
127 if (innerTypes != null) {
128 ArrayList<Type> innerTypeList = new ArrayList<>(innerTypes);
129 innerTypeList.sort(TYPE_COMPARATOR);
130
131 for (Type innerType : innerTypeList) {
132 add(new TypeTreeNode(entry, innerType, new TreeNodeBean(innerType.getDisplayInnerTypeName(), innerType.getIcon()), factory));
133 }
134 }
135
136 // Create fields
137 Collection<Type.Field> fields = type.getFields();
138
139 if (fields != null) {
140 ArrayList<FieldOrMethodBean> beans = new ArrayList<>(fields.size());
141
142 for (Type.Field field : fields) {
143 String fragment = typeName + '-' + field.getName() + '-' + field.getDescriptor();
144 beans.add(new FieldOrMethodBean(fragment, field.getDisplayName(), field.getIcon()));
145 }
146
147 beans.sort(FIELD_OR_METHOD_BEAN_COMPARATOR);
148
149 for (FieldOrMethodBean bean : beans) {
150 add(new FieldOrMethodTreeNode(entry, bean.fragment, new TreeNodeBean(bean.label, bean.icon), factory));
151 }
152 }
153
154 // Create methods
155 Collection<Type.Method> methods = type.getMethods();
156
157 if (methods != null) {
158 ArrayList<FieldOrMethodBean> beans = new ArrayList<>();
159
160 for (Type.Method method : methods) {
161 if (!method.getName().equals("<clinit>")) {
162 String fragment = typeName + '-' + method.getName() + '-' + method.getDescriptor();
163 beans.add(new FieldOrMethodBean(fragment, method.getDisplayName(), method.getIcon()));
164 }
165 }
166
167 beans.sort(FIELD_OR_METHOD_BEAN_COMPARATOR);
168
169 for (FieldOrMethodBean bean : beans) {
170 add(new FieldOrMethodTreeNode(entry, bean.fragment, new TreeNodeBean(bean.label, bean.icon), factory));
171 }
172 }
173
174 initialized = true;
175 }
176 }
177 }
178
179 protected static class FieldOrMethodTreeNode extends BaseTreeNode {
180 public FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
181 super(entry, fragment, userObject, factory);
182 }
183 }
184
185 protected static class FieldOrMethodBean {
186 public String fragment, label;
187 public Icon icon;
188
189 public FieldOrMethodBean(String fragment, String label, Icon icon) {
190 this.fragment = fragment;
191 this.label = label;
192 this.icon = icon;
193 }
194 }
195
196 protected interface PageAndTipFactory {
197 <T extends JComponent & UriGettable> T makePage(API api, Container.Entry entry);
198 String makeTip(API api, Container.Entry entry);
199 }
200
201 protected static class TypeComparator implements Comparator<Type> {
202 @Override
203 public int compare(Type type1, Type type2) {
204 return type1.getName().compareTo(type2.getName());
205 }
206 }
207
208 protected static class FieldOrMethodBeanComparator implements Comparator<FieldOrMethodBean> {
209 @Override
210 public int compare(FieldOrMethodBean bean1, FieldOrMethodBean bean2) {
211 return bean1.label.compareTo(bean2.label);
212 }
213 }
214 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.util.exception.ExceptionUtil;
14 import org.jd.gui.view.component.DynamicPage;
15 import org.jd.gui.view.data.TreeNodeBean;
16
17 import javax.swing.*;
18 import javax.swing.tree.DefaultMutableTreeNode;
19 import java.io.EOFException;
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.regex.Pattern;
24
25 public class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
26 protected static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/classf_obj.png"));
27 protected static final Factory FACTORY = new Factory();
28
29 static {
30 // Early class loading
31 try {
32 Class.forName(DynamicPage.class.getName());
33 } catch (Exception e) {
34 assert ExceptionUtil.printStackTrace(e);
35 }
36 }
37
38 @Override public String[] getSelectors() { return appendSelectors("*:file:*.class"); }
39
40 @Override
41 public Pattern getPathPattern() {
42 if (externalPathPattern == null) {
43 return Pattern.compile("^((?!module-info\\.class).)*$");
44 } else {
45 return externalPathPattern;
46 }
47 }
48
49 @Override
50 @SuppressWarnings("unchecked")
51 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
52 int lastSlashIndex = entry.getPath().lastIndexOf('/');
53 String label = entry.getPath().substring(lastSlashIndex+1);
54 return (T)new FileTreeNode(entry, new TreeNodeBean(label, CLASS_FILE_ICON), FACTORY);
55 }
56
57 protected static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
58 @Override
59 @SuppressWarnings("unchecked")
60 public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
61 return (T)new DynamicPage(a, e);
62 }
63
64 @Override
65 public String makeTip(API api, Container.Entry entry) {
66 String location = new File(entry.getUri()).getPath();
67 StringBuilder tip = new StringBuilder("<html>Location: ");
68
69 tip.append(location);
70 tip.append("<br>Java compiler version: ");
71
72 try (InputStream is = entry.getInputStream()) {
73 is.skip(4); // Skip magic number
74 int minorVersion = readUnsignedShort(is);
75 int majorVersion = readUnsignedShort(is);
76
77 if (majorVersion >= 49) {
78 tip.append(majorVersion - (49-5));
79 } else if (majorVersion >= 45) {
80 tip.append("1.");
81 tip.append(majorVersion - (45-1));
82 }
83 tip.append(" (");
84 tip.append(majorVersion);
85 tip.append('.');
86 tip.append(minorVersion);
87 tip.append(')');
88 } catch (IOException e) {
89 assert ExceptionUtil.printStackTrace(e);
90 }
91
92 tip.append("</html>");
93
94 return tip.toString();
95 }
96
97 /**
98 * @see java.io.DataInputStream#readUnsignedShort()
99 */
100 protected int readUnsignedShort(InputStream is) throws IOException {
101 int ch1 = is.read();
102 int ch2 = is.read();
103 if ((ch1 | ch2) < 0)
104 throw new EOFException();
105 return (ch1 << 8) + (ch2 << 0);
106 }
107 }
108 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import javax.swing.*;
10
11 public class ClassesDirectoryTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
12 protected static final ImageIcon ICON = new ImageIcon(ClassesDirectoryTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/packagefolder_obj.png"));
13
14 @Override public String[] getSelectors() {
15 return appendSelectors(
16 "jar:dir:META-INF/versions",
17 "jar:dir:META-INF/versions/5",
18 "jar:dir:META-INF/versions/6",
19 "jar:dir:META-INF/versions/7",
20 "jar:dir:META-INF/versions/8",
21 "jar:dir:META-INF/versions/9",
22 "jar:dir:META-INF/versions/10",
23 "jar:dir:META-INF/versions/11",
24 "jar:dir:META-INF/versions/12",
25 "jar:dir:META-INF/versions/13",
26 "jar:dir:META-INF/versions/14",
27 "war:dir:WEB-INF/classes",
28 "jmod:dir:classes");
29 }
30
31 @Override public ImageIcon getIcon() { return ICON; }
32 @Override public ImageIcon getOpenIcon() { return null; }
33 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class CssFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(HtmlFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/css_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.css"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() {
43 return SyntaxConstants.SYNTAX_STYLE_CSS;
44 }
45 };
46 }
47 }
48 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.TreeNodeExpandable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.api.model.Container.Entry;
15 import org.jd.gui.spi.TreeNodeFactory;
16 import org.jd.gui.view.data.TreeNodeBean;
17
18 import javax.swing.*;
19 import javax.swing.tree.DefaultMutableTreeNode;
20 import java.io.File;
21 import java.net.URI;
22 import java.util.Collection;
23
24 public class DirectoryTreeNodeFactoryProvider extends AbstractTreeNodeFactoryProvider {
25 protected static final ImageIcon ICON = new ImageIcon(DirectoryTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/folder.gif"));
26 protected static final ImageIcon OPEN_ICON = new ImageIcon(DirectoryTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/folder_open.png"));
27
28 @Override public String[] getSelectors() { return appendSelectors("*:dir:*"); }
29
30 @Override
31 @SuppressWarnings("unchecked")
32 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
33 int lastSlashIndex = entry.getPath().lastIndexOf('/');
34 Collection<Entry> entries = entry.getChildren();
35
36 // Aggregate directory names
37 while (entries.size() == 1) {
38 Entry child = entries.iterator().next();
39 if (!child.isDirectory() || api.getTreeNodeFactory(child) != this || entry.getContainer() != child.getContainer()) break;
40 entry = child;
41 entries = entry.getChildren();
42 }
43
44 String label = entry.getPath().substring(lastSlashIndex+1);
45 String location = new File(entry.getUri()).getPath();
46 TreeNode node = new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, getIcon(), getOpenIcon()));
47
48 if (entries.size() > 0) {
49 // Add dummy node
50 node.add(new DefaultMutableTreeNode());
51 }
52
53 return (T)node;
54 }
55
56 public ImageIcon getIcon() { return ICON; }
57 public ImageIcon getOpenIcon() { return OPEN_ICON; }
58
59 protected static class TreeNode extends DefaultMutableTreeNode implements ContainerEntryGettable, UriGettable, TreeNodeExpandable {
60 Container.Entry entry;
61 boolean initialized;
62
63 public TreeNode(Container.Entry entry, Object userObject) {
64 super(userObject);
65 this.entry = entry;
66 this.initialized = false;
67 }
68
69 // --- ContainerEntryGettable --- //
70 @Override public Container.Entry getEntry() { return entry; }
71
72 // --- UriGettable --- //
73 @Override public URI getUri() { return entry.getUri(); }
74
75 // --- TreeNodeExpandable --- //
76 @Override
77 public void populateTreeNode(API api) {
78 if (!initialized) {
79 removeAllChildren();
80
81 Collection<Container.Entry> entries = getChildren();
82
83 while (entries.size() == 1) {
84 Entry child = entries.iterator().next();
85 if (!child.isDirectory() || api.getTreeNodeFactory(child) != this) {
86 break;
87 }
88 entries = child.getChildren();
89 }
90
91 for (Entry entry : entries) {
92 TreeNodeFactory factory = api.getTreeNodeFactory(entry);
93 if (factory != null) {
94 add(factory.make(api, entry));
95 }
96 }
97
98 initialized = true;
99 }
100 }
101
102 public Collection<Container.Entry> getChildren() { return entry.getChildren(); }
103 }
104 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class DtdFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(DtdFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/dtd_obj.gif"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.dtd"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_DTD; }
43 };
44 }
45 }
46 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.data.TreeNodeBean;
14
15 import javax.swing.*;
16 import javax.swing.tree.DefaultMutableTreeNode;
17 import java.io.File;
18
19 public class EarFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider {
20 protected static final ImageIcon ICON = new ImageIcon(JarFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/ear_obj.gif"));
21
22 @Override public String[] getSelectors() { return appendSelectors("*:file:*.ear"); }
23
24 @Override
25 @SuppressWarnings("unchecked")
26 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
27 int lastSlashIndex = entry.getPath().lastIndexOf("/");
28 String label = entry.getPath().substring(lastSlashIndex+1);
29 String location = new File(entry.getUri()).getPath();
30 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
31 // Add dummy node
32 node.add(new DefaultMutableTreeNode());
33 return node;
34 }
35 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.PageCreator;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.component.EjbJarXmlFilePage;
15 import org.jd.gui.view.data.TreeNodeBean;
16
17 import javax.swing.*;
18 import javax.swing.tree.DefaultMutableTreeNode;
19 import java.io.File;
20
21 public class EjbJarXmlFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider {
22 protected static final ImageIcon ICON = new ImageIcon(ManifestFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/xml_obj.gif"));
23
24 @Override public String[] getSelectors() { return appendSelectors("jar:file:META-INF/ejb-jar.xml"); }
25
26 @Override
27 @SuppressWarnings("unchecked")
28 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
29 String location = new File(entry.getUri()).getPath();
30 return (T)new TreeNode(entry, new TreeNodeBean("ejb-jar.xml", "Location: " + location, ICON));
31 }
32
33 protected static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator {
34 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
35
36 // --- PageCreator --- //
37 @Override
38 @SuppressWarnings("unchecked")
39 public <T extends JComponent & UriGettable> T createPage(API api) {
40 return (T)new EjbJarXmlFilePage(api, entry);
41 }
42 }
43 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.data.TreeNodeBean;
14
15 import javax.swing.*;
16 import javax.swing.tree.DefaultMutableTreeNode;
17 import java.io.File;
18 import java.net.URI;
19
20 public class FileTreeNodeFactoryProvider extends AbstractTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(FileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/file_plain_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf('/');
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends DefaultMutableTreeNode implements ContainerEntryGettable, UriGettable {
35 protected Container.Entry entry;
36
37 public TreeNode(Container.Entry entry, Object userObject) {
38 super(userObject);
39 this.entry = entry;
40 }
41
42 // --- ContainerEntryGettable --- //
43 @Override public Container.Entry getEntry() { return entry; }
44
45 // --- UriGettable --- //
46 @Override public URI getUri() { return entry.getUri(); }
47 }
48 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class HtmlFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(HtmlFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/html_obj.gif"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.html", "*:file:*.xhtml"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_HTML; }
43 };
44 }
45 }
46 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.*;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.util.exception.ExceptionUtil;
13 import org.jd.gui.view.data.TreeNodeBean;
14
15 import javax.imageio.ImageIO;
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.awt.*;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URI;
23
24 public class ImageFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider {
25 protected static final ImageIcon ICON = new ImageIcon(ImageFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/file-image.gif"));
26
27 @Override public String[] getSelectors() { return appendSelectors("*:file:*.gif", "*:file:*.jpg", "*:file:*.png"); }
28
29 @Override
30 @SuppressWarnings("unchecked")
31 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
32 int lastSlashIndex = entry.getPath().lastIndexOf("/");
33 String label = entry.getPath().substring(lastSlashIndex+1);
34 String location = new File(entry.getUri()).getPath();
35 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
36 }
37
38 protected static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator {
39 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
40
41 // --- PageCreator --- //
42 @Override
43 @SuppressWarnings("unchecked")
44 public <T extends JComponent & UriGettable> T createPage(API api) {
45 return (T)new ImagePage(entry);
46 }
47 }
48
49 protected static class ImagePage extends JPanel implements UriGettable {
50 protected Container.Entry entry;
51
52 public ImagePage(Container.Entry entry) {
53 super(new BorderLayout());
54
55 this.entry = entry;
56
57 try (InputStream is = entry.getInputStream()) {
58 JScrollPane scrollPane = new JScrollPane(new JLabel(new ImageIcon(ImageIO.read(is))));
59
60 scrollPane.getHorizontalScrollBar().setUnitIncrement(16);
61 scrollPane.getVerticalScrollBar().setUnitIncrement(16);
62
63 add(scrollPane, BorderLayout.CENTER);
64 } catch (IOException e) {
65 assert ExceptionUtil.printStackTrace(e);
66 }
67 }
68
69 // --- UriGettable --- //
70 @Override public URI getUri() { return entry.getUri(); }
71 }
72 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.util.container.JarContainerEntryUtil;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19 import java.util.Collection;
20
21 public class JarFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider {
22 protected static final ImageIcon JAR_FILE_ICON = new ImageIcon(JarFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/jar_obj.png"));
23 protected static final ImageIcon EJB_FILE_ICON = new ImageIcon(JarFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/ejbmodule_obj.gif"));
24
25 @Override public String[] getSelectors() { return appendSelectors("*:file:*.jar"); }
26
27 @Override
28 @SuppressWarnings("unchecked")
29 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
30 int lastSlashIndex = entry.getPath().lastIndexOf("/");
31 String label = entry.getPath().substring(lastSlashIndex+1);
32 String location = new File(entry.getUri()).getPath();
33 ImageIcon icon = isAEjbModule(entry) ? EJB_FILE_ICON : JAR_FILE_ICON;
34 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, icon));
35 // Add dummy node
36 node.add(new DefaultMutableTreeNode());
37 return node;
38 }
39
40 protected static boolean isAEjbModule(Container.Entry entry) {
41 Collection<Container.Entry> children = entry.getChildren();
42
43 if (children != null) {
44 Container.Entry metaInf = null;
45
46 for (Container.Entry child : children) {
47 if (child.getPath().equals("META-INF")) {
48 metaInf = child;
49 break;
50 }
51 }
52
53 if (metaInf != null) {
54 children = metaInf.getChildren();
55
56 for (Container.Entry child : children) {
57 if (child.getPath().equals("META-INF/ejb-jar.xml")) {
58 return true;
59 }
60 }
61 }
62 }
63
64 return false;
65 }
66
67 protected static class TreeNode extends ZipFileTreeNodeFactoryProvider.TreeNode {
68 public TreeNode(Container.Entry entry, Object userObject) {
69 super(entry, userObject);
70 }
71
72 @Override
73 public Collection<Container.Entry> getChildren() {
74 return JarContainerEntryUtil.removeInnerTypeEntries(entry.getChildren());
75 }
76 }
77 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.component.JavaFilePage;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class JavaFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
21 protected static final ImageIcon JAVA_FILE_ICON = new ImageIcon(JavaFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/jcu_obj.png"));
22 protected static final Factory FACTORY = new Factory();
23
24 @Override public String[] getSelectors() { return appendSelectors("*:file:*.java"); }
25
26 @Override
27 @SuppressWarnings("unchecked")
28 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
29 int lastSlashIndex = entry.getPath().lastIndexOf('/');
30 String label = entry.getPath().substring(lastSlashIndex+1);
31 String location = new File(entry.getUri()).getPath();
32 return (T)new FileTreeNode(entry, new TreeNodeBean(label, "Location: " + location, JAVA_FILE_ICON), FACTORY);
33 }
34
35 protected static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
36 // --- PageAndTipFactory --- //
37 @Override
38 @SuppressWarnings("unchecked")
39 public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
40 return (T)new JavaFilePage(a, e);
41 }
42
43 @Override
44 public String makeTip(API api, Container.Entry entry) {
45 String location = new File(entry.getUri()).getPath();
46 StringBuilder tip = new StringBuilder("<html>Location: ");
47
48 tip.append(location);
49 tip.append("</html>");
50
51 return tip.toString();
52 }
53 }
54 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.data.TreeNodeBean;
14
15 import javax.swing.tree.DefaultMutableTreeNode;
16 import java.io.File;
17
18 public class JavaModuleFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider {
19 @Override public String[] getSelectors() { return appendSelectors("*:file:*.jmod"); }
20
21 @Override
22 @SuppressWarnings("unchecked")
23 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
24 int lastSlashIndex = entry.getPath().lastIndexOf("/");
25 String label = entry.getPath().substring(lastSlashIndex+1);
26 String location = new File(entry.getUri()).getPath();
27 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
28 // Add dummy node
29 node.add(new DefaultMutableTreeNode());
30 return node;
31 }
32 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import java.util.regex.Pattern;
10
11 public class JavaModulePackageTreeNodeFactoryProvider extends PackageTreeNodeFactoryProvider {
12
13 @Override public String[] getSelectors() { return appendSelectors("jmod:dir:*"); }
14
15 @Override
16 public Pattern getPathPattern() {
17 if (externalPathPattern == null) {
18 return Pattern.compile("classes\\/(?!META-INF)..*");
19 } else {
20 return externalPathPattern;
21 }
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class JavascriptFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(JavascriptFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/js_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.js"); }
24
25 @SuppressWarnings("unchecked")
26 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
27 int lastSlashIndex = entry.getPath().lastIndexOf("/");
28 String label = entry.getPath().substring(lastSlashIndex+1);
29 String location = new File(entry.getUri()).getPath();
30 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
31 }
32
33 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
34 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
35
36 // --- PageCreator --- //
37 @Override
38 @SuppressWarnings("unchecked")
39 public <T extends JComponent & UriGettable> T createPage(API api) {
40 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
41 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT; }
42 };
43 }
44 }
45 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class JsonFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(JsonFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/ascii_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.json"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JSON; }
43 };
44 }
45 }
46 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class JspFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(HtmlFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/html_obj.gif"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.jsp", "*:file:*.jspf"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JSP; }
43 };
44 }
45 }
46 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.data.TreeNodeBean;
14
15 import javax.swing.tree.DefaultMutableTreeNode;
16 import java.io.File;
17
18 public class KarFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider {
19 @Override public String[] getSelectors() { return appendSelectors("*:file:*.kar"); }
20
21 @Override
22 @SuppressWarnings("unchecked")
23 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
24 int lastSlashIndex = entry.getPath().lastIndexOf("/");
25 String label = entry.getPath().substring(lastSlashIndex+1);
26 String location = new File(entry.getUri()).getPath();
27 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
28 // Add dummy node
29 node.add(new DefaultMutableTreeNode());
30 return node;
31 }
32 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.PageCreator;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.component.ManifestFilePage;
15 import org.jd.gui.view.data.TreeNodeBean;
16
17 import javax.swing.*;
18 import javax.swing.tree.DefaultMutableTreeNode;
19 import java.io.File;
20
21 public class ManifestFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider {
22 protected static final ImageIcon ICON = new ImageIcon(ManifestFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/manifest_obj.png"));
23
24 @Override public String[] getSelectors() { return appendSelectors("*:file:META-INF/MANIFEST.MF"); }
25
26 @Override
27 @SuppressWarnings("unchecked")
28 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
29 String location = new File(entry.getUri()).getPath();
30 return (T)new TreeNode(entry, new TreeNodeBean("MANIFEST.MF", "Location: " + location, ICON));
31 }
32
33 protected static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator {
34 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
35
36 // --- PageCreator --- //
37 @Override
38 @SuppressWarnings("unchecked")
39 public <T extends JComponent & UriGettable> T createPage(API api) {
40 return (T)new ManifestFilePage(api, entry);
41 }
42 }
43 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import javax.swing.*;
10 import java.util.regex.Pattern;
11
12 public class MetainfDirectoryTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
13 protected static final ImageIcon ICON = new ImageIcon(MetainfDirectoryTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/inf_obj.png"));
14
15 @Override public String[] getSelectors() {
16 return appendSelectors(
17 "jar:dir:META-INF",
18 "war:dir:WEB-INF",
19 "war:dir:WEB-INF/classes/META-INF",
20 "ear:dir:META-INF",
21 "jmod:dir:classes/META-INF");
22 }
23
24 @Override public ImageIcon getIcon() { return ICON; }
25 @Override public ImageIcon getOpenIcon() { return null; }
26 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.PageCreator;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.component.OneTypeReferencePerLinePage;
15 import org.jd.gui.view.data.TreeNodeBean;
16
17 import javax.swing.*;
18 import javax.swing.tree.DefaultMutableTreeNode;
19 import java.io.File;
20 import java.util.regex.Pattern;
21
22 public class MetainfServiceFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider {
23 protected static final ImageIcon ICON = new ImageIcon(TextFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/ascii_obj.png"));
24
25 @Override public String[] getSelectors() { return appendSelectors("*:file:*"); }
26
27 @Override
28 public Pattern getPathPattern() {
29 if (externalPathPattern == null) {
30 return Pattern.compile("META-INF\\/services\\/[^\\/]+");
31 } else {
32 return externalPathPattern;
33 }
34 }
35
36 @SuppressWarnings("unchecked")
37 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
38 int lastSlashIndex = entry.getPath().lastIndexOf("/");
39 String label = entry.getPath().substring(lastSlashIndex+1);
40 String location = new File(entry.getUri()).getPath();
41 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
42 }
43
44 protected static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator {
45 public TreeNode(Container.Entry entry, Object userObject) {
46 super(entry, userObject);
47 }
48
49 // --- PageCreator --- //
50 @Override
51 @SuppressWarnings("unchecked")
52 public <T extends JComponent & UriGettable> T createPage(API api) {
53 return (T)new OneTypeReferencePerLinePage(api, entry);
54 }
55 }
56 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.api.model.Type;
14 import org.jd.gui.spi.TypeFactory;
15 import org.jd.gui.util.exception.ExceptionUtil;
16 import org.jd.gui.view.component.ModuleInfoFilePage;
17 import org.jd.gui.view.data.TreeNodeBean;
18
19 import javax.swing.*;
20 import javax.swing.tree.DefaultMutableTreeNode;
21 import java.io.File;
22 import java.util.Collection;
23 import java.util.regex.Pattern;
24
25 public class ModuleInfoFileTreeNodeFactoryProvider extends ClassFileTreeNodeFactoryProvider {
26 protected static final ImageIcon MODULE_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/module_obj.png"));
27 protected static final Factory FACTORY = new Factory();
28
29 static {
30 // Early class loading
31 try {
32 Class.forName(ModuleInfoFilePage.class.getName());
33 } catch (Exception e) {
34 assert ExceptionUtil.printStackTrace(e);
35 }
36 }
37
38 @Override public String[] getSelectors() { return appendSelectors("*:file:*/module-info.class"); }
39
40 @Override public Pattern getPathPattern() { return externalPathPattern; }
41
42 @Override
43 @SuppressWarnings("unchecked")
44 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
45 int lastSlashIndex = entry.getPath().lastIndexOf('/');
46 String label = entry.getPath().substring(lastSlashIndex+1);
47 return (T)new ModuleInfoFileTreeNode(entry, new TreeNodeBean(label, CLASS_FILE_ICON), FACTORY);
48 }
49
50 protected static class ModuleInfoFileTreeNode extends FileTreeNode {
51 public ModuleInfoFileTreeNode(Container.Entry entry, Object userObject, PageAndTipFactory pageAndTipFactory) {
52 super(entry, null, userObject, pageAndTipFactory);
53 }
54
55 // --- TreeNodeExpandable --- //
56 @Override
57 public void populateTreeNode(API api) {
58 if (!initialized) {
59 removeAllChildren();
60 // Create type node
61 TypeFactory typeFactory = api.getTypeFactory(entry);
62
63 if (typeFactory != null) {
64 Collection<Type> types = typeFactory.make(api, entry);
65
66 for (Type type : types) {
67 add(new BaseTreeNode(entry, type.getName(), new TreeNodeBean(type.getDisplayTypeName(), MODULE_FILE_ICON), factory));
68 }
69 }
70
71 initialized = true;
72 }
73 }
74 }
75
76 protected static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
77 // --- PageAndTipFactory --- //
78 @Override
79 @SuppressWarnings("unchecked")
80 public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
81 return (T)new ModuleInfoFilePage(a, e);
82 }
83
84 @Override
85 public String makeTip(API api, Container.Entry entry) {
86 String location = new File(entry.getUri()).getPath();
87 StringBuilder tip = new StringBuilder("<html>Location: ");
88
89 tip.append(location);
90 tip.append("</html>");
91
92 return tip.toString();
93 }
94 }
95 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.util.container.JarContainerEntryUtil;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19 import java.util.Collection;
20 import java.util.regex.Pattern;
21
22 public class PackageTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
23 protected static final ImageIcon ICON = new ImageIcon(PackageTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/package_obj.png"));
24
25 @Override public String[] getSelectors() { return appendSelectors("jar:dir:*"); }
26
27 @Override
28 public Pattern getPathPattern() {
29 if (externalPathPattern == null) {
30 return Pattern.compile("(META-INF\\/versions\\/.*)|(?!META-INF)..*");
31 } else {
32 return externalPathPattern;
33 }
34 }
35
36 @Override
37 @SuppressWarnings("unchecked")
38 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
39 int lastSlashIndex = entry.getPath().lastIndexOf("/");
40 Collection<Container.Entry> entries = entry.getChildren();
41
42 // Aggregate directory names
43 while (entries.size() == 1) {
44 Container.Entry child = entries.iterator().next();
45 if (!child.isDirectory() || (api.getTreeNodeFactory(child) != this) || (entry.getContainer() != child.getContainer())) break;
46 entry = child;
47 entries = entry.getChildren();
48 }
49
50 String label = entry.getPath().substring(lastSlashIndex+1).replace("/", ".");
51 String location = new File(entry.getUri()).getPath();
52 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, getIcon(), getOpenIcon()));
53
54 if (entries.size() > 0) {
55 // Add dummy node
56 node.add(new DefaultMutableTreeNode());
57 }
58
59 return node;
60 }
61
62 @Override public ImageIcon getIcon() { return ICON; }
63 @Override public ImageIcon getOpenIcon() { return null; }
64
65 protected static class TreeNode extends DirectoryTreeNodeFactoryProvider.TreeNode {
66 public TreeNode(Container.Entry entry, Object userObject) {
67 super(entry, userObject);
68 }
69
70 @Override
71 public Collection<Container.Entry> getChildren() {
72 return JarContainerEntryUtil.removeInnerTypeEntries(entry.getChildren());
73 }
74 }
75 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class PropertiesFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(PropertiesFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/ascii_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.properties"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() {
43 return SyntaxConstants.SYNTAX_STYLE_PROPERTIES_FILE;
44 }
45 };
46 }
47 }
48 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import java.util.regex.Pattern;
10
11 public class SpiFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
12 @Override public String[] getSelectors() {
13 return appendSelectors("*:file:*");
14 }
15
16 @Override
17 public Pattern getPathPattern() {
18 if (externalPathPattern == null) {
19 return Pattern.compile("(.*\\/)?META-INF\\/services\\/.*");
20 } else {
21 return externalPathPattern;
22 }
23 }
24 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class SqlFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(SqlFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/sql_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.sql"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_SQL; }
43 };
44 }
45 }
46 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
10 import org.fife.ui.rsyntaxtextarea.Theme;
11 import org.fife.ui.rtextarea.Gutter;
12 import org.jd.gui.api.API;
13 import org.jd.gui.api.feature.ContainerEntryGettable;
14 import org.jd.gui.api.feature.PageCreator;
15 import org.jd.gui.api.feature.UriGettable;
16 import org.jd.gui.api.model.Container;
17 import org.jd.gui.util.exception.ExceptionUtil;
18 import org.jd.gui.util.io.TextReader;
19 import org.jd.gui.view.component.TextPage;
20 import org.jd.gui.view.data.TreeNodeBean;
21
22 import javax.swing.*;
23 import javax.swing.tree.DefaultMutableTreeNode;
24 import java.io.File;
25 import java.io.IOException;
26 import java.net.URI;
27
28 public class TextFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider {
29 protected static final ImageIcon ICON = new ImageIcon(TextFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/ascii_obj.png"));
30
31 static {
32 // Early class loading
33 new Gutter(new RSyntaxTextArea());
34 try {
35 Theme.load(TextFileTreeNodeFactoryProvider.class.getClassLoader().getResourceAsStream("rsyntaxtextarea/themes/eclipse.xml"));
36 } catch (IOException e) {
37 assert ExceptionUtil.printStackTrace(e);
38 }
39 }
40
41 @Override public String[] getSelectors() {
42 return appendSelectors("*:file:*.txt", "*:file:*.md", "*:file:*.SF", "*:file:*.policy", "*:file:*.yaml", "*:file:*.yml", "*:file:*/COPYRIGHT", "*:file:*/LICENSE");
43 }
44
45 @Override
46 @SuppressWarnings("unchecked")
47 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
48 int lastSlashIndex = entry.getPath().lastIndexOf("/");
49 String label = entry.getPath().substring(lastSlashIndex+1);
50 String location = new File(entry.getUri()).getPath();
51 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
52 }
53
54 protected static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator {
55 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
56
57 // --- PageCreator --- //
58 @Override
59 @SuppressWarnings("unchecked")
60 public <T extends JComponent & UriGettable> T createPage(API api) {
61 return (T)new Page(entry);
62 }
63 }
64
65 protected static class Page extends TextPage implements UriGettable {
66 protected Container.Entry entry;
67
68 public Page(Container.Entry entry) {
69 this.entry = entry;
70 setText(TextReader.getText(entry.getInputStream()));
71 }
72
73 // --- UriGettable --- //
74 @Override public URI getUri() { return entry.getUri(); }
75
76 // --- ContentSavable --- //
77 public String getFileName() {
78 String path = entry.getPath();
79 int index = path.lastIndexOf("/");
80 return path.substring(index+1);
81 }
82 }
83 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.data.TreeNodeBean;
14
15 import javax.swing.*;
16 import javax.swing.tree.DefaultMutableTreeNode;
17 import java.io.File;
18
19 public class WarFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider {
20 protected static final ImageIcon ICON = new ImageIcon(JarFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/war_obj.gif"));
21
22 @Override public String[] getSelectors() { return appendSelectors("*:file:*.war"); }
23
24 @Override
25 @SuppressWarnings("unchecked")
26 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
27 int lastSlashIndex = entry.getPath().lastIndexOf("/");
28 String label = entry.getPath().substring(lastSlashIndex+1);
29 String location = new File(entry.getUri()).getPath();
30 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
31 // Add dummy node
32 node.add(new DefaultMutableTreeNode());
33 return node;
34 }
35 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import java.util.regex.Pattern;
10
11 public class WarPackageTreeNodeFactoryProvider extends PackageTreeNodeFactoryProvider {
12
13 @Override public String[] getSelectors() { return appendSelectors("war:dir:*"); }
14
15 @Override
16 public Pattern getPathPattern() {
17 if (externalPathPattern == null) {
18 return Pattern.compile("WEB-INF\\/classes\\/(?!META-INF)..*");
19 } else {
20 return externalPathPattern;
21 }
22 }
23 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.PageCreator;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.component.WebXmlFilePage;
15 import org.jd.gui.view.data.TreeNodeBean;
16
17 import javax.swing.*;
18 import javax.swing.tree.DefaultMutableTreeNode;
19 import java.io.File;
20
21 public class WebXmlFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider {
22 protected static final ImageIcon ICON = new ImageIcon(ManifestFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/xml_obj.gif"));
23
24 @Override public String[] getSelectors() { return appendSelectors("war:file:WEB-INF/web.xml"); }
25
26 @Override
27 @SuppressWarnings("unchecked")
28 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
29 String location = new File(entry.getUri()).getPath();
30 return (T)new TreeNode(entry, new TreeNodeBean("web.xml", "Location: " + location, ICON));
31 }
32
33 protected static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator {
34 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
35
36 // --- PageCreator --- //
37 @Override
38 @SuppressWarnings("unchecked")
39 public <T extends JComponent & UriGettable> T createPage(API api) {
40 return (T)new WebXmlFilePage(api, entry);
41 }
42 }
43 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import javax.swing.*;
10
11 public class WebinfLibDirectoryTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
12 protected static final ImageIcon ICON = new ImageIcon(WebinfLibDirectoryTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/archivefolder_obj.png"));
13
14 @Override public String[] getSelectors() { return appendSelectors("war:dir:WEB-INF/lib"); }
15 @Override public ImageIcon getIcon() { return ICON; }
16 @Override public ImageIcon getOpenIcon() { return null; }
17 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.ContainerEntryGettable;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class XmlBasedFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(XmlBasedFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/xml_obj.gif"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.xsl", "*:file:*.xslt", "*:file:*.xsd", "*:file:*.tld", "*:file:*.wsdl"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new TextFileTreeNodeFactoryProvider.Page(entry) {
42 @Override public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_XML; }
43 };
44 }
45 }
46 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.view.component.XmlFilePage;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class XmlFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(XmlFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/xml_obj.gif"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.xml"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 return (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 }
33
34 protected static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode {
35 public TreeNode(Container.Entry entry, Object userObject) { super(entry, userObject); }
36
37 // --- PageCreator --- //
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends JComponent & UriGettable> T createPage(API api) {
41 return (T)new XmlFilePage(api, entry);
42 }
43 }
44 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.spi.TreeNodeFactory;
14 import org.jd.gui.view.data.TreeNodeBean;
15
16 import javax.swing.*;
17 import javax.swing.tree.DefaultMutableTreeNode;
18 import java.io.File;
19
20 public class ZipFileTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider {
21 protected static final ImageIcon ICON = new ImageIcon(ZipFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/zip_obj.png"));
22
23 @Override public String[] getSelectors() { return appendSelectors("*:file:*.zip", "*:file:*.aar"); }
24
25 @Override
26 @SuppressWarnings("unchecked")
27 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
28 int lastSlashIndex = entry.getPath().lastIndexOf("/");
29 String label = entry.getPath().substring(lastSlashIndex+1);
30 String location = new File(entry.getUri()).getPath();
31 T node = (T)new TreeNode(entry, new TreeNodeBean(label, "Location: " + location, ICON));
32 // Add dummy node
33 node.add(new DefaultMutableTreeNode());
34 return node;
35 }
36
37 protected static class TreeNode extends DirectoryTreeNodeFactoryProvider.TreeNode {
38 public TreeNode(Container.Entry entry, Object userObject) {
39 super(entry, userObject);
40 }
41
42 // --- TreeNodeExpandable --- //
43 public void populateTreeNode(API api) {
44 if (!initialized) {
45 removeAllChildren();
46
47 for (Container.Entry e : getChildren()) {
48 TreeNodeFactory factory = api.getTreeNodeFactory(e);
49 if (factory != null) {
50 add(factory.make(api, e));
51 }
52 }
53
54 initialized = true;
55 }
56 }
57 }
58 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.type;
8
9 import org.jd.gui.api.model.Type;
10 import org.jd.gui.spi.TypeFactory;
11 import org.jd.gui.util.exception.ExceptionUtil;
12
13 import javax.swing.*;
14 import java.awt.*;
15 import java.awt.image.BufferedImage;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.*;
19 import java.util.List;
20 import java.util.regex.Pattern;
21
22 public abstract class AbstractTypeFactoryProvider implements TypeFactory {
23 protected List<String> externalSelectors;
24 protected Pattern externalPathPattern;
25
26 /**
27 * Initialize "selectors" and "pathPattern" with optional external properties file
28 */
29 public AbstractTypeFactoryProvider() {
30 Properties properties = new Properties();
31 Class clazz = this.getClass();
32
33 try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".properties")) {
34 if (is != null) {
35 properties.load(is);
36 }
37 } catch (IOException e) {
38 assert ExceptionUtil.printStackTrace(e);
39 }
40
41 init(properties);
42 }
43
44 protected void init(Properties properties) {
45 String selectors = properties.getProperty("selectors");
46 externalSelectors = (selectors == null) ? null : Arrays.asList(selectors.split(","));
47
48 String pathRegExp = properties.getProperty("pathRegExp");
49 externalPathPattern = (pathRegExp == null) ? null : Pattern.compile(pathRegExp);
50 }
51
52 protected String[] appendSelectors(String selector) {
53 if (externalSelectors == null) {
54 return new String[] { selector };
55 } else {
56 int size = externalSelectors.size();
57 String[] array = new String[size+1];
58 externalSelectors.toArray(array);
59 array[size] = selector;
60 return array;
61 }
62 }
63
64 protected String[] appendSelectors(String... selectors) {
65 if (externalSelectors == null) {
66 return selectors;
67 } else {
68 int size = externalSelectors.size();
69 String[] array = new String[size+selectors.length];
70 externalSelectors.toArray(array);
71 System.arraycopy(selectors, 0, array, size, selectors.length);
72 return array;
73 }
74 }
75
76 public Pattern getPathPattern() { return externalPathPattern; }
77
78 // Signature writers
79 protected static int writeSignature(StringBuilder sb, String descriptor, int length, int index, boolean varargsFlag) {
80 while (true) {
81 // Print array : '[[?' ou '[L[?;'
82 int dimensionLength = 0;
83
84 if (descriptor.charAt(index) == '[') {
85 dimensionLength++;
86
87 while (++index < length) {
88 if ((descriptor.charAt(index) == 'L') && (index+1 < length) && (descriptor.charAt(index+1) == '[')) {
89 index++;
90 length--;
91 dimensionLength++;
92 } else if (descriptor.charAt(index) == '[') {
93 dimensionLength++;
94 } else {
95 break;
96 }
97 }
98 }
99
100 switch(descriptor.charAt(index)) {
101 case 'B': sb.append("byte"); index++; break;
102 case 'C': sb.append("char"); index++; break;
103 case 'D': sb.append("double"); index++; break;
104 case 'F': sb.append("float"); index++; break;
105 case 'I': sb.append("int"); index++; break;
106 case 'J': sb.append("long"); index++; break;
107 case 'L': case '.':
108 int beginIndex = ++index;
109 char c = '.';
110
111 // Search ; or de <
112 while (index < length) {
113 c = descriptor.charAt(index);
114 if ((c == ';') || (c == '<'))
115 break;
116 index++;
117 }
118
119 String internalClassName = descriptor.substring(beginIndex, index);
120 int lastPackageSeparatorIndex = internalClassName.lastIndexOf('/');
121
122 if (lastPackageSeparatorIndex >= 0) {
123 // Cut package name
124 internalClassName = internalClassName.substring(lastPackageSeparatorIndex + 1);
125 }
126
127 sb.append(internalClassName.replace('$', '.'));
128
129 if (c == '<') {
130 sb.append('<');
131 index = writeSignature(sb, descriptor, length, index+1, false);
132
133 while (descriptor.charAt(index) != '>') {
134 sb.append(", ");
135 index = writeSignature(sb, descriptor, length, index, false);
136 }
137 sb.append('>');
138
139 // pass '>'
140 index++;
141 }
142
143 // pass ';'
144 if (descriptor.charAt(index) == ';')
145 index++;
146 break;
147 case 'S': sb.append("short"); index++; break;
148 case 'T':
149 beginIndex = ++index;
150 index = descriptor.substring(beginIndex, length).indexOf(';');
151 sb.append(descriptor.substring(beginIndex, index));
152 index++;
153 break;
154 case 'V': sb.append("void"); index++; break;
155 case 'Z': sb.append("boolean"); index++; break;
156 case '-':
157 sb.append("? super ");
158 index = writeSignature(sb, descriptor, length, index+1, false);
159 break;
160 case '+':
161 sb.append("? extends ");
162 index = writeSignature(sb, descriptor, length, index+1, false);
163 break;
164 case '*': sb.append('?'); index++; break;
165 case 'X': case 'Y': sb.append("int"); index++; break;
166 default:
167 throw new RuntimeException("SignatureWriter.WriteSignature: invalid signature '" + descriptor + "'");
168 }
169
170 if (varargsFlag) {
171 if (dimensionLength > 0) {
172 while (--dimensionLength > 0)
173 sb.append("[]");
174 sb.append("...");
175 }
176 } else {
177 while (dimensionLength-- > 0)
178 sb.append("[]");
179 }
180
181 if ((index >= length) || (descriptor.charAt(index) != '.'))
182 break;
183
184 sb.append('.');
185 }
186
187 return index;
188 }
189
190 protected static void writeMethodSignature(
191 StringBuilder sb, int typeAccess, int methodAccess, boolean isInnerClass,
192 String constructorName, String methodName, String descriptor) {
193 if (methodName.equals("<clinit>")) {
194 sb.append("{...}");
195 } else {
196 boolean isAConstructor = methodName.equals("<init>");
197
198 if (isAConstructor) {
199 sb.append(constructorName);
200 } else {
201 sb.append(methodName);
202 }
203
204 // Skip generics
205 int length = descriptor.length();
206 int index = 0;
207
208 while ((index < length) && (descriptor.charAt(index) != '('))
209 index++;
210
211 if (descriptor.charAt(index) != '(') {
212 throw new RuntimeException("Signature format exception: '" + descriptor + "'");
213 }
214
215 sb.append('(');
216
217 // pass '('
218 index++;
219
220 if (descriptor.charAt(index) != ')') {
221 if (isAConstructor && isInnerClass && ((typeAccess & Type.FLAG_STATIC) == 0)) {
222 // Skip first parameter
223 int lengthBackup = sb.length();
224 index = writeSignature(sb, descriptor, length, index, false);
225 sb.setLength(lengthBackup);
226 }
227
228 if (descriptor.charAt(index) != ')') {
229 int varargsParameterIndex;
230
231 if ((methodAccess & Type.FLAG_VARARGS) == 0) {
232 varargsParameterIndex = Integer.MAX_VALUE;
233 } else {
234 // Count parameters
235 int indexBackup = index;
236 int lengthBackup = sb.length();
237
238 varargsParameterIndex = -1;
239
240 while (descriptor.charAt(index) != ')') {
241 index = writeSignature(sb, descriptor, length, index, false);
242 varargsParameterIndex++;
243 }
244
245 index = indexBackup;
246 sb.setLength(lengthBackup);
247 }
248
249 // Write parameters
250 index = writeSignature(sb, descriptor, length, index, false);
251
252 int parameterIndex = 1;
253
254 while (descriptor.charAt(index) != ')') {
255 sb.append(", ");
256 index = writeSignature(sb, descriptor, length, index, (parameterIndex == varargsParameterIndex));
257 parameterIndex++;
258 }
259 }
260 }
261
262 if (isAConstructor) {
263 sb.append(')');
264 } else {
265 sb.append(") : ");
266 writeSignature(sb, descriptor, length, ++index, false);
267 }
268 }
269 }
270
271 // Icon getters
272 protected static ImageIcon getTypeIcon(int access) {
273 if ((access & Type.FLAG_ANNOTATION) != 0)
274 return ANNOTATION_ICON;
275 else if ((access & Type.FLAG_INTERFACE) != 0)
276 return INTERFACE_ICONS[accessToIndex(access)];
277 else if ((access & Type.FLAG_ENUM) != 0)
278 return ENUM_ICON;
279 else
280 return CLASS_ICONS[accessToIndex(access)];
281 }
282
283 protected static ImageIcon getFieldIcon(int access) {
284 return FIELD_ICONS[accessToIndex(access)];
285 }
286
287 protected static ImageIcon getMethodIcon(int access) {
288 return METHOD_ICONS[accessToIndex(access)];
289 }
290
291 protected static int accessToIndex(int access) {
292 int index = 0;
293
294 if ((access & Type.FLAG_STATIC) != 0)
295 index += 4;
296
297 if ((access & Type.FLAG_FINAL) != 0)
298 index += 8;
299
300 if ((access & Type.FLAG_ABSTRACT) != 0)
301 index += 16;
302
303 if ((access & Type.FLAG_PUBLIC) != 0)
304 return index + 1;
305 else if ((access & Type.FLAG_PROTECTED) != 0)
306 return index + 2;
307 else if ((access & Type.FLAG_PRIVATE) != 0)
308 return index + 3;
309 else
310 return index;
311 }
312
313 // Internal graphic stuff ...
314 protected static ImageIcon mergeIcons(ImageIcon background, ImageIcon overlay, int x, int y) {
315 int w = background.getIconWidth();
316 int h = background.getIconHeight();
317 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
318
319 if (x + overlay.getIconWidth() > w)
320 x = w - overlay.getIconWidth();
321 if (y + overlay.getIconHeight() > h)
322 y = h - overlay.getIconHeight();
323
324 Graphics2D g2 = image.createGraphics();
325 g2.drawImage(background.getImage(), 0, 0, null);
326 g2.drawImage(overlay.getImage(), x, y, null);
327 g2.dispose();
328
329 return new ImageIcon(image);
330 }
331
332 protected static ImageIcon[] mergeIcons(ImageIcon[] backgrounds, ImageIcon overlay, int x, int y) {
333 int length = backgrounds.length;
334 ImageIcon[] result = new ImageIcon[length*2];
335
336 // Copy source icons
337 System.arraycopy(backgrounds, 0, result, 0, length);
338
339 // Add overlays
340 for (int i=0; i<length; i++) {
341 result[length+i] = mergeIcons(backgrounds[i], overlay, x, y);
342 }
343
344 return result;
345 }
346
347 protected static final ImageIcon ABSTRACT_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/abstract_ovr.png"));
348 protected static final ImageIcon FINAL_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/final_ovr.png"));
349 protected static final ImageIcon STATIC_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/static_ovr.png"));
350
351 protected static final ImageIcon CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/class_default_obj.png"));
352 protected static final ImageIcon PUBLIC_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/class_obj.png"));
353 protected static final ImageIcon PROTECTED_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/class_protected_obj.png"));
354 protected static final ImageIcon PRIVATE_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/class_private_obj.png"));
355
356 protected static final ImageIcon INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/int_default_obj.png"));
357 protected static final ImageIcon PUBLIC_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/int_obj.png"));
358 protected static final ImageIcon PROTECTED_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/int_protected_obj.png"));
359 protected static final ImageIcon PRIVATE_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/int_private_obj.png"));
360
361 protected static final ImageIcon ANNOTATION_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/annotation_obj.png"));
362 protected static final ImageIcon ENUM_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/enum_obj.png"));
363
364 protected static final ImageIcon FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/field_default_obj.png"));
365 protected static final ImageIcon PUBLIC_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/field_public_obj.png"));
366 protected static final ImageIcon PROTECTED_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/field_protected_obj.png"));
367 protected static final ImageIcon PRIVATE_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/field_private_obj.png"));
368
369 protected static final ImageIcon METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/methdef_obj.png"));
370 protected static final ImageIcon PUBLIC_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/methpub_obj.png"));
371 protected static final ImageIcon PROTECTED_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/methpro_obj.png"));
372 protected static final ImageIcon PRIVATE_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/methpri_obj.png"));
373
374 // Default icon set
375 protected static final ImageIcon[] DEFAULT_CLASS_ICONS = {
376 CLASS_ICON,
377 PUBLIC_CLASS_ICON,
378 PROTECTED_CLASS_ICON,
379 PRIVATE_CLASS_ICON
380 };
381
382 protected static final ImageIcon[] DEFAULT_INTERFACE_ICONS = {
383 INTERFACE_ICON,
384 PUBLIC_INTERFACE_ICON,
385 PROTECTED_INTERFACE_ICON,
386 PRIVATE_INTERFACE_ICON
387 };
388
389 protected static final ImageIcon[] DEFAULT_FIELD_ICONS = {
390 FIELD_ICON,
391 PUBLIC_FIELD_ICON,
392 PROTECTED_FIELD_ICON,
393 PRIVATE_FIELD_ICON
394 };
395
396 protected static final ImageIcon[] DEFAULT_METHOD_ICONS = {
397 METHOD_ICON,
398 PUBLIC_METHOD_ICON,
399 PROTECTED_METHOD_ICON,
400 PRIVATE_METHOD_ICON
401 };
402
403 // Add static icon set
404 protected static final ImageIcon[] STATIC_CLASS_ICONS = mergeIcons(DEFAULT_CLASS_ICONS, STATIC_OVERLAY_ICON, 100, 0);
405 protected static final ImageIcon[] STATIC_INTERFACE_ICONS = mergeIcons(DEFAULT_INTERFACE_ICONS, STATIC_OVERLAY_ICON, 100, 0);
406 protected static final ImageIcon[] STATIC_FIELD_ICONS = mergeIcons(DEFAULT_FIELD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
407 protected static final ImageIcon[] STATIC_METHOD_ICONS = mergeIcons(DEFAULT_METHOD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
408
409 // Add final icon set
410 protected static final ImageIcon[] FINAL_STATIC_CLASS_ICONS = mergeIcons(STATIC_CLASS_ICONS, FINAL_OVERLAY_ICON, 0, 0);
411 protected static final ImageIcon[] FINAL_STATIC_INTERFACE_ICONS = mergeIcons(STATIC_INTERFACE_ICONS, FINAL_OVERLAY_ICON, 0, 0);
412 protected static final ImageIcon[] FINAL_STATIC_FIELD_ICONS = mergeIcons(STATIC_FIELD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
413 protected static final ImageIcon[] FINAL_STATIC_METHOD_ICONS = mergeIcons(STATIC_METHOD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
414
415 // Add abstract icon set
416 protected static final ImageIcon[] CLASS_ICONS = mergeIcons(FINAL_STATIC_CLASS_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
417 protected static final ImageIcon[] INTERFACE_ICONS = mergeIcons(FINAL_STATIC_INTERFACE_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
418 protected static final ImageIcon[] FIELD_ICONS = mergeIcons(FINAL_STATIC_FIELD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
419 protected static final ImageIcon[] METHOD_ICONS = mergeIcons(FINAL_STATIC_METHOD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
420
421 // Cache
422 protected static class Cache<K, V> extends LinkedHashMap<K, V> {
423 public static final int CACHE_MAX_ENTRIES = 100;
424
425 public Cache() {
426 super(CACHE_MAX_ENTRIES*3/2, 0.7f, true);
427 }
428
429 @Override
430 protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
431 return size() > CACHE_MAX_ENTRIES;
432 }
433 }
434 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.type;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.model.Container;
11 import org.jd.gui.api.model.Type;
12 import org.jd.gui.util.exception.ExceptionUtil;
13 import org.objectweb.asm.*;
14
15 import javax.swing.*;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.net.URI;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23
24 public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
25
26 static {
27 // Early class loading
28 try {
29 Class.forName(JavaType.class.getName());
30 } catch (Exception e) {
31 assert ExceptionUtil.printStackTrace(e);
32 }
33 }
34
35 // Create cache
36 protected Cache<URI, JavaType> cache = new Cache<>();
37
38 @Override public String[] getSelectors() { return appendSelectors("*:file:*.class"); }
39
40 @Override
41 public Collection<Type> make(API api, Container.Entry entry) {
42 return Collections.singletonList(make(api, entry, null));
43 }
44
45 @Override
46 public Type make(API api, Container.Entry entry, String fragment) {
47 URI key = entry.getUri();
48
49 if (cache.containsKey(key)) {
50 return cache.get(key);
51 } else {
52 JavaType type;
53
54 try (InputStream is = entry.getInputStream()) {
55 ClassReader classReader = new ClassReader(is);
56
57 if ((fragment != null) && (fragment.length() > 0)) {
58 // Search type name in fragment. URI format : see jd.gui.api.feature.UriOpener
59 int index = fragment.indexOf('-');
60 if (index != -1) {
61 // Keep type name only
62 fragment = fragment.substring(0, index);
63 }
64
65 if (!classReader.getClassName().equals(fragment)) {
66 // Search entry for type name
67 String entryTypePath = classReader.getClassName() + ".class";
68 String fragmentTypePath = fragment + ".class";
69
70 while (true) {
71 if (entry.getPath().endsWith(entryTypePath)) {
72 // Entry path ends with the internal class name
73 String pathToFound = entry.getPath().substring(0, entry.getPath().length() - entryTypePath.length()) + fragmentTypePath;
74 Container.Entry entryFound = null;
75
76 for (Container.Entry e : entry.getParent().getChildren()) {
77 if (e.getPath().equals(pathToFound)) {
78 entryFound = e;
79 break;
80 }
81 }
82
83 if (entryFound == null)
84 return null;
85
86 entry = entryFound;
87
88 try (InputStream is2 = entry.getInputStream()) {
89 classReader = new ClassReader(is2);
90 } catch (IOException e) {
91 assert ExceptionUtil.printStackTrace(e);
92 return null;
93 }
94 break;
95 }
96
97 // Truncated path ? Cut first package name and retry
98 int firstPackageSeparatorIndex = entryTypePath.indexOf('/');
99 if (firstPackageSeparatorIndex == -1) {
100 // Nothing to cut -> Stop
101 return null;
102 }
103
104 entryTypePath = entryTypePath.substring(firstPackageSeparatorIndex + 1);
105 fragmentTypePath = fragmentTypePath.substring(fragmentTypePath.indexOf('/') + 1);
106 }
107 }
108 }
109
110 type = new JavaType(entry, classReader, -1);
111 } catch (IOException e) {
112 assert ExceptionUtil.printStackTrace(e);
113 type = null;
114 }
115
116 cache.put(key, type);
117 return type;
118 }
119 }
120
121 static class JavaType implements Type {
122 protected Container.Entry entry;
123 protected int access;
124 protected String name;
125 protected String superName;
126 protected String outerName;
127
128 protected String displayTypeName;
129 protected String displayInnerTypeName;
130 protected String displayPackageName;
131
132 protected List<Type> innerTypes;
133 protected List<Type.Field> fields = new ArrayList<>();
134 protected List<Type.Method> methods = new ArrayList<>();
135
136 @SuppressWarnings("unchecked")
137 protected JavaType(Container.Entry entry, ClassReader classReader, final int outerAccess) {
138 this.entry = entry;
139
140 ClassVisitor classAndInnerClassesVisitor = new ClassVisitor(Opcodes.ASM7) {
141 @Override
142 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
143 JavaType.this.access = (outerAccess == -1) ? access : outerAccess;
144 JavaType.this.name = name;
145 JavaType.this.superName = ((access & Opcodes.ACC_INTERFACE) != 0) && "java/lang/Object".equals(superName) ? null : superName;
146 }
147
148 @Override
149 public void visitInnerClass(String name, String outerName, String innerName, int access) {
150 if (JavaType.this.name.equals(name)) {
151 // Inner class path found
152 JavaType.this.outerName = outerName;
153 JavaType.this.displayInnerTypeName = innerName;
154 } else if (((access & (Opcodes.ACC_SYNTHETIC|Opcodes.ACC_BRIDGE)) == 0) && JavaType.this.name.equals(outerName)) {
155 Container.Entry innerEntry = getEntry(name);
156
157 if (innerEntry != null) {
158 try (InputStream is = innerEntry.getInputStream()) {
159 ClassReader classReader = new ClassReader(is);
160 if (innerTypes == null) {
161 innerTypes = new ArrayList<>();
162 }
163 innerTypes.add(new JavaType(innerEntry, classReader, access));
164 } catch (IOException e) {
165 assert ExceptionUtil.printStackTrace(e);
166 }
167 }
168 }
169 }
170 };
171
172 classReader.accept(classAndInnerClassesVisitor, ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
173
174 int lastPackageSeparatorIndex = name.lastIndexOf('/');
175
176 if (lastPackageSeparatorIndex == -1) {
177 displayPackageName = "";
178
179 if (outerName == null) {
180 displayTypeName = name;
181 } else {
182 displayTypeName = getDisplayTypeName(outerName, 0) + '.' + displayInnerTypeName;
183 }
184 } else {
185 displayPackageName = name.substring(0, lastPackageSeparatorIndex).replace('/', '.');
186
187 if (outerName == null) {
188 displayTypeName = name;
189 } else {
190 displayTypeName = getDisplayTypeName(outerName, lastPackageSeparatorIndex) + '.' + displayInnerTypeName;
191 }
192
193 displayTypeName = displayTypeName.substring(lastPackageSeparatorIndex+1);
194 }
195
196 ClassVisitor fieldsAndMethodsVisitor = new ClassVisitor(Opcodes.ASM7) {
197 @Override
198 public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
199 if ((access & (Opcodes.ACC_SYNTHETIC|Opcodes.ACC_ENUM)) == 0) {
200 fields.add(new Type.Field() {
201 public int getFlags() { return access; }
202 public String getName() { return name; }
203 public String getDescriptor() { return descriptor; }
204 public Icon getIcon() { return getFieldIcon(access); }
205
206 public String getDisplayName() {
207 StringBuilder sb = new StringBuilder();
208 sb.append(name).append(" : ");
209 writeSignature(sb, descriptor, descriptor.length(), 0, false);
210 return sb.toString();
211 }
212 });
213 }
214 return null;
215 }
216
217 @Override
218 public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
219 if ((access & (Opcodes.ACC_SYNTHETIC|Opcodes.ACC_ENUM|Opcodes.ACC_BRIDGE)) == 0) {
220 methods.add(new Type.Method() {
221 public int getFlags() { return access; }
222 public String getName() { return name; }
223 public String getDescriptor() { return descriptor; }
224 public Icon getIcon() { return getMethodIcon(access); }
225
226 public String getDisplayName() {
227 boolean isInnerClass = (JavaType.this.displayInnerTypeName != null);
228 String constructorName = isInnerClass ? JavaType.this.displayInnerTypeName : JavaType.this.displayTypeName;
229 StringBuilder sb = new StringBuilder();
230 writeMethodSignature(sb, JavaType.this.access, access, isInnerClass, constructorName, name, descriptor);
231 return sb.toString();
232 }
233 });
234 }
235 return null;
236 }
237 };
238
239 classReader.accept(fieldsAndMethodsVisitor, ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
240 }
241
242 @SuppressWarnings("unchecked")
243 protected String getDisplayTypeName(String name, int packageLength) {
244 int indexDollar = name.lastIndexOf('$');
245
246 if (indexDollar > packageLength) {
247 Container.Entry entry = getEntry(name);
248
249 if (entry != null) {
250 try (InputStream is = entry.getInputStream()) {
251 ClassReader classReader = new ClassReader(is);
252 InnerClassVisitor classVisitor = new InnerClassVisitor(name);
253
254 classReader.accept(classVisitor, ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
255
256 String outerName = classVisitor.getOuterName();
257
258 if (outerName != null) {
259 // Inner class path found => Recursive call
260 return getDisplayTypeName(outerName, packageLength) + '.' + classVisitor.getInnerName();
261 }
262 } catch (IOException e) {
263 assert ExceptionUtil.printStackTrace(e);
264 }
265 }
266 }
267
268 return name;
269 }
270
271 protected Container.Entry getEntry(String typeName) {
272 String pathToFound = typeName + ".class";
273
274 for (Container.Entry entry : entry.getParent().getChildren()) {
275 if (entry.getPath().equals(pathToFound)) {
276 return entry;
277 }
278 }
279
280 return null;
281 }
282
283 @Override public int getFlags() { return access; }
284 @Override public String getName() { return name; }
285 @Override public String getSuperName() { return superName; }
286 @Override public String getOuterName() { return outerName; }
287 @Override public String getDisplayPackageName() { return displayPackageName; }
288 @Override public String getDisplayTypeName() { return displayTypeName; }
289 @Override public String getDisplayInnerTypeName() { return displayInnerTypeName; }
290 @Override public Icon getIcon() { return getTypeIcon(access); }
291 @Override public List<Type> getInnerTypes() { return innerTypes; }
292 @Override public List<Type.Field> getFields() { return fields; }
293 @Override public List<Type.Method> getMethods() { return methods; }
294 }
295
296 protected static class InnerClassVisitor extends ClassVisitor {
297 protected String name;
298 protected String outerName;
299 protected String innerName;
300
301 public InnerClassVisitor(String name) {
302 super(Opcodes.ASM7);
303 this.name = name;
304 }
305
306 @Override
307 public void visitInnerClass(String name, String outerName, String innerName, int access) {
308 if (this.name.equals(name)) {
309 // Inner class path found
310 this.outerName = outerName;
311 this.innerName = innerName;
312 }
313 }
314
315 public String getOuterName() {
316 return outerName;
317 }
318
319 public String getInnerName() {
320 return innerName;
321 }
322 }
323 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.type;
8
9 import org.antlr.v4.runtime.ANTLRInputStream;
10 import org.antlr.v4.runtime.ParserRuleContext;
11 import org.antlr.v4.runtime.tree.ParseTree;
12 import org.antlr.v4.runtime.tree.TerminalNode;
13 import org.jd.gui.api.API;
14 import org.jd.gui.api.model.Container;
15 import org.jd.gui.api.model.Type;
16 import org.jd.gui.util.exception.ExceptionUtil;
17 import org.jd.gui.util.parser.antlr.ANTLRJavaParser;
18 import org.jd.gui.util.parser.antlr.AbstractJavaListener;
19 import org.jd.gui.util.parser.antlr.JavaParser;
20
21 import javax.swing.*;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URI;
25 import java.util.*;
26
27 public class JavaFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
28
29 static {
30 // Early class loading
31 ANTLRJavaParser.parse(new ANTLRInputStream("class EarlyLoading{}"), new Listener(null));
32 }
33
34 // Create cache
35 protected Cache<URI, Listener> cache = new Cache<>();
36
37 @Override public String[] getSelectors() { return appendSelectors("*:file:*.java"); }
38
39 @Override
40 public Collection<Type> make(API api, Container.Entry entry) {
41 Listener listener = getListener(entry);
42
43 if (listener == null) {
44 return Collections.emptyList();
45 } else {
46 return listener.getRootTypes();
47 }
48 }
49
50 @Override
51 public Type make(API api, Container.Entry entry, String fragment) {
52 Listener listener = getListener(entry);
53
54 if (listener == null) {
55 return null;
56 } else {
57 if ((fragment != null) && (fragment.length() > 0)) {
58 // Search type name in fragment. URI format : see jd.gui.api.feature.UriOpener
59 int index = fragment.indexOf('-');
60
61 if (index != -1) {
62 // Keep type name only
63 fragment = fragment.substring(0, index);
64 }
65
66 return listener.getType(fragment);
67 } else {
68 return listener.getMainType();
69 }
70 }
71 }
72
73 protected Listener getListener(Container.Entry entry) {
74 URI key = entry.getUri();
75
76 if (cache.containsKey(key)) {
77 return cache.get(key);
78 } else {
79 Listener listener;
80
81 try (InputStream inputStream = entry.getInputStream()) {
82 ANTLRJavaParser.parse(new ANTLRInputStream(inputStream), listener = new Listener(entry));
83 } catch (IOException e) {
84 assert ExceptionUtil.printStackTrace(e);
85 listener = null;
86 }
87
88 cache.put(key, listener);
89 return listener;
90 }
91 }
92
93 protected static class JavaType implements Type {
94 protected int access;
95 protected String name;
96 protected String superName;
97 protected String outerName;
98
99 protected String displayTypeName;
100 protected String displayInnerTypeName;
101 protected String displayPackageName;
102
103 protected List<Type> innerTypes = new ArrayList<>();
104 protected List<Field> fields = new ArrayList<>();
105 protected List<Method> methods = new ArrayList<>();
106
107 protected JavaType outerType;
108
109 public JavaType(
110 int access, String name, String superName, String outerName,
111 String displayTypeName, String displayInnerTypeName, String displayPackageName,
112 JavaType outerType) {
113
114 this.access = access;
115 this.name = name;
116 this.superName = superName;
117 this.outerName = outerName;
118 this.displayTypeName = displayTypeName;
119 this.displayInnerTypeName = displayInnerTypeName;
120 this.displayPackageName = displayPackageName;
121 this.outerType = outerType;
122 }
123
124 public int getFlags() { return access; }
125 public String getName() { return name; }
126 public String getSuperName() { return superName; }
127 public String getOuterName() { return outerName; }
128 public String getDisplayTypeName() { return displayTypeName; }
129 public String getDisplayInnerTypeName() { return displayInnerTypeName; }
130 public String getDisplayPackageName() { return displayPackageName; }
131 public Icon getIcon() { return getTypeIcon(access); }
132 public JavaType getOuterType() { return outerType; }
133 public Collection<Type> getInnerTypes() { return innerTypes; }
134 public Collection<Field> getFields() { return fields; }
135 public Collection<Method> getMethods() { return methods; }
136 }
137
138 protected static class JavaField implements Type.Field {
139 protected int access;
140 protected String name;
141 protected String descriptor;
142
143 public JavaField(int access, String name, String descriptor) {
144 this.access = access;
145 this.name = name;
146 this.descriptor = descriptor;
147 }
148
149 public int getFlags() { return access; }
150 public String getName() { return name; }
151 public String getDescriptor() { return descriptor; }
152 public Icon getIcon() { return getFieldIcon(access); }
153
154 public String getDisplayName() {
155 StringBuilder sb = new StringBuilder();
156 sb.append(name).append(" : ");
157 writeSignature(sb, descriptor, descriptor.length(), 0, false);
158 return sb.toString();
159 }
160 }
161
162 protected static class JavaMethod implements Type.Method {
163 protected JavaType type;
164 protected int access;
165 protected String name;
166 protected String descriptor;
167
168 public JavaMethod(JavaType type, int access, String name, String descriptor) {
169 this.type = type;
170 this.access = access;
171 this.name = name;
172 this.descriptor = descriptor;
173 }
174
175 public int getFlags() { return access; }
176 public String getName() { return name; }
177 public String getDescriptor() { return descriptor; }
178 public Icon getIcon() { return getMethodIcon(access); }
179
180 public String getDisplayName() {
181 String constructorName = type.getDisplayInnerTypeName();
182 boolean isInnerClass = (constructorName != null);
183
184 if (constructorName == null)
185 constructorName = type.getDisplayTypeName();
186
187 StringBuilder sb = new StringBuilder();
188 writeMethodSignature(sb, access, access, isInnerClass, constructorName, name, descriptor);
189 return sb.toString();
190 }
191 }
192
193 protected static class Listener extends AbstractJavaListener {
194
195 protected String displayPackageName = "";
196
197 protected JavaType mainType = null;
198 protected JavaType currentType = null;
199 protected ArrayList<Type> rootTypes = new ArrayList<>();
200 protected HashMap<String, Type> types = new HashMap<>();
201
202 public Listener(Container.Entry entry) {
203 super(entry);
204 }
205
206 public Type getMainType() {
207 return mainType;
208 }
209 public Type getType(String typeName) {
210 return types.get(typeName);
211 }
212 public ArrayList<Type> getRootTypes() {
213 return rootTypes;
214 }
215
216 // --- ANTLR Listener --- //
217
218 public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
219 super.enterPackageDeclaration(ctx);
220 displayPackageName = packageName.replace('/', '.');
221 }
222
223 public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx, 0); }
224 public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
225
226 public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_ENUM); }
227 public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
228
229 public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_INTERFACE); }
230 public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
231
232 public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_ANNOTATION); }
233 public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
234
235 protected void enterTypeDeclaration(ParserRuleContext ctx, int access) {
236 String name = ctx.getToken(JavaParser.Identifier, 0).getText();
237
238 JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
239 String superQualifiedTypeName;
240
241 if (superType == null) {
242 superQualifiedTypeName = ((access & JavaType.FLAG_INTERFACE) == 0) ? "java/lang/Object" : "";
243 } else {
244 superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
245 }
246
247 ParserRuleContext parent = ctx.getParent();
248
249 if (parent instanceof JavaParser.TypeDeclarationContext)
250 access += getTypeDeclarationContextAccessFlag(parent);
251 else if (parent instanceof JavaParser.MemberDeclarationContext)
252 access += getMemberDeclarationContextAccessFlag(parent.getParent());
253
254 if (currentType == null) {
255 String internalTypeName = packageName.isEmpty() ? name : packageName + "/" + name;
256 String outerName = null;
257 String displayTypeName = name;
258 String displayInnerTypeName = null;
259
260 currentType = new JavaType(access, internalTypeName, superQualifiedTypeName, outerName, displayTypeName, displayInnerTypeName, displayPackageName, null);
261 types.put(internalTypeName, currentType);
262 rootTypes.add(currentType);
263 nameToInternalTypeName.put(name, internalTypeName);
264
265 if (mainType == null) {
266 mainType = currentType;
267 } else {
268 // Multi class definitions in the same file
269 String path = entry.getPath();
270 int index = path.lastIndexOf('/') + 1;
271
272 if (path.substring(index).startsWith(name + '.')) {
273 // Select the correct root type
274 mainType = currentType;
275 }
276 }
277 } else {
278 String internalTypeName = currentType.getName() + '$' + name;
279 String outerName = currentType.getName();
280 String displayTypeName = currentType.getDisplayTypeName() + '.' + name;
281 String displayInnerTypeName = name;
282 JavaType subType = new JavaType(access, internalTypeName, superQualifiedTypeName, outerName, displayTypeName, displayInnerTypeName, displayPackageName, currentType);
283
284 currentType.getInnerTypes().add(subType);
285 currentType = subType;
286 types.put(internalTypeName, currentType);
287 nameToInternalTypeName.put(name, internalTypeName);
288 }
289 }
290
291 protected void exitTypeDeclaration() {
292 currentType = currentType.getOuterType();
293 }
294
295 public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) {
296 if (ctx.getChildCount() == 2) {
297 ParseTree first = ctx.getChild(0);
298
299 if (first instanceof TerminalNode) {
300 if (((TerminalNode)first).getSymbol().getType() == JavaParser.STATIC) {
301 currentType.getMethods().add(new JavaMethod(currentType, JavaType.FLAG_STATIC, "<clinit>", "()V"));
302 }
303 }
304 }
305 }
306
307 public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
308 JavaParser.TypeContext typeContext = ctx.type();
309 int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
310
311 for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
312 TerminalNode identifier = constantDeclaratorContext.Identifier();
313 String name = identifier.getText();
314 int dimensionOnVariable = countDimension(constantDeclaratorContext.children);
315 String descriptor = createDescriptor(typeContext, dimensionOnVariable);
316
317 currentType.getFields().add(new JavaField(access, name, descriptor));
318 }
319 }
320
321 public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
322 JavaParser.TypeContext typeContext = ctx.type();
323 int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
324
325 for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
326 JavaParser.VariableDeclaratorIdContext variableDeclaratorId = declaration.variableDeclaratorId();
327 TerminalNode identifier = variableDeclaratorId.Identifier();
328 String name = identifier.getText();
329 int dimensionOnVariable = countDimension(variableDeclaratorId.children);
330 String descriptor = createDescriptor(typeContext, dimensionOnVariable);
331
332 currentType.getFields().add(new JavaField(access, name, descriptor));
333 }
334 }
335
336 public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
337 enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
338 }
339
340 public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
341 enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
342 }
343
344 public void enterMethodDeclaration(
345 ParserRuleContext ctx, TerminalNode identifier,
346 JavaParser.FormalParametersContext formalParameters, JavaParser.TypeContext returnType) {
347
348 int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
349 String name = identifier.getText();
350 String paramDescriptors = createParamDescriptors(formalParameters.formalParameterList());
351 String returnDescriptor = createDescriptor(returnType, 0);
352 String descriptor = paramDescriptors + returnDescriptor;
353
354 currentType.getMethods().add(new JavaMethod(currentType, access, name, descriptor));
355 }
356
357 public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
358 int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
359 String paramDescriptors = createParamDescriptors(ctx.formalParameters().formalParameterList());
360 String descriptor = paramDescriptors + "V";
361
362 currentType.getMethods().add(new JavaMethod(currentType, access, "<init>", descriptor));
363 }
364
365 protected String createParamDescriptors(JavaParser.FormalParameterListContext formalParameterList) {
366 StringBuilder paramDescriptors = null;
367
368 if (formalParameterList != null) {
369 List<JavaParser.FormalParameterContext> formalParameters = formalParameterList.formalParameter();
370 paramDescriptors = new StringBuilder("(");
371
372 for (JavaParser.FormalParameterContext formalParameter : formalParameters) {
373 int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children);
374 paramDescriptors.append(createDescriptor(formalParameter.type(), dimensionOnParameter));
375 }
376 }
377
378 return (paramDescriptors == null) ? "()" : paramDescriptors.append(')').toString();
379 }
380
381 protected int getTypeDeclarationContextAccessFlag(ParserRuleContext ctx) {
382 int access = 0;
383
384 for (JavaParser.ClassOrInterfaceModifierContext coiModifierContext : ctx.getRuleContexts(JavaParser.ClassOrInterfaceModifierContext.class)) {
385 access += getAccessFlag(coiModifierContext);
386 }
387
388 return access;
389 }
390
391 protected int getMemberDeclarationContextAccessFlag(ParserRuleContext ctx) {
392 int access = 0;
393
394 for (JavaParser.ModifierContext modifierContext : ctx.getRuleContexts(JavaParser.ModifierContext.class)) {
395 JavaParser.ClassOrInterfaceModifierContext coiModifierContext = modifierContext.classOrInterfaceModifier();
396 if (coiModifierContext != null) {
397 access += getAccessFlag(coiModifierContext);
398 }
399 }
400
401 return access;
402 }
403
404 protected int getClassBodyDeclarationAccessFlag(ParserRuleContext ctx) {
405 if ((currentType.access & JavaType.FLAG_INTERFACE) == 0) {
406 int access = 0;
407
408 for (JavaParser.ModifierContext modifierContext : ctx.getRuleContexts(JavaParser.ModifierContext.class)) {
409 JavaParser.ClassOrInterfaceModifierContext coimc = modifierContext.classOrInterfaceModifier();
410
411 if (coimc != null) {
412 access += getAccessFlag(coimc);
413 }
414 }
415
416 return access;
417 } else {
418 return JavaType.FLAG_PUBLIC;
419 }
420 }
421
422 protected int getAccessFlag(JavaParser.ClassOrInterfaceModifierContext ctx) {
423 if (ctx.getChildCount() == 1) {
424 ParseTree first = ctx.getChild(0);
425
426 if (first instanceof TerminalNode) {
427 switch (((TerminalNode)first).getSymbol().getType()) {
428 case JavaParser.STATIC: return JavaType.FLAG_STATIC;
429 case JavaParser.FINAL: return JavaType.FLAG_FINAL;
430 case JavaParser.ABSTRACT: return JavaType.FLAG_ABSTRACT;
431 case JavaParser.PUBLIC: return JavaType.FLAG_PUBLIC;
432 case JavaParser.PROTECTED: return JavaType.FLAG_PROTECTED;
433 case JavaParser.PRIVATE: return JavaType.FLAG_PRIVATE;
434 }
435 }
436 }
437
438 return 0;
439 }
440 }
441 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.uriloader;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.spi.FileLoader;
11 import org.jd.gui.spi.UriLoader;
12
13 import java.io.File;
14 import java.net.URI;
15
16 public class FileUriLoaderProvider implements UriLoader {
17 protected static final String[] SCHEMES = { "file" };
18
19 public String[] getSchemes() { return SCHEMES; }
20
21 public boolean accept(API api, URI uri) { return "file".equals(uri.getScheme()); }
22
23 public boolean load(API api, URI uri) {
24 File file = new File(uri.getPath());
25 FileLoader fileLoader = api.getFileLoader(file);
26
27 return (fileLoader != null) && fileLoader.load(api, file);
28 }
29 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.container;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.model.container.ContainerEntryComparator;
11 import org.jd.gui.util.exception.ExceptionUtil;
12 import org.objectweb.asm.ClassReader;
13 import org.objectweb.asm.ClassVisitor;
14 import org.objectweb.asm.Opcodes;
15
16 import java.io.InputStream;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.List;
21
22 public class JarContainerEntryUtil {
23 public static Collection<Container.Entry> removeInnerTypeEntries(Collection<Container.Entry> entries) {
24 HashSet<String> potentialOuterTypePaths = new HashSet<>();
25 Collection<Container.Entry> filtredSubEntries;
26
27 for (Container.Entry e : entries) {
28 if (!e.isDirectory()) {
29 String p = e.getPath();
30
31 if (p.toLowerCase().endsWith(".class")) {
32 int lastSeparatorIndex = p.lastIndexOf('/');
33 int dollarIndex = p.substring(lastSeparatorIndex+1).indexOf('$');
34
35 if (dollarIndex != -1) {
36 potentialOuterTypePaths.add(p.substring(0, lastSeparatorIndex+1+dollarIndex) + ".class");
37 }
38 }
39 }
40 }
41
42 if (potentialOuterTypePaths.size() == 0) {
43 filtredSubEntries = entries;
44 } else {
45 HashSet<String> innerTypePaths = new HashSet<>();
46
47 for (Container.Entry e : entries) {
48 if (!e.isDirectory() && potentialOuterTypePaths.contains(e.getPath())) {
49 populateInnerTypePaths(innerTypePaths, e);
50 }
51 }
52
53 filtredSubEntries = new ArrayList<>();
54
55 for (Container.Entry e : entries) {
56 if (!e.isDirectory()) {
57 String p = e.getPath();
58
59 if (p.toLowerCase().endsWith(".class")) {
60 int indexDollar = p.lastIndexOf('$');
61
62 if (indexDollar != -1) {
63 int indexSeparator = p.lastIndexOf('/');
64
65 if (indexDollar > indexSeparator) {
66 if (innerTypePaths.contains(p)) {
67 // Inner class found -> Skip
68 continue;
69 } else {
70 populateInnerTypePaths(innerTypePaths, e);
71
72 if (innerTypePaths.contains(p)) {
73 // Inner class found -> Skip
74 continue;
75 }
76 }
77 }
78 }
79 }
80 }
81 // Valid path
82 filtredSubEntries.add(e);
83 }
84 }
85
86 List<Container.Entry> list = new ArrayList<>(filtredSubEntries);
87 list.sort(ContainerEntryComparator.COMPARATOR);
88
89 return list;
90 }
91
92 protected static void populateInnerTypePaths(final HashSet<String> innerTypePaths, Container.Entry entry) {
93 try (InputStream is = entry.getInputStream()) {
94 ClassReader classReader = new ClassReader(is);
95 String p = entry.getPath();
96 final String prefixPath = p.substring(0, p.length() - classReader.getClassName().length() - 6);
97
98 ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM7) {
99 public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) {
100 innerTypePaths.add(prefixPath + name + ".class");
101 }
102 };
103
104 classReader.accept(classVisitor, ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
105 } catch (Exception e) {
106 assert ExceptionUtil.printStackTrace(e);
107 }
108 }
109 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.decompiler;
8
9 import org.jd.core.v1.api.loader.Loader;
10 import org.jd.core.v1.api.loader.LoaderException;
11
12 import java.io.ByteArrayOutputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15
16 public class ClassPathLoader implements Loader {
17 protected byte[] buffer = new byte[1024 * 4];
18
19 @Override
20 public boolean canLoad(String internalName) {
21 return this.getClass().getResource("/" + internalName + ".class") != null;
22 }
23
24 @Override
25 public byte[] load(String internalName) throws LoaderException {
26 InputStream is = this.getClass().getResourceAsStream("/" + internalName + ".class");
27
28 if (is == null) {
29 return null;
30 } else {
31 try (InputStream input=is; ByteArrayOutputStream output=new ByteArrayOutputStream()) {
32 int len = input.read(buffer);
33
34 while (len > 0) {
35 output.write(buffer, 0, len);
36 len = input.read(buffer);
37 }
38
39 return output.toByteArray();
40 } catch (IOException e) {
41 throw new LoaderException(e);
42 }
43 }
44 }
45 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.decompiler;
8
9 import org.jd.core.v1.api.loader.Loader;
10 import org.jd.core.v1.api.loader.LoaderException;
11 import org.jd.gui.api.model.Container;
12
13 import java.io.ByteArrayOutputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16
17 public class ContainerLoader implements Loader {
18 protected byte[] buffer = new byte[1024 * 4];
19 protected Container.Entry entry;
20
21 public ContainerLoader() { this.entry = null; }
22 public ContainerLoader(Container.Entry entry) {
23 this.entry = entry;
24 }
25
26 public void setEntry(Container.Entry e) { this.entry = e; }
27
28 protected Container.Entry getEntry(String internalPath) {
29 String path = internalPath + ".class";
30
31 if (entry.getPath().equals(path)) {
32 return entry;
33 }
34 for (Container.Entry e : entry.getParent().getChildren()) {
35 if (e.getPath().equals(path)) {
36 return e;
37 }
38 }
39 return null;
40 }
41
42 // --- Loader --- //
43 @Override
44 public boolean canLoad(String internalName) {
45 return getEntry(internalName) != null;
46 }
47
48 @Override
49 public byte[] load(String internalName) throws LoaderException {
50 Container.Entry entry = getEntry(internalName);
51
52 if (entry == null) {
53 return null;
54 } else {
55 try (InputStream input=entry.getInputStream(); ByteArrayOutputStream output=new ByteArrayOutputStream()) {
56 int len = input.read(buffer);
57
58 while (len > 0) {
59 output.write(buffer, 0, len);
60 len = input.read(buffer);
61 }
62
63 return output.toByteArray();
64 } catch (IOException e) {
65 throw new LoaderException(e);
66 }
67 }
68 }
69 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.decompiler;
8
9 public class LineNumberStringBuilderPrinter extends StringBuilderPrinter {
10 protected boolean showLineNumbers = false;
11
12 protected int maxLineNumber = 0;
13 protected int digitCount = 0;
14
15 protected String lineNumberBeginPrefix;
16 protected String lineNumberEndPrefix;
17 protected String unknownLineNumberPrefix;
18
19 public void setShowLineNumbers(boolean showLineNumbers) { this.showLineNumbers = showLineNumbers; }
20
21 protected int printDigit(int dcv, int lineNumber, int divisor, int left) {
22 if (digitCount >= dcv) {
23 if (lineNumber < divisor) {
24 stringBuffer.append(' ');
25 } else {
26 int e = (lineNumber-left) / divisor;
27 stringBuffer.append((char)('0' + e));
28 left += e*divisor;
29 }
30 }
31
32 return left;
33 }
34
35 // --- Printer --- //
36 @Override
37 public void start(int maxLineNumber, int majorVersion, int minorVersion) {
38 super.start(maxLineNumber, majorVersion, minorVersion);
39
40 if (showLineNumbers) {
41 this.maxLineNumber = maxLineNumber;
42
43 if (maxLineNumber > 0) {
44 digitCount = 1;
45 unknownLineNumberPrefix = " ";
46 int maximum = 9;
47
48 while (maximum < maxLineNumber) {
49 digitCount++;
50 unknownLineNumberPrefix += ' ';
51 maximum = maximum*10 + 9;
52 }
53
54 lineNumberBeginPrefix = "/* ";
55 lineNumberEndPrefix = " */ ";
56 } else {
57 unknownLineNumberPrefix = "";
58 lineNumberBeginPrefix = "";
59 lineNumberEndPrefix = "";
60 }
61 } else {
62 this.maxLineNumber = 0;
63 unknownLineNumberPrefix = "";
64 lineNumberBeginPrefix = "";
65 lineNumberEndPrefix = "";
66 }
67 }
68
69 @Override public void startLine(int lineNumber) {
70 if (maxLineNumber > 0) {
71 stringBuffer.append(lineNumberBeginPrefix);
72
73 if (lineNumber == UNKNOWN_LINE_NUMBER) {
74 stringBuffer.append(unknownLineNumberPrefix);
75 } else {
76 int left = 0;
77
78 left = printDigit(5, lineNumber, 10000, left);
79 left = printDigit(4, lineNumber, 1000, left);
80 left = printDigit(3, lineNumber, 100, left);
81 left = printDigit(2, lineNumber, 10, left);
82 stringBuffer.append((char)('0' + (lineNumber-left)));
83 }
84
85 stringBuffer.append(lineNumberEndPrefix);
86 }
87
88 for (int i=0; i<indentationCount; i++) {
89 stringBuffer.append(TAB);
90 }
91 }
92 @Override public void extraLine(int count) {
93 if (realignmentLineNumber) {
94 while (count-- > 0) {
95 if (maxLineNumber > 0) {
96 stringBuffer.append(lineNumberBeginPrefix);
97 stringBuffer.append(unknownLineNumberPrefix);
98 stringBuffer.append(lineNumberEndPrefix);
99 }
100
101 stringBuffer.append(NEWLINE);
102 }
103 }
104 }
105 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.decompiler;
8
9 import org.jd.core.v1.api.printer.Printer;
10
11 public class NopPrinter implements Printer {
12 @Override public void start(int maxLineNumber, int majorVersion, int minorVersion) {}
13 @Override public void end() {}
14
15 @Override public void printText(String text) {}
16 @Override public void printNumericConstant(String constant) {}
17 @Override public void printStringConstant(String constant, String ownerInternalName) {}
18 @Override public void printKeyword(String keyword) {}
19
20 @Override public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) {}
21 @Override public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) {}
22
23 @Override public void indent() {}
24 @Override public void unindent() {}
25
26 @Override public void startLine(int lineNumber) {}
27 @Override public void endLine() {}
28 @Override public void extraLine(int count) {}
29
30 @Override public void startMarker(int type) {}
31 @Override public void endMarker(int type) {}
32 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.decompiler;
8
9 import org.jd.core.v1.api.printer.Printer;
10
11 public class StringBuilderPrinter implements Printer {
12 protected static final String TAB = " ";
13 protected static final String NEWLINE = "\n";
14
15 protected StringBuilder stringBuffer = new StringBuilder(10*1024);
16
17 protected boolean unicodeEscape = true;
18 protected boolean realignmentLineNumber = false;
19
20 protected int majorVersion = 0;
21 protected int minorVersion = 0;
22 protected int indentationCount;
23
24 public void setUnicodeEscape(boolean unicodeEscape) { this.unicodeEscape = unicodeEscape; }
25 public void setRealignmentLineNumber(boolean realignmentLineNumber) { this.realignmentLineNumber = realignmentLineNumber; }
26
27 public int getMajorVersion() { return majorVersion; }
28 public int getMinorVersion() { return minorVersion; }
29 public StringBuilder getStringBuffer() { return stringBuffer; }
30
31 protected void escape(String s) {
32 if (unicodeEscape && (s != null)) {
33 int length = s.length();
34
35 for (int i=0; i<length; i++) {
36 char c = s.charAt(i);
37
38 if (c == '\t') {
39 stringBuffer.append(c);
40 } else if (c < 32) {
41 // Write octal format
42 stringBuffer.append("\\0");
43 stringBuffer.append((char) ('0' + (c >> 3)));
44 stringBuffer.append((char) ('0' + (c & 0x7)));
45 } else if (c > 127) {
46 // Write octal format
47 stringBuffer.append("\\u");
48
49 int z = (c >> 12);
50 stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z)));
51 z = ((c >> 8) & 0xF);
52 stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z)));
53 z = ((c >> 4) & 0xF);
54 stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z)));
55 z = (c & 0xF);
56 stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z)));
57 } else {
58 stringBuffer.append(c);
59 }
60 }
61 } else {
62 stringBuffer.append(s);
63 }
64 }
65
66 // --- Printer --- //
67 @Override
68 public void start(int maxLineNumber, int majorVersion, int minorVersion) {
69 this.stringBuffer.setLength(0);
70 this.majorVersion = majorVersion;
71 this.minorVersion = minorVersion;
72 this.indentationCount = 0;
73 }
74
75 @Override public void end() {}
76
77 @Override public void printText(String text) { escape(text); }
78 @Override public void printNumericConstant(String constant) { escape(constant); }
79 @Override public void printStringConstant(String constant, String ownerInternalName) { escape(constant); }
80 @Override public void printKeyword(String keyword) { stringBuffer.append(keyword); }
81
82 @Override public void printDeclaration(int type, String internalTypeName, String name, String descriptor) { escape(name); }
83 @Override public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) { escape(name); }
84
85 @Override public void indent() { indentationCount++; }
86 @Override public void unindent() { if (indentationCount > 0) indentationCount--; }
87
88 @Override public void startLine(int lineNumber) { for (int i=0; i<indentationCount; i++) stringBuffer.append(TAB); }
89 @Override public void endLine() { stringBuffer.append(NEWLINE); }
90 @Override public void extraLine(int count) { if (realignmentLineNumber) while (count-- > 0) stringBuffer.append(NEWLINE); }
91
92 @Override public void startMarker(int type) {}
93 @Override public void endMarker(int type) {}
94 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.exception;
8
9 public class ExceptionUtil {
10 public static boolean printStackTrace(Throwable throwable) {
11 throwable.printStackTrace();
12 return true;
13 }
14 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.index;
8
9 import org.jd.gui.api.model.Container;
10 import org.jd.gui.api.model.Indexes;
11 import org.jd.gui.util.exception.ExceptionUtil;
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.concurrent.Future;
18
19 public class IndexesUtil {
20 public static boolean containsInternalTypeName(Collection<Future<Indexes>> collectionOfFutureIndexes, String internalTypeName) {
21 return contains(collectionOfFutureIndexes, "typeDeclarations", internalTypeName);
22 }
23
24 @SuppressWarnings("unchecked")
25 public static List<Container.Entry> findInternalTypeName(Collection<Future<Indexes>> collectionOfFutureIndexes, String internalTypeName) {
26 return find(collectionOfFutureIndexes, "typeDeclarations", internalTypeName);
27 }
28
29 public static boolean contains(Collection<Future<Indexes>> collectionOfFutureIndexes, String indexName, String key) {
30 try {
31 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
32 if (futureIndexes.isDone()) {
33 Map<String, Collection> index = futureIndexes.get().getIndex(indexName);
34 if ((index != null) && (index.get(key) != null)) {
35 return true;
36 }
37 }
38 }
39 } catch (Exception e) {
40 assert ExceptionUtil.printStackTrace(e);
41 }
42
43 return false;
44 }
45
46 @SuppressWarnings("unchecked")
47 public static List<Container.Entry> find(Collection<Future<Indexes>> collectionOfFutureIndexes, String indexName, String key) {
48 ArrayList<Container.Entry> entries = new ArrayList<>();
49
50 try {
51 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
52 if (futureIndexes.isDone()) {
53 Map<String, Collection> index = futureIndexes.get().getIndex(indexName);
54 if (index != null) {
55 Collection<Container.Entry> collection = index.get(key);
56 if (collection != null) {
57 entries.addAll(collection);
58 }
59 }
60 }
61 }
62 } catch (Exception e) {
63 assert ExceptionUtil.printStackTrace(e);
64 }
65
66 return entries;
67 }
68 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.io;
8
9 import java.io.FilterOutputStream;
10 import java.io.IOException;
11 import java.io.OutputStream;
12 import java.nio.charset.Charset;
13
14 public class NewlineOutputStream extends FilterOutputStream {
15 private static byte[] lineSeparator;
16
17 public NewlineOutputStream(OutputStream os) {
18 super(os);
19
20 if (lineSeparator == null) {
21 String s = System.getProperty("line.separator");
22
23 if ((s == null) || (s.length() <= 0))
24 s = "\n";
25
26 lineSeparator = s.getBytes(Charset.forName("UTF-8"));
27 }
28 }
29
30 public void write(int b) throws IOException {
31 if (b == '\n') {
32 out.write(lineSeparator);
33 } else {
34 out.write(b);
35 }
36 }
37
38 public void write(byte b[]) throws IOException {
39 write(b, 0, b.length);
40 }
41
42 public void write(byte b[], int off, int len) throws IOException {
43 int i;
44
45 for (i=off; i<len; i++) {
46 if (b[i] == '\n') {
47 out.write(b, off, i-off);
48 out.write(lineSeparator);
49 off = i+1;
50 }
51 }
52
53 out.write(b, off, i-off);
54 }
55 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.io;
8
9 import org.jd.gui.util.exception.ExceptionUtil;
10
11 import java.io.*;
12
13 public class TextReader {
14
15 public static String getText(File file) {
16 try {
17 return getText(new FileInputStream(file));
18 } catch (IOException e) {
19 assert ExceptionUtil.printStackTrace(e);
20 return "";
21 }
22 }
23
24 public static String getText(InputStream is) {
25 StringBuilder sb = new StringBuilder();
26 char[] charBuffer = new char[8192];
27 int nbCharRead;
28
29 try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
30 while ((nbCharRead = reader.read(charBuffer)) != -1) {
31 // appends buffer
32 sb.append(charBuffer, 0, nbCharRead);
33 }
34 } catch (IOException e) {
35 assert ExceptionUtil.printStackTrace(e);
36 }
37
38 return sb.toString();
39 }
40 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.matcher;
8
9 /*
10 * Descriptor format : @see jd.gui.api.feature.UriOpenable
11 */
12 public class DescriptorMatcher {
13
14 public static boolean matchFieldDescriptors(String d1, String d2) {
15 return matchDescriptors(new CharBuffer(d1), new CharBuffer(d2));
16 }
17
18 protected static boolean matchDescriptors(CharBuffer cb1, CharBuffer cb2) {
19 if (cb1.read() == '?') {
20 if (cb2.read() == '?') {
21 return true;
22 } else {
23 cb2.unread();
24 return cb2.skipType();
25 }
26 } else {
27 cb1.unread();
28
29 if (cb2.read() == '?') {
30 return cb1.skipType();
31 } else {
32 cb2.unread();
33 return cb1.compareTypeWith(cb2);
34 }
35 }
36 }
37
38 public static boolean matchMethodDescriptors(String d1, String d2) {
39 CharBuffer cb1 = new CharBuffer(d1);
40 CharBuffer cb2 = new CharBuffer(d2);
41
42 if ((cb1.read() != '(') || (cb2.read() != '('))
43 return false;
44
45 if (cb1.read() == '*') {
46 return true;
47 }
48 if (cb2.read() == '*') {
49 return true;
50 }
51
52 cb1.unread();
53 cb2.unread();
54
55 // Check parameter descriptors
56 while (cb2.get() != ')') {
57 if (!matchDescriptors(cb1, cb2))
58 return false;
59 }
60
61 if ((cb1.read() != ')') || (cb2.read() != ')'))
62 return false;
63
64 // Check return descriptor
65 return matchDescriptors(cb1, cb2);
66 }
67
68 protected static class CharBuffer {
69 protected char[] buffer;
70 protected int length;
71 protected int offset;
72
73 public CharBuffer(String s) {
74 this.buffer = s.toCharArray();
75 this.length = buffer.length;
76 this.offset = 0;
77 }
78
79 public char read() {
80 if (offset < length)
81 return buffer[offset++];
82 else
83 return (char)0;
84 }
85
86 public boolean unread() {
87 if (offset > 0) {
88 offset--;
89 return true;
90 } else {
91 return false;
92 }
93 }
94
95 public char get() {
96 if (offset < length)
97 return buffer[offset];
98 else
99 return (char)0;
100 }
101
102 public boolean skipType() {
103 if (offset < length) {
104 char c = buffer[offset++];
105
106 while ((c == '[') && (offset < length)) {
107 c = buffer[offset++];
108 }
109
110 if (c == 'L') {
111 while (offset < length) {
112 if (buffer[offset++] == ';')
113 return true;
114 }
115 } else if (c != '[') {
116 return true;
117 }
118 }
119 return false;
120 }
121
122 public boolean compareTypeWith(CharBuffer other) {
123 if (offset >= length)
124 return false;
125
126 char c = buffer[offset++];
127
128 if (c != other.read())
129 return false;
130
131 if (c == 'L') {
132 if ((offset >= length) || (other.offset >= other.length))
133 return false;
134
135 char[] otherBuffer = other.buffer;
136
137 if ((buffer[offset] == '*') || (otherBuffer[other.offset] == '*')) {
138 int start = offset;
139 int otherStart = other.offset;
140
141 // Search ';'
142 if (!searchEndOfType() || !other.searchEndOfType())
143 return false;
144
145 int current = offset - 1;
146 int otherCurrent = other.offset - 1;
147
148 // Backward comparison
149 while ((start < current) && (otherStart < otherCurrent)) {
150 c = buffer[--current];
151 if (c == '*')
152 return true;
153
154 char otherC = otherBuffer[--otherCurrent];
155 if (otherC == '*')
156 return true;
157 if (c != otherC)
158 return false;
159 }
160 } else {
161 // Forward comparison
162 while (offset < length) {
163 c = buffer[offset++];
164 if (c != other.read())
165 return false;
166 if (c == ';')
167 return true;
168 }
169 return false;
170 }
171 }
172
173 return true;
174 }
175
176 protected boolean searchEndOfType() {
177 while (offset < length) {
178 if (buffer[offset++] == ';')
179 return true;
180 }
181 return false;
182 }
183
184 public String toString() {
185 return new String(buffer, offset, length-offset);
186 }
187 }
188 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.parser.antlr;
8
9 import org.antlr.v4.runtime.CharStream;
10 import org.antlr.v4.runtime.CommonTokenStream;
11 import org.antlr.v4.runtime.tree.ParseTree;
12 import org.antlr.v4.runtime.tree.ParseTreeWalker;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 public class ANTLRJavaParser {
16 public static void parse(CharStream input, JavaListener listener) {
17 try {
18 JavaLexer lexer = new JavaLexer(input);
19
20 lexer.removeErrorListeners();
21
22 CommonTokenStream tokens = new CommonTokenStream(lexer);
23 JavaParser parser = new JavaParser(tokens);
24
25 parser.removeErrorListeners();
26
27 ParseTree tree = parser.compilationUnit();
28
29 ParseTreeWalker.DEFAULT.walk(listener, tree);
30 } catch (StackOverflowError e) {
31 // Too complex source file, probably not written by a human.
32 // This error may happen on Java file generated by ANTLR for example.
33 assert ExceptionUtil.printStackTrace(e);
34 }
35 }
36 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.parser.antlr;
8
9 import org.antlr.v4.runtime.tree.ParseTree;
10 import org.antlr.v4.runtime.tree.TerminalNode;
11 import org.antlr.v4.runtime.tree.TerminalNodeImpl;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import java.util.HashMap;
16 import java.util.List;
17
18 public abstract class AbstractJavaListener extends JavaBaseListener {
19 protected Container.Entry entry;
20 protected String packageName = "";
21 protected HashMap<String, String> nameToInternalTypeName = new HashMap<>();
22 protected StringBuilder sb = new StringBuilder();
23 protected HashMap<String, String> typeNameCache = new HashMap<>();
24
25 public AbstractJavaListener(Container.Entry entry) {
26 this.entry = entry;
27 }
28
29 public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
30 packageName = concatIdentifiers(ctx.qualifiedName().Identifier());
31 }
32
33 public void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
34 List<TerminalNode> identifiers = ctx.qualifiedName().Identifier();
35 int size = identifiers.size();
36
37 if (size > 1) {
38 nameToInternalTypeName.put(identifiers.get(size - 1).getText(), concatIdentifiers(identifiers));
39 }
40 }
41
42 protected String concatIdentifiers(List<TerminalNode> identifiers) {
43 switch (identifiers.size()) {
44 case 0:
45 return "";
46 case 1:
47 return identifiers.get(0).getText();
48 default:
49 sb.setLength(0);
50
51 for (TerminalNode identifier : identifiers) {
52 sb.append(identifier.getText()).append('/');
53 }
54
55 // Remove last separator
56 sb.setLength(sb.length() - 1);
57
58 return sb.toString();
59 }
60 }
61
62 protected String resolveInternalTypeName(List<TerminalNode> identifiers) {
63 switch (identifiers.size()) {
64 case 0:
65 return null;
66
67 case 1:
68 // Search in cache
69 String name = identifiers.get(0).getText();
70 String qualifiedName = typeNameCache.get(name);
71
72 if (qualifiedName != null) {
73 return qualifiedName;
74 }
75
76 // Search in imports
77 String imp = nameToInternalTypeName.get(name);
78
79 if (imp != null) {
80 // Import found
81 return imp;
82 }
83
84 // Search type in same package
85 String prefix = name + '.';
86
87 if (entry.getPath().indexOf('/') != -1) {
88 // Not in root package
89 Container.Entry parent = entry.getParent();
90 int packageLength = parent.getPath().length() + 1;
91
92 for (Container.Entry child : parent.getChildren()) {
93 if (!child.isDirectory() && child.getPath().substring(packageLength).startsWith(prefix)) {
94 qualifiedName = packageName + '/' + name;
95 typeNameCache.put(name, qualifiedName);
96 return qualifiedName;
97 }
98 }
99 }
100
101 // Search type in root package
102 for (Container.Entry child : entry.getContainer().getRoot().getChildren()) {
103 if (!child.isDirectory() && child.getPath().startsWith(prefix)) {
104 typeNameCache.put(name, name);
105 return name;
106 }
107 }
108
109 // Search type in 'java.lang'
110 try {
111 if (Class.forName("java.lang." + name) != null) {
112 qualifiedName = "java/lang/" + name;
113 typeNameCache.put(name, qualifiedName);
114 return qualifiedName;
115 }
116 } catch (ClassNotFoundException ignore) {
117 // Ignore class loading error
118 }
119
120 // Type not found
121 qualifiedName = "*/" + name;
122 typeNameCache.put(name, qualifiedName);
123 return qualifiedName;
124
125 default:
126 // Qualified type name -> Nothing to do
127 return concatIdentifiers(identifiers);
128 }
129 }
130
131 protected String createDescriptor(JavaParser.TypeContext typeContext, int dimension) {
132 if (typeContext == null) {
133 return "V";
134 } else {
135 dimension += countDimension(typeContext.children);
136 JavaParser.PrimitiveTypeContext primitive = typeContext.primitiveType();
137 String name;
138
139 if (primitive == null) {
140 JavaParser.ClassOrInterfaceTypeContext type = typeContext.classOrInterfaceType();
141 List<JavaParser.TypeArgumentsContext> typeArgumentsContexts = type.typeArguments();
142
143 if (typeArgumentsContexts.size() == 1) {
144 JavaParser.TypeArgumentsContext typeArgumentsContext = typeArgumentsContexts.get(0);
145 List<JavaParser.TypeArgumentContext> typeArguments = typeArgumentsContext.typeArgument();
146 } else if (typeArgumentsContexts.size() > 1) {
147 throw new RuntimeException("UNEXPECTED");
148 }
149
150 name = "L" + resolveInternalTypeName(type.Identifier()) + ";";
151 } else {
152 // Search primitive
153 switch (primitive.getText()) {
154 case "boolean": name = "Z"; break;
155 case "byte": name = "B"; break;
156 case "char": name = "C"; break;
157 case "double": name = "D"; break;
158 case "float": name = "F"; break;
159 case "int": name = "I"; break;
160 case "long": name = "J"; break;
161 case "short": name = "S"; break;
162 case "void": name = "V"; break;
163 default:
164 throw new RuntimeException("UNEXPECTED PRIMITIVE");
165 }
166 }
167
168 switch (dimension) {
169 case 0: return name;
170 case 1: return "[" + name;
171 case 2: return "[[" + name;
172 default: return new String(new char[dimension]).replace('\0', '[') + name;
173 }
174 }
175 }
176
177 protected int countDimension(List<ParseTree> children) {
178 int dimension = 0;
179
180 for (ParseTree child : children) {
181 if (child instanceof TerminalNodeImpl) {
182 if (((TerminalNodeImpl)child).getSymbol().getType() == JavaParser.LBRACK)
183 dimension++;
184 }
185 }
186
187 return dimension;
188 }
189 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.util.xml;
8
9 import org.jd.gui.util.exception.ExceptionUtil;
10
11 import javax.xml.stream.XMLInputFactory;
12 import javax.xml.stream.XMLStreamException;
13 import javax.xml.stream.XMLStreamReader;
14 import java.io.StringReader;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.HashSet;
18
19 public abstract class AbstractXmlPathFinder {
20 protected HashMap<String, HashSet<String>> tagNameToPaths = new HashMap<>();
21 protected StringBuilder sb = new StringBuilder(200);
22
23 public AbstractXmlPathFinder(Collection<String> paths) {
24 for (String path : paths) {
25 if ((path != null) && (path.length() > 0)) {
26 // Normalize path
27 path = '/' + path;
28 int lastIndex = path.lastIndexOf('/');
29 String lastTagName = path.substring(lastIndex+1);
30
31 // Add tag names to map
32 HashSet<String> setOfPaths = tagNameToPaths.get(lastTagName);
33 if (setOfPaths == null) {
34 tagNameToPaths.put(lastTagName, setOfPaths = new HashSet<>());
35 }
36 setOfPaths.add(path);
37 }
38 }
39 }
40
41 public void find(String text) {
42 sb.setLength(0);
43
44 try {
45 XMLInputFactory factory = XMLInputFactory.newInstance();
46 XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(text));
47
48 String tagName = "";
49 int offset = 0;
50
51 while (reader.hasNext()) {
52 reader.next();
53
54 switch (reader.getEventType())
55 {
56 case XMLStreamReader.START_ELEMENT:
57 sb.append('/').append(tagName = reader.getLocalName());
58 offset = reader.getLocation().getCharacterOffset();
59 break;
60 case XMLStreamReader.END_ELEMENT:
61 sb.setLength(sb.length() - reader.getLocalName().length() - 1);
62 break;
63 case XMLStreamReader.CHARACTERS:
64 HashSet<String> setOfPaths = tagNameToPaths.get(tagName);
65
66 if (setOfPaths != null) {
67 String path = sb.toString();
68
69 if (setOfPaths.contains(path)) {
70 // Search start offset
71 while (offset > 0) {
72 if (text.charAt(offset) == '>') {
73 break;
74 } else {
75 offset--;
76 }
77 }
78
79 handle(path.substring(1), reader.getText(), offset+1);
80 }
81 }
82 break;
83 }
84 }
85 } catch (XMLStreamException e) {
86 assert ExceptionUtil.printStackTrace(e);
87 }
88 }
89
90 public abstract void handle(String path, String text, int position);
91 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.*;
10 import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
11 import org.fife.ui.rtextarea.*;
12 import org.jd.gui.api.feature.ContentSearchable;
13 import org.jd.gui.api.feature.LineNumberNavigable;
14 import org.jd.gui.api.feature.PreferencesChangeListener;
15 import org.jd.gui.api.feature.UriOpenable;
16 import org.jd.gui.util.exception.ExceptionUtil;
17
18 import javax.swing.*;
19 import javax.swing.text.BadLocationException;
20 import java.awt.*;
21 import java.awt.event.KeyEvent;
22 import java.awt.event.MouseAdapter;
23 import java.awt.event.MouseEvent;
24 import java.awt.event.MouseWheelListener;
25 import java.io.IOException;
26 import java.io.UnsupportedEncodingException;
27 import java.net.URI;
28 import java.net.URLDecoder;
29 import java.util.HashMap;
30 import java.util.Map;
31
32 public class AbstractTextPage extends JPanel implements LineNumberNavigable, ContentSearchable, UriOpenable, PreferencesChangeListener {
33 protected static final String FONT_SIZE_KEY = "ViewerPreferences.fontSize";
34
35 protected static final ImageIcon COLLAPSED_ICON = new ImageIcon(AbstractTextPage.class.getClassLoader().getResource("org/jd/gui/images/plus.png"));
36 protected static final ImageIcon EXPANDED_ICON = new ImageIcon(AbstractTextPage.class.getClassLoader().getResource("org/jd/gui/images/minus.png"));
37
38 protected static final Color DOUBLE_CLICK_HIGHLIGHT_COLOR = new Color(0x66ff66);
39 protected static final Color SEARCH_HIGHLIGHT_COLOR = new Color(0xffff66);
40 protected static final Color SELECT_HIGHLIGHT_COLOR = new Color(0xF49810);
41
42 protected static final RSyntaxTextAreaEditorKit.DecreaseFontSizeAction DECREASE_FONT_SIZE_ACTION = new RSyntaxTextAreaEditorKit.DecreaseFontSizeAction();
43 protected static final RSyntaxTextAreaEditorKit.IncreaseFontSizeAction INCREASE_FONT_SIZE_ACTION = new RSyntaxTextAreaEditorKit.IncreaseFontSizeAction();
44
45 protected RSyntaxTextArea textArea;
46 protected RTextScrollPane scrollPane;
47
48 protected Map<String, String> preferences;
49
50 public AbstractTextPage() {
51 super(new BorderLayout());
52
53 textArea = newSyntaxTextArea();
54 textArea.setSyntaxEditingStyle(getSyntaxStyle());
55 textArea.setCodeFoldingEnabled(true);
56 textArea.setAntiAliasingEnabled(true);
57 textArea.setCaretPosition(0);
58 textArea.setEditable(false);
59 textArea.setDropTarget(null);
60 textArea.setPopupMenu(null);
61 textArea.addMouseListener(new MouseAdapter() {
62 public void mouseClicked(MouseEvent e) {
63 if (e.getClickCount() == 2) {
64 textArea.setMarkAllHighlightColor(DOUBLE_CLICK_HIGHLIGHT_COLOR);
65 SearchEngine.markAll(textArea, newSearchContext(textArea.getSelectedText(), true, true, true, false));
66 }
67 }
68 });
69
70 KeyStroke ctrlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
71 KeyStroke ctrlC = KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
72 KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
73 InputMap inputMap = textArea.getInputMap();
74 inputMap.put(ctrlA, "none");
75 inputMap.put(ctrlC, "none");
76 inputMap.put(ctrlV, "none");
77
78 try {
79 Theme theme = Theme.load(getClass().getClassLoader().getResourceAsStream("rsyntaxtextarea/themes/eclipse.xml"));
80 theme.apply(textArea);
81 } catch (IOException e) {
82 assert ExceptionUtil.printStackTrace(e);
83 }
84
85 scrollPane = new RTextScrollPane(textArea);
86 scrollPane.setFoldIndicatorEnabled(true);
87 scrollPane.setFont(textArea.getFont());
88
89 final MouseWheelListener[] mouseWheelListeners = scrollPane.getMouseWheelListeners();
90
91 // Remove default listeners
92 for (MouseWheelListener listener : mouseWheelListeners) {
93 scrollPane.removeMouseWheelListener(listener);
94 }
95
96 scrollPane.addMouseWheelListener(e -> {
97 if ((e.getModifiers() & (Event.META_MASK|Event.CTRL_MASK)) != 0) {
98 int x = e.getX() + scrollPane.getX() - textArea.getX();
99 int y = e.getY() + scrollPane.getY() - textArea.getY();
100 int offset = textArea.viewToModel(new Point(x, y));
101
102 // Update font size
103 if (e.getWheelRotation() > 0) {
104 DECREASE_FONT_SIZE_ACTION.actionPerformedImpl(null, textArea);
105 } else {
106 INCREASE_FONT_SIZE_ACTION.actionPerformedImpl(null, textArea);
107 }
108
109 // Save preferences
110 if (preferences != null) {
111 preferences.put(FONT_SIZE_KEY, String.valueOf(textArea.getFont().getSize()));
112 }
113
114 try {
115 Rectangle newRectangle = textArea.modelToView(offset);
116 int newY = newRectangle.y + (newRectangle.height >> 1);
117
118 // Scroll
119 Point viewPosition = scrollPane.getViewport().getViewPosition();
120 viewPosition.y = Math.max(viewPosition.y +newY - y, 0);
121 scrollPane.getViewport().setViewPosition(viewPosition);
122 } catch (BadLocationException ee) {
123 assert ExceptionUtil.printStackTrace(ee);
124 }
125 } else {
126 // Call default listeners
127 for (MouseWheelListener listener : mouseWheelListeners) {
128 listener.mouseWheelMoved(e);
129 }
130 }
131 });
132
133 Gutter gutter = scrollPane.getGutter();
134 gutter.setFoldIcons(COLLAPSED_ICON, EXPANDED_ICON);
135 gutter.setFoldIndicatorForeground(gutter.getBorderColor());
136
137 add(scrollPane, BorderLayout.CENTER);
138 add(new RoundMarkErrorStrip(textArea), BorderLayout.LINE_END);
139 }
140
141 protected RSyntaxTextArea newSyntaxTextArea() { return new RSyntaxTextArea(); }
142
143 public String getText() { return textArea.getText(); }
144
145 public JScrollPane getScrollPane() {
146 return scrollPane;
147 }
148
149 public void setText(String text) {
150 textArea.setText(text);
151 textArea.setCaretPosition(0);
152 }
153
154 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_NONE; }
155
156 /**
157 * @see org.fife.ui.rsyntaxtextarea.RSyntaxUtilities#selectAndPossiblyCenter
158 * Force center and do not select
159 */
160 public void setCaretPositionAndCenter(DocumentRange range) {
161 final int start = range.getStartOffset();
162 final int end = range.getEndOffset();
163 boolean foldsExpanded = false;
164 FoldManager fm = textArea.getFoldManager();
165
166 if (fm.isCodeFoldingSupportedAndEnabled()) {
167 foldsExpanded = fm.ensureOffsetNotInClosedFold(start);
168 foldsExpanded |= fm.ensureOffsetNotInClosedFold(end);
169 }
170
171 if (!foldsExpanded) {
172 try {
173 Rectangle rec = textArea.modelToView(start);
174
175 if (rec != null) {
176 // Visible
177 setCaretPositionAndCenter(start, end, rec);
178 } else {
179 // Not visible yet
180 SwingUtilities.invokeLater(() -> {
181 try {
182 Rectangle r = textArea.modelToView(start);
183 if (r != null) {
184 setCaretPositionAndCenter(start, end, r);
185 }
186 } catch (BadLocationException e) {
187 assert ExceptionUtil.printStackTrace(e);
188 }
189 });
190 }
191 } catch (BadLocationException e) {
192 assert ExceptionUtil.printStackTrace(e);
193 }
194 }
195 }
196
197 protected void setCaretPositionAndCenter(int start, int end, Rectangle r) {
198 if (end != start) {
199 try {
200 r = r.union(textArea.modelToView(end));
201 } catch (BadLocationException e) {
202 assert ExceptionUtil.printStackTrace(e);
203 }
204 }
205
206 Rectangle visible = textArea.getVisibleRect();
207
208 // visible.x = r.x - (visible.width - r.width) / 2;
209 visible.y = r.y - (visible.height - r.height) / 2;
210
211 Rectangle bounds = textArea.getBounds();
212 Insets i = textArea.getInsets();
213 //bounds.x = i.left;
214 bounds.y = i.top;
215 //bounds.width -= i.left + i.right;
216 bounds.height -= i.top + i.bottom;
217
218 //if (visible.x < bounds.x) {
219 // visible.x = bounds.x;
220 //}
221 //if (visible.x + visible.width > bounds.x + bounds.width) {
222 // visible.x = bounds.x + bounds.width - visible.width;
223 //}
224 if (visible.y < bounds.y) {
225 visible.y = bounds.y;
226 }
227 if (visible.y + visible.height > bounds.y + bounds.height) {
228 visible.y = bounds.y + bounds.height - visible.height;
229 }
230
231 textArea.scrollRectToVisible(visible);
232 textArea.setCaretPosition(start);
233 }
234
235 // --- LineNumberNavigable --- //
236 public int getMaximumLineNumber() {
237 try {
238 return textArea.getLineOfOffset(textArea.getDocument().getLength()) + 1;
239 } catch (BadLocationException e) {
240 assert ExceptionUtil.printStackTrace(e);
241 return 0;
242 }
243 }
244
245 public void goToLineNumber(int lineNumber) {
246 try {
247 textArea.setCaretPosition(textArea.getLineStartOffset(lineNumber-1));
248 } catch (BadLocationException e) {
249 assert ExceptionUtil.printStackTrace(e);
250 }
251 }
252
253 public boolean checkLineNumber(int lineNumber) { return true; }
254
255 // --- ContentSearchable --- //
256 public boolean highlightText(String text, boolean caseSensitive) {
257 if (text.length() > 1) {
258 textArea.setMarkAllHighlightColor(SEARCH_HIGHLIGHT_COLOR);
259 textArea.setCaretPosition(textArea.getSelectionStart());
260
261 SearchContext context = newSearchContext(text, caseSensitive, false, true, false);
262 SearchResult result = SearchEngine.find(textArea, context);
263
264 if (!result.wasFound()) {
265 textArea.setCaretPosition(0);
266 result = SearchEngine.find(textArea, context);
267 }
268
269 return result.wasFound();
270 } else {
271 return true;
272 }
273 }
274
275 public void findNext(String text, boolean caseSensitive) {
276 if (text.length() > 1) {
277 textArea.setMarkAllHighlightColor(SEARCH_HIGHLIGHT_COLOR);
278
279 SearchContext context = newSearchContext(text, caseSensitive, false, true, false);
280 SearchResult result = SearchEngine.find(textArea, context);
281
282 if (!result.wasFound()) {
283 textArea.setCaretPosition(0);
284 SearchEngine.find(textArea, context);
285 }
286 }
287 }
288
289 public void findPrevious(String text, boolean caseSensitive) {
290 if (text.length() > 1) {
291 textArea.setMarkAllHighlightColor(SEARCH_HIGHLIGHT_COLOR);
292
293 SearchContext context = newSearchContext(text, caseSensitive, false, false, false);
294 SearchResult result = SearchEngine.find(textArea, context);
295
296 if (!result.wasFound()) {
297 textArea.setCaretPosition(textArea.getDocument().getLength());
298 SearchEngine.find(textArea, context);
299 }
300 }
301 }
302
303 protected SearchContext newSearchContext(String searchFor, boolean matchCase, boolean wholeWord, boolean searchForward, boolean regexp) {
304 SearchContext context = new SearchContext(searchFor, matchCase);
305 context.setMarkAll(true);
306 context.setWholeWord(wholeWord);
307 context.setSearchForward(searchForward);
308 context.setRegularExpression(regexp);
309 return context;
310 }
311
312 // --- UriOpenable --- //
313 public boolean openUri(URI uri) {
314 String query = uri.getQuery();
315
316 if (query != null) {
317 Map<String, String> parameters = parseQuery(query);
318
319 if (parameters.containsKey("lineNumber")) {
320 String lineNumber = parameters.get("lineNumber");
321
322 try {
323 goToLineNumber(Integer.parseInt(lineNumber));
324 return true;
325 } catch (NumberFormatException e) {
326 assert ExceptionUtil.printStackTrace(e);
327 }
328 } else if (parameters.containsKey("position")) {
329 String position = parameters.get("position");
330
331 try {
332 int pos = Integer.parseInt(position);
333 if (textArea.getDocument().getLength() > pos) {
334 setCaretPositionAndCenter(new DocumentRange(pos, pos));
335 return true;
336 }
337 } catch (NumberFormatException e) {
338 assert ExceptionUtil.printStackTrace(e);
339 }
340 } else if (parameters.containsKey("highlightFlags")) {
341 String highlightFlags = parameters.get("highlightFlags");
342
343 if ((highlightFlags.indexOf('s') != -1) && parameters.containsKey("highlightPattern")) {
344 textArea.setMarkAllHighlightColor(SELECT_HIGHLIGHT_COLOR);
345 textArea.setCaretPosition(0);
346
347 // Highlight all
348 String searchFor = createRegExp(parameters.get("highlightPattern"));
349 SearchContext context = newSearchContext(searchFor, true, false, true, true);
350 SearchResult result = SearchEngine.find(textArea, context);
351
352 if (result.getMatchRange() != null) {
353 textArea.setCaretPosition(result.getMatchRange().getStartOffset());
354 }
355
356 return true;
357 }
358 }
359 }
360
361 return false;
362 }
363
364 protected Map<String, String> parseQuery(String query) {
365 HashMap<String, String> parameters = new HashMap<>();
366
367 // Parse parameters
368 try {
369 for (String param : query.split("&")) {
370 int index = param.indexOf('=');
371
372 if (index == -1) {
373 parameters.put(URLDecoder.decode(param, "UTF-8"), "");
374 } else {
375 String key = param.substring(0, index);
376 String value = param.substring(index + 1);
377 parameters.put(URLDecoder.decode(key, "UTF-8"), URLDecoder.decode(value, "UTF-8"));
378 }
379 }
380 } catch (UnsupportedEncodingException e) {
381 assert ExceptionUtil.printStackTrace(e);
382 }
383
384 return parameters;
385 }
386
387 /**
388 * Create a simple regular expression
389 *
390 * Rules:
391 * '*' matchTypeEntries 0 ou N characters
392 * '?' matchTypeEntries 1 character
393 */
394 public static String createRegExp(String pattern) {
395 int patternLength = pattern.length();
396 StringBuilder sbPattern = new StringBuilder(patternLength * 2);
397
398 for (int i = 0; i < patternLength; i++) {
399 char c = pattern.charAt(i);
400
401 if (c == '*') {
402 sbPattern.append(".*");
403 } else if (c == '?') {
404 sbPattern.append('.');
405 } else if (c == '.') {
406 sbPattern.append("\\.");
407 } else {
408 sbPattern.append(c);
409 }
410 }
411
412 return sbPattern.toString();
413 }
414
415 // --- PreferencesChangeListener --- //
416 public void preferencesChanged(Map<String, String> preferences) {
417 String fontSize = preferences.get(FONT_SIZE_KEY);
418
419 if (fontSize != null) {
420 try {
421 textArea.setFont(textArea.getFont().deriveFont(Float.parseFloat(fontSize)));
422 } catch (Exception e) {
423 assert ExceptionUtil.printStackTrace(e);
424 }
425 }
426
427 this.preferences = preferences;
428 }
429 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.DocumentRange;
10 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
11 import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
12 import org.jd.gui.api.API;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.util.decompiler.*;
15 import org.jd.gui.util.exception.ExceptionUtil;
16 import org.jd.gui.util.io.NewlineOutputStream;
17
18 import javax.swing.text.BadLocationException;
19 import javax.swing.text.DefaultCaret;
20 import java.awt.*;
21 import java.io.*;
22 import java.nio.charset.Charset;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 public class ClassFilePage extends TypePage {
27 protected static final String ESCAPE_UNICODE_CHARACTERS = "ClassFileDecompilerPreferences.escapeUnicodeCharacters";
28 protected static final String REALIGN_LINE_NUMBERS = "ClassFileDecompilerPreferences.realignLineNumbers";
29 protected static final String WRITE_LINE_NUMBERS = "ClassFileSaverPreferences.writeLineNumbers";
30 protected static final String WRITE_METADATA = "ClassFileSaverPreferences.writeMetadata";
31 protected static final String JD_CORE_VERSION = "JdGuiPreferences.jdCoreVersion";
32
33 protected static final ClassFileToJavaSourceDecompiler DECOMPILER = new ClassFileToJavaSourceDecompiler();
34
35 protected int maximumLineNumber = -1;
36
37 static {
38 // Early class loading
39 try {
40 String internalTypeName = ClassFilePage.class.getName().replace('.', '/');
41 DECOMPILER.decompile(new ClassPathLoader(), new NopPrinter(), internalTypeName);
42 } catch (Throwable t) {
43 assert ExceptionUtil.printStackTrace(t);
44 }
45 }
46
47 public ClassFilePage(API api, Container.Entry entry) {
48 super(api, entry);
49 Map<String, String> preferences = api.getPreferences();
50 // Init view
51 setErrorForeground(Color.decode(preferences.get("JdGuiPreferences.errorBackgroundColor")));
52 // Display source
53 decompile(preferences);
54 }
55
56 public void decompile(Map<String, String> preferences) {
57 try {
58 // Clear ...
59 clearHyperlinks();
60 clearLineNumbers();
61 declarations.clear();
62 typeDeclarations.clear();
63 strings.clear();
64
65 // Init preferences
66 boolean realignmentLineNumbers = getPreferenceValue(preferences, REALIGN_LINE_NUMBERS, false);
67 boolean unicodeEscape = getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false);
68
69 Map<String, Object> configuration = new HashMap<>();
70 configuration.put("realignLineNumbers", realignmentLineNumbers);
71
72 setShowMisalignment(realignmentLineNumbers);
73
74 // Init loader
75 ContainerLoader loader = new ContainerLoader(entry);
76
77 // Init printer
78 ClassFilePrinter printer = new ClassFilePrinter();
79 printer.setRealignmentLineNumber(realignmentLineNumbers);
80 printer.setUnicodeEscape(unicodeEscape);
81
82 // Format internal name
83 String entryPath = entry.getPath();
84 assert entryPath.endsWith(".class");
85 String entryInternalName = entryPath.substring(0, entryPath.length() - 6); // 6 = ".class".length()
86
87 // Decompile class file
88 DECOMPILER.decompile(loader, printer, entryInternalName, configuration);
89 } catch (Throwable t) {
90 assert ExceptionUtil.printStackTrace(t);
91 setText("// INTERNAL ERROR //");
92 }
93
94 maximumLineNumber = getMaximumSourceLineNumber();
95 }
96
97 protected static boolean getPreferenceValue(Map<String, String> preferences, String key, boolean defaultValue) {
98 String v = preferences.get(key);
99 return (v == null) ? defaultValue : Boolean.valueOf(v);
100 }
101
102 @Override
103 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JAVA; }
104
105 // --- ContentSavable --- //
106 @Override
107 public String getFileName() {
108 String path = entry.getPath();
109 int index = path.lastIndexOf('.');
110 return path.substring(0, index) + ".java";
111 }
112
113 @Override
114 public void save(API api, OutputStream os) {
115 try {
116 // Init preferences
117 Map<String, String> preferences = api.getPreferences();
118 boolean realignmentLineNumbers = getPreferenceValue(preferences, REALIGN_LINE_NUMBERS, false);
119 boolean unicodeEscape = getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false);
120 boolean showLineNumbers = getPreferenceValue(preferences, WRITE_LINE_NUMBERS, true);
121
122 Map<String, Object> configuration = new HashMap<>();
123 configuration.put("realignLineNumbers", realignmentLineNumbers);
124
125 // Init loader
126 ContainerLoader loader = new ContainerLoader(entry);
127
128 // Init printer
129 LineNumberStringBuilderPrinter printer = new LineNumberStringBuilderPrinter();
130 printer.setRealignmentLineNumber(realignmentLineNumbers);
131 printer.setUnicodeEscape(unicodeEscape);
132 printer.setShowLineNumbers(showLineNumbers);
133
134 // Format internal name
135 String entryPath = entry.getPath();
136 assert entryPath.endsWith(".class");
137 String entryInternalName = entryPath.substring(0, entryPath.length() - 6); // 6 = ".class".length()
138
139 // Decompile class file
140 DECOMPILER.decompile(loader, printer, entryInternalName, configuration);
141
142 StringBuilder stringBuffer = printer.getStringBuffer();
143
144 // Metadata
145 if (getPreferenceValue(preferences, WRITE_METADATA, true)) {
146 // Add location
147 String location =
148 new File(entry.getUri()).getPath()
149 // Escape "\ u" sequence to prevent "Invalid unicode" errors
150 .replaceAll("(^|[^\\\\])\\\\u", "\\\\\\\\u");
151 stringBuffer.append("\n\n/* Location: ");
152 stringBuffer.append(location);
153 // Add Java compiler version
154 int majorVersion = printer.getMajorVersion();
155
156 if (majorVersion >= 45) {
157 stringBuffer.append("\n * Java compiler version: ");
158
159 if (majorVersion >= 49) {
160 stringBuffer.append(majorVersion - (49 - 5));
161 } else {
162 stringBuffer.append(majorVersion - (45 - 1));
163 }
164
165 stringBuffer.append(" (");
166 stringBuffer.append(majorVersion);
167 stringBuffer.append('.');
168 stringBuffer.append(printer.getMinorVersion());
169 stringBuffer.append(')');
170 }
171 // Add JD-Core version
172 stringBuffer.append("\n * JD-Core Version: ");
173 stringBuffer.append(preferences.get(JD_CORE_VERSION));
174 stringBuffer.append("\n */");
175 }
176
177 try (PrintStream ps = new PrintStream(new NewlineOutputStream(os), true, "UTF-8")) {
178 ps.print(stringBuffer.toString());
179 } catch (IOException e) {
180 assert ExceptionUtil.printStackTrace(e);
181 }
182 } catch (Throwable t) {
183 assert ExceptionUtil.printStackTrace(t);
184
185 try (OutputStreamWriter writer = new OutputStreamWriter(os, Charset.defaultCharset())) {
186 writer.write("// INTERNAL ERROR //");
187 } catch (IOException ee) {
188 assert ExceptionUtil.printStackTrace(ee);
189 }
190 }
191 }
192
193 // --- LineNumberNavigable --- //
194 @Override
195 public int getMaximumLineNumber() { return maximumLineNumber; }
196
197 @Override
198 public void goToLineNumber(int lineNumber) {
199 int textAreaLineNumber = getTextAreaLineNumber(lineNumber);
200 if (textAreaLineNumber > 0) {
201 try {
202 int start = textArea.getLineStartOffset(textAreaLineNumber - 1);
203 int end = textArea.getLineEndOffset(textAreaLineNumber - 1);
204 setCaretPositionAndCenter(new DocumentRange(start, end));
205 } catch (BadLocationException e) {
206 assert ExceptionUtil.printStackTrace(e);
207 }
208 }
209 }
210
211 @Override
212 public boolean checkLineNumber(int lineNumber) { return lineNumber <= maximumLineNumber; }
213
214 // --- PreferencesChangeListener --- //
215 @Override
216 public void preferencesChanged(Map<String, String> preferences) {
217 DefaultCaret caret = (DefaultCaret)textArea.getCaret();
218 int updatePolicy = caret.getUpdatePolicy();
219
220 caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
221 decompile(preferences);
222 caret.setUpdatePolicy(updatePolicy);
223
224 super.preferencesChanged(preferences);
225 }
226
227 public class ClassFilePrinter extends StringBuilderPrinter {
228 protected HashMap<String, ReferenceData> referencesCache = new HashMap<>();
229
230 // Manage line number and misalignment
231 int textAreaLineNumber = 1;
232
233 @Override
234 public void start(int maxLineNumber, int majorVersion, int minorVersion) {
235 super.start(maxLineNumber, majorVersion, minorVersion);
236
237 if (maxLineNumber == 0) {
238 scrollPane.setLineNumbersEnabled(false);
239 } else {
240 setMaxLineNumber(maxLineNumber);
241 }
242 }
243
244 @Override
245 public void end() {
246 setText(stringBuffer.toString());
247 }
248
249 // --- Add strings --- //
250 @Override
251 public void printStringConstant(String constant, String ownerInternalName) {
252 if (constant == null) constant = "null";
253 if (ownerInternalName == null) ownerInternalName = "null";
254
255 strings.add(new TypePage.StringData(stringBuffer.length(), constant.length(), constant, ownerInternalName));
256 super.printStringConstant(constant, ownerInternalName);
257 }
258
259 @Override
260 public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
261 if (internalTypeName == null) internalTypeName = "null";
262 if (name == null) name = "null";
263 if (descriptor == null) descriptor = "null";
264
265 switch (type) {
266 case TYPE:
267 TypePage.DeclarationData data = new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalTypeName, null, null);
268 declarations.put(internalTypeName, data);
269 typeDeclarations.put(stringBuffer.length(), data);
270 break;
271 case CONSTRUCTOR:
272 declarations.put(internalTypeName + "-<init>-" + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalTypeName, "<init>", descriptor));
273 break;
274 default:
275 declarations.put(internalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalTypeName, name, descriptor));
276 break;
277 }
278 super.printDeclaration(type, internalTypeName, name, descriptor);
279 }
280
281 @Override
282 public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) {
283 if (internalTypeName == null) internalTypeName = "null";
284 if (name == null) name = "null";
285 if (descriptor == null) descriptor = "null";
286
287 switch (type) {
288 case TYPE:
289 addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalTypeName, null, null, ownerInternalName)));
290 break;
291 case CONSTRUCTOR:
292 addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalTypeName, "<init>", descriptor, ownerInternalName)));
293 break;
294 default:
295 addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalTypeName, name, descriptor, ownerInternalName)));
296 break;
297 }
298 super.printReference(type, internalTypeName, name, descriptor, ownerInternalName);
299 }
300
301 @Override
302 public void startLine(int lineNumber) {
303 super.startLine(lineNumber);
304 setLineNumber(textAreaLineNumber, lineNumber);
305 }
306 @Override
307 public void endLine() {
308 super.endLine();
309 textAreaLineNumber++;
310 }
311 @Override
312 public void extraLine(int count) {
313 super.extraLine(count);
314 if (realignmentLineNumber) {
315 textAreaLineNumber += count;
316 }
317 }
318
319 // --- Add references --- //
320 public TypePage.ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
321 String key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName;
322 ReferenceData reference = referencesCache.get(key);
323
324 if (reference == null) {
325 reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName);
326 referencesCache.put(key, reference);
327 references.add(reference);
328 }
329
330 return reference;
331 }
332 }
333 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
10 import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;
11 import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI;
12 import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
13 import org.fife.ui.rsyntaxtextarea.folding.Fold;
14 import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
15 import org.fife.ui.rtextarea.Gutter;
16 import org.fife.ui.rtextarea.LineNumberList;
17 import org.fife.ui.rtextarea.RTextArea;
18 import org.fife.ui.rtextarea.RTextAreaUI;
19
20 import javax.swing.*;
21 import javax.swing.text.EditorKit;
22 import javax.swing.text.Element;
23 import javax.swing.text.JTextComponent;
24 import javax.swing.text.View;
25 import java.awt.*;
26 import java.util.Arrays;
27 import java.util.Map;
28
29 public abstract class CustomLineNumbersPage extends HyperlinkPage {
30 protected Color errorForeground = Color.RED;
31 protected boolean showMisalignment = true;
32
33 public void setErrorForeground(Color color) {
34 errorForeground = color;
35 }
36
37 public void setShowMisalignment(boolean b) {
38 showMisalignment = b;
39 }
40
41 /**
42 * Map[textarea line number] = original line number
43 */
44 protected int[] lineNumberMap = null;
45 protected int maxLineNumber = 0;
46
47 protected void setMaxLineNumber(int maxLineNumber) {
48 if (maxLineNumber > 0) {
49 if (lineNumberMap == null) {
50 lineNumberMap = new int[maxLineNumber+1];
51 } else if (lineNumberMap.length <= maxLineNumber) {
52 int[] tmp = new int[maxLineNumber+1];
53 System.arraycopy(lineNumberMap, 0, tmp, 0, lineNumberMap.length);
54 lineNumberMap = tmp;
55 }
56
57 this.maxLineNumber = maxLineNumber;
58 }
59 }
60
61 protected void initLineNumbers() {
62 String text = getText();
63 int len = text.length();
64
65 if (len == 0) {
66 setMaxLineNumber(0);
67 } else {
68 int mln = len - text.replace("\n", "").length();
69
70 if (text.charAt(len-1) != '\n') {
71 mln++;
72 }
73
74 setMaxLineNumber(mln);
75
76 for (int i=1; i<=maxLineNumber; i++) {
77 lineNumberMap[i] = i;
78 }
79 }
80 }
81
82 protected void setLineNumber(int textAreaLineNumber, int originalLineNumber) {
83 if (originalLineNumber > 0) {
84 setMaxLineNumber(textAreaLineNumber);
85 lineNumberMap[textAreaLineNumber] = originalLineNumber;
86 }
87 }
88
89 protected void clearLineNumbers() {
90 if (lineNumberMap != null) {
91 Arrays.fill(lineNumberMap, 0);
92 }
93 }
94
95 protected int getMaximumSourceLineNumber() { return maxLineNumber; }
96
97 protected int getTextAreaLineNumber(int originalLineNumber) {
98 int textAreaLineNumber = 1;
99 int greatestLowerSourceLineNumber = 0;
100 int i = lineNumberMap.length;
101
102 while (i-- > 0) {
103 int sln = lineNumberMap[i];
104 if (sln <= originalLineNumber) {
105 if (greatestLowerSourceLineNumber < sln) {
106 greatestLowerSourceLineNumber = sln;
107 textAreaLineNumber = i;
108 }
109 }
110 }
111
112 return textAreaLineNumber;
113 }
114
115 @Override protected RSyntaxTextArea newSyntaxTextArea() { return new SourceSyntaxTextArea(); }
116
117 public class SourceSyntaxTextArea extends HyperlinkSyntaxTextArea {
118 @Override protected RTextAreaUI createRTextAreaUI() { return new SourceSyntaxTextAreaUI(this); }
119 }
120
121 /**
122 * A lot of code to replace the default LineNumberList...
123 */
124 public class SourceSyntaxTextAreaUI extends RSyntaxTextAreaUI {
125 public SourceSyntaxTextAreaUI(JComponent rSyntaxTextArea) { super(rSyntaxTextArea); }
126 @Override public EditorKit getEditorKit(JTextComponent tc) { return new SourceSyntaxTextAreaEditorKit(); }
127 @Override public Rectangle getVisibleEditorRect() { return super.getVisibleEditorRect(); }
128 }
129
130 public class SourceSyntaxTextAreaEditorKit extends RSyntaxTextAreaEditorKit {
131 @Override public LineNumberList createLineNumberList(RTextArea textArea) { return new SourceLineNumberList(textArea); }
132 }
133
134 /**
135 * Why 'LineNumberList' is so unexpandable ? Too many private fields & methods and too many package scope.
136 */
137 public class SourceLineNumberList extends LineNumberList {
138 protected RTextArea rTextArea;
139 protected Map<?,?> aaHints;
140 protected Rectangle visibleRect;
141 protected Insets textAreaInsets;
142 protected Dimension preferredSize;
143
144 public SourceLineNumberList(RTextArea textArea) {
145 super(textArea, null);
146 this.rTextArea = textArea;
147 }
148
149 @Override
150 protected void init() {
151 super.init();
152 visibleRect = new Rectangle();
153 aaHints = RSyntaxUtilities.getDesktopAntiAliasHints();
154 textAreaInsets = null;
155 }
156
157 /**
158 * @see org.fife.ui.rtextarea.LineNumberList#paintComponent(java.awt.Graphics)
159 */
160 @Override
161 protected void paintComponent(Graphics g) {
162 visibleRect = g.getClipBounds(visibleRect);
163
164 if (visibleRect == null) {
165 visibleRect = getVisibleRect();
166 }
167 if (visibleRect == null) {
168 return;
169 }
170
171 int cellWidth = getPreferredSize().width;
172 int cellHeight = rTextArea.getLineHeight();
173 int ascent = rTextArea.getMaxAscent();
174 FoldManager fm = ((RSyntaxTextArea)rTextArea).getFoldManager();
175 int RHS_BORDER_WIDTH = getRhsBorderWidth();
176 FontMetrics metrics = g.getFontMetrics();
177 int rhs = getWidth() - RHS_BORDER_WIDTH;
178
179 if (getParent() instanceof Gutter) { // Should always be true
180 g.setColor(getParent().getBackground());
181 } else {
182 g.setColor(getBackground());
183 }
184
185 g.fillRect(0, visibleRect.y, cellWidth, visibleRect.height);
186 g.setFont(getFont());
187
188 if (aaHints != null) {
189 ((Graphics2D)g).addRenderingHints(aaHints);
190 }
191
192 if (rTextArea.getLineWrap()) {
193 SourceSyntaxTextAreaUI ui = (SourceSyntaxTextAreaUI)rTextArea.getUI();
194 View v = ui.getRootView(rTextArea).getView(0);
195 Element root = rTextArea.getDocument().getDefaultRootElement();
196 int lineCount = root.getElementCount();
197 int topPosition = rTextArea.viewToModel(visibleRect.getLocation());
198 int topLine = root.getElementIndex(topPosition);
199 Rectangle visibleEditorRect = ui.getVisibleEditorRect();
200 Rectangle r = LineNumberList.getChildViewBounds(v, topLine, visibleEditorRect);
201 int y = r.y;
202
203 int visibleBottom = visibleRect.y + visibleRect.height;
204
205 // Keep painting lines until our y-coordinate is past the visible
206 // end of the text area.
207
208 while (y < visibleBottom) {
209 r = getChildViewBounds(v, topLine, visibleEditorRect);
210
211 // Paint the line number.
212 paintLineNumber(g, metrics, rhs, y+ascent, topLine + 1);
213
214 // The next possible y-coordinate is just after the last line
215 // painted.
216 y += r.height;
217
218 // Update topLine (we're actually using it for our "current line"
219 // variable now).
220 if (fm != null) {
221 Fold fold = fm.getFoldForLine(topLine);
222 if ((fold != null) && fold.isCollapsed()) {
223 topLine += fold.getCollapsedLineCount();
224 }
225 }
226
227 if (++topLine >= lineCount) {
228 break;
229 }
230 }
231 } else {
232 textAreaInsets = rTextArea.getInsets(textAreaInsets);
233
234 if (visibleRect.y < textAreaInsets.top) {
235 visibleRect.height -= (textAreaInsets.top - visibleRect.y);
236 visibleRect.y = textAreaInsets.top;
237 }
238
239 int topLine = (visibleRect.y - textAreaInsets.top) / cellHeight;
240 int actualTopY = topLine * cellHeight + textAreaInsets.top;
241 int y = actualTopY + ascent;
242
243 // Get the actual first line to paint, taking into account folding.
244 topLine += fm.getHiddenLineCountAbove(topLine, true);
245
246 // Paint line numbers
247 g.setColor(getForeground());
248
249 int line = topLine + 1;
250
251 while ((y < visibleRect.y + visibleRect.height + ascent) && (line <= rTextArea.getLineCount())) {
252 paintLineNumber(g, metrics, rhs, y, line);
253
254 y += cellHeight;
255
256 if (fm != null) {
257 Fold fold = fm.getFoldForLine(line - 1);
258 // Skip to next line to paint, taking extra care for lines with
259 // block ends and begins together, e.g. "} else {"
260 while ((fold != null) && fold.isCollapsed()) {
261 int hiddenLineCount = fold.getLineCount();
262 if (hiddenLineCount == 0) {
263 // Fold parser identified a 0-line fold region... This
264 // is really a bug, but we'll handle it gracefully.
265 break;
266 }
267 line += hiddenLineCount;
268 fold = fm.getFoldForLine(line - 1);
269 }
270 }
271
272 line++;
273 }
274 }
275 }
276
277 protected void paintLineNumber(Graphics g, FontMetrics metrics, int x, int y, int lineNumber) {
278 int originalLineNumber;
279
280 if (lineNumberMap != null) {
281 originalLineNumber = (lineNumber < lineNumberMap.length) ? lineNumberMap[lineNumber] : 0;
282 } else {
283 originalLineNumber = lineNumber;
284 }
285
286 if (originalLineNumber != 0) {
287 String number = Integer.toString(originalLineNumber);
288 int strWidth = metrics.stringWidth(number);
289 g.setColor(showMisalignment && (lineNumber != originalLineNumber) ? errorForeground : getForeground());
290 g.drawString(number, x-strWidth, y);
291 }
292 }
293
294 public int getRhsBorderWidth() { return ((RSyntaxTextArea)rTextArea).isCodeFoldingEnabled() ? 0 : 4; }
295
296 @Override
297 public Dimension getPreferredSize() {
298 if (preferredSize == null) {
299 int lineCount = getMaximumSourceLineNumber();
300
301 if (lineCount > 0) {
302 Font font = getFont();
303 FontMetrics fontMetrics = getFontMetrics(font);
304 int count = 1;
305
306 while (lineCount >= 10) {
307 lineCount = lineCount / 10;
308 count++;
309 }
310
311 int preferredWidth = fontMetrics.charWidth('9') * count + 10;
312 preferredSize = new Dimension(preferredWidth, 0);
313 } else {
314 preferredSize = new Dimension(0, 0);
315 }
316 }
317
318 return preferredSize;
319 }
320 }
321 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.*;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.api.model.Indexes;
13
14 import javax.swing.*;
15 import java.awt.*;
16 import java.io.ByteArrayInputStream;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.net.URI;
20 import java.util.Collection;
21 import java.util.Map;
22 import java.util.concurrent.Future;
23
24 public class DynamicPage
25 extends JPanel
26 implements ContentCopyable, ContentSavable, ContentSearchable, ContentSelectable, FocusedTypeGettable,
27 IndexesChangeListener, LineNumberNavigable, PreferencesChangeListener, UriGettable, UriOpenable,
28 API.LoadSourceListener
29 {
30 protected API api;
31 protected Container.Entry entry;
32 protected TypePage page;
33 protected URI lastOpenedUri;
34 protected Collection<Future<Indexes>> lastCollectionOfFutureIndexes;
35
36 public DynamicPage(API api, Container.Entry entry) {
37 super(new BorderLayout());
38 this.api = api;
39 this.entry = entry;
40
41 String source = api.getSource(entry);
42
43 if (source == null) {
44 // Display the decompiled source code
45 add(page = new ClassFilePage(api, entry));
46 // Try to load source in background
47 api.loadSource(entry, this);
48 } else {
49 // Display original source code
50 add(page = new JavaFilePage(api, new DelegatedEntry(entry, source)));
51 }
52 }
53
54 // --- ContentCopyable --- //
55 @Override public void copy() { page.copy(); }
56
57 // --- ContentSavable --- //
58 @Override public String getFileName() { return page.getFileName(); }
59 @Override public void save(API api, OutputStream outputStream) { page.save(api, outputStream); }
60
61 // --- ContentSearchable --- //
62 @Override public boolean highlightText(String text, boolean caseSensitive) { return page.highlightText(text, caseSensitive); }
63 @Override public void findNext(String text, boolean caseSensitive) { page.findNext(text, caseSensitive); }
64 @Override public void findPrevious(String text, boolean caseSensitive) { page.findPrevious(text, caseSensitive); }
65
66 // --- ContentSelectable --- //
67 @Override public void selectAll() { page.selectAll(); }
68
69 // --- FocusedTypeGettable --- //
70 @Override public String getFocusedTypeName() { return page.getFocusedTypeName(); }
71
72 // --- ContainerEntryGettable --- //
73 @Override public Container.Entry getEntry() { return entry; }
74
75 // --- IndexesChangeListener --- //
76 @Override public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
77 page.indexesChanged(lastCollectionOfFutureIndexes = collectionOfFutureIndexes);
78 }
79
80 // --- LineNumberNavigable --- //
81 @Override public int getMaximumLineNumber() { return page.getMaximumLineNumber(); }
82 @Override public void goToLineNumber(int lineNumber) { page.goToLineNumber(lineNumber); }
83 @Override public boolean checkLineNumber(int lineNumber) { return page.checkLineNumber(lineNumber); }
84
85 // --- PreferencesChangeListener --- //
86 @Override public void preferencesChanged(Map<String, String> preferences) { page.preferencesChanged(preferences); }
87
88 // --- UriGettable --- //
89 @Override public URI getUri() { return entry.getUri(); }
90
91 // --- UriOpenable --- //
92 @Override public boolean openUri(URI uri) { return page.openUri(lastOpenedUri = uri); }
93
94 // --- LoadSourceListener --- //
95 @Override public void sourceLoaded(String source) {
96 SwingUtilities.invokeLater(() -> {
97 // Replace the decompiled source code by the original
98 Point viewPosition = page.getScrollPane().getViewport().getViewPosition();
99
100 removeAll();
101 add(page = new JavaFilePage(api, new DelegatedEntry(entry, source)));
102 page.getScrollPane().getViewport().setViewPosition(viewPosition);
103
104 if (lastOpenedUri != null) {
105 page.openUri(lastOpenedUri);
106 }
107
108 if (lastCollectionOfFutureIndexes != null) {
109 page.indexesChanged(lastCollectionOfFutureIndexes);
110 }
111 });
112 }
113
114 protected static class DelegatedEntry implements Container.Entry {
115 protected Container.Entry entry;
116 protected String source;
117
118 DelegatedEntry(Container.Entry entry, String source) {
119 this.entry = entry;
120 this.source = source;
121 }
122
123 @Override public Container getContainer() { return entry.getContainer(); }
124 @Override public Container.Entry getParent() { return entry.getParent(); }
125 @Override public URI getUri() { return entry.getUri(); }
126 @Override public String getPath() { return entry.getPath(); }
127 @Override public boolean isDirectory() { return entry.isDirectory(); }
128 @Override public long length() { return entry.length(); }
129 @Override public InputStream getInputStream() { return new ByteArrayInputStream(source.getBytes()); }
130 @Override public Collection<Container.Entry> getChildren() { return entry.getChildren(); }
131 }
132 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.IndexesChangeListener;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.api.model.Indexes;
15 import org.jd.gui.util.exception.ExceptionUtil;
16 import org.jd.gui.util.index.IndexesUtil;
17 import org.jd.gui.util.io.TextReader;
18 import org.jd.gui.util.xml.AbstractXmlPathFinder;
19
20 import java.awt.*;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.*;
24 import java.util.List;
25 import java.util.concurrent.Future;
26
27 public class EjbJarXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
28 protected API api;
29 protected Container.Entry entry;
30 protected Collection<Future<Indexes>> collectionOfFutureIndexes = Collections.emptyList();
31
32 public EjbJarXmlFilePage(API api, Container.Entry entry) {
33 this.api = api;
34 this.entry = entry;
35 // Load content file
36 String text = TextReader.getText(entry.getInputStream());
37 // Create hyperlinks
38 new PathFinder().find(text);
39 // Display
40 setText(text);
41 }
42
43 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_XML; }
44
45 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((TypeHyperlinkData)hyperlinkData).enabled; }
46
47 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
48 TypeHyperlinkData data = (TypeHyperlinkData)hyperlinkData;
49
50 if (data.enabled) {
51 try {
52 // Save current position in history
53 Point location = textArea.getLocationOnScreen();
54 int offset = textArea.viewToModel(new Point(x - location.x, y - location.y));
55 URI uri = entry.getUri();
56 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
57
58 // Open link
59 String internalTypeName = data.internalTypeName;
60 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
61 String rootUri = entry.getContainer().getRoot().getUri().toString();
62 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
63
64 for (Container.Entry entry : entries) {
65 if (entry.getUri().toString().startsWith(rootUri)) {
66 sameContainerEntries.add(entry);
67 }
68 }
69
70 if (sameContainerEntries.size() > 0) {
71 api.openURI(x, y, sameContainerEntries, null, data.internalTypeName);
72 } else if (entries.size() > 0) {
73 api.openURI(x, y, entries, null, data.internalTypeName);
74 }
75 } catch (URISyntaxException e) {
76 assert ExceptionUtil.printStackTrace(e);
77 }
78 }
79 }
80
81 // --- UriGettable --- //
82 public URI getUri() { return entry.getUri(); }
83
84 // --- ContentSavable --- //
85 public String getFileName() {
86 String path = entry.getPath();
87 int index = path.lastIndexOf('/');
88 return path.substring(index+1);
89 }
90
91 // --- IndexesChangeListener --- //
92 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
93 // Update the list of containers
94 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
95 // Refresh links
96 boolean refresh = false;
97
98 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
99 TypeHyperlinkData entryData = (TypeHyperlinkData)entry.getValue();
100 String internalTypeName = entryData.internalTypeName;
101 boolean enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
102
103 if (entryData.enabled != enabled) {
104 entryData.enabled = enabled;
105 refresh = true;
106 }
107 }
108
109 if (refresh) {
110 textArea.repaint();
111 }
112 }
113
114 public static final List<String> typeHyperlinkPaths = Arrays.asList(
115 "ejb-jar/assembly-descriptor/application-exception/exception-class",
116 "ejb-jar/assembly-descriptor/interceptor-binding/interceptor-class",
117
118 "ejb-jar/enterprise-beans/entity/home",
119 "ejb-jar/enterprise-beans/entity/remote",
120 "ejb-jar/enterprise-beans/entity/ejb-class",
121 "ejb-jar/enterprise-beans/entity/prim-key-class",
122
123 "ejb-jar/enterprise-beans/message-driven/ejb-class",
124 "ejb-jar/enterprise-beans/message-driven/messaging-type",
125 "ejb-jar/enterprise-beans/message-driven/resource-ref/injection-target/injection-target-class",
126 "ejb-jar/enterprise-beans/message-driven/resource-env-ref/injection-target/injection-target-class",
127
128 "ejb-jar/enterprise-beans/session/home",
129 "ejb-jar/enterprise-beans/session/local",
130 "ejb-jar/enterprise-beans/session/remote",
131 "ejb-jar/enterprise-beans/session/business-local",
132 "ejb-jar/enterprise-beans/session/business-remote",
133 "ejb-jar/enterprise-beans/session/service-endpoint",
134 "ejb-jar/enterprise-beans/session/ejb-class",
135 "ejb-jar/enterprise-beans/session/ejb-ref/home",
136 "ejb-jar/enterprise-beans/session/ejb-ref/remote",
137
138 "ejb-jar/interceptors/interceptor/around-invoke/class",
139 "ejb-jar/interceptors/interceptor/ejb-ref/home",
140 "ejb-jar/interceptors/interceptor/ejb-ref/remote",
141 "ejb-jar/interceptors/interceptor/interceptor-class"
142 );
143
144 public class PathFinder extends AbstractXmlPathFinder {
145 public PathFinder() {
146 super(typeHyperlinkPaths);
147 }
148
149 public void handle(String path, String text, int position) {
150 String trim = text.trim();
151 if (trim != null) {
152 int startIndex = position + text.indexOf(trim);
153 int endIndex = startIndex + trim.length();
154 String internalTypeName = trim.replace(".", "/");
155 addHyperlink(new TypeHyperlinkData(startIndex, endIndex, internalTypeName));
156 }
157 }
158 }
159 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
10 import org.fife.ui.rsyntaxtextarea.Token;
11
12 import java.awt.*;
13 import java.awt.event.MouseAdapter;
14 import java.awt.event.MouseEvent;
15 import java.util.Map;
16 import java.util.TreeMap;
17
18 public abstract class HyperlinkPage extends TextPage {
19 protected static final Cursor DEFAULT_CURSOR = Cursor.getDefaultCursor();
20 protected static final Cursor HAND_CURSOR = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
21
22 protected TreeMap<Integer, HyperlinkData> hyperlinks = new TreeMap<>();
23
24 public HyperlinkPage() {
25 MouseAdapter listener = new MouseAdapter() {
26 int lastX = -1;
27 int lastY = -1;
28 int lastModifiers = -1;
29
30 public void mouseClicked(MouseEvent e) {
31 if ((e.getClickCount() == 1) && ((e.getModifiers() & (Event.ALT_MASK|Event.META_MASK|Event.SHIFT_MASK)) == 0)) {
32 int offset = textArea.viewToModel(new Point(e.getX(), e.getY()));
33 if (offset != -1) {
34 Map.Entry<Integer, HyperlinkData> entry = hyperlinks.floorEntry(offset);
35 if (entry != null) {
36 HyperlinkData entryData = entry.getValue();
37 if ((entryData != null) && (offset < entryData.endPosition) && (offset >= entryData.startPosition) && isHyperlinkEnabled(entryData)) {
38 openHyperlink(e.getXOnScreen(), e.getYOnScreen(), entryData);
39 }
40 }
41 }
42 }
43 }
44
45 public void mouseMoved(MouseEvent e) {
46 if ((e.getX() != lastX) || (e.getY() != lastY) || (lastModifiers != e.getModifiers())) {
47 lastX = e.getX();
48 lastY = e.getY();
49 lastModifiers = e.getModifiers();
50
51 if ((e.getModifiers() & (Event.ALT_MASK|Event.META_MASK|Event.SHIFT_MASK)) == 0) {
52 int offset = textArea.viewToModel(new Point(e.getX(), e.getY()));
53 if (offset != -1) {
54 Map.Entry<Integer, HyperlinkData> entry = hyperlinks.floorEntry(offset);
55 if (entry != null) {
56 HyperlinkData entryData = entry.getValue();
57 if ((entryData != null) && (offset < entryData.endPosition) && (offset >= entryData.startPosition) && isHyperlinkEnabled(entryData)) {
58 if (textArea.getCursor() != HAND_CURSOR) {
59 textArea.setCursor(HAND_CURSOR);
60 }
61 return;
62 }
63 }
64 }
65 }
66
67 if (textArea.getCursor() != DEFAULT_CURSOR) {
68 textArea.setCursor(DEFAULT_CURSOR);
69 }
70 }
71 }
72 };
73
74 textArea.addMouseListener(listener);
75 textArea.addMouseMotionListener(listener);
76 }
77
78 protected RSyntaxTextArea newSyntaxTextArea() { return new HyperlinkSyntaxTextArea(); }
79
80 public void addHyperlink(HyperlinkData hyperlinkData) {
81 hyperlinks.put(hyperlinkData.startPosition, hyperlinkData);
82 }
83
84 public void clearHyperlinks() {
85 hyperlinks.clear();
86 }
87
88 protected abstract boolean isHyperlinkEnabled(HyperlinkData hyperlinkData);
89
90 protected abstract void openHyperlink(int x, int y, HyperlinkData hyperlinkData);
91
92 public static class HyperlinkData {
93 public int startPosition;
94 public int endPosition;
95
96 public HyperlinkData(int startPosition, int endPosition) {
97 this.startPosition = startPosition;
98 this.endPosition = endPosition;
99 }
100 }
101
102 public class HyperlinkSyntaxTextArea extends RSyntaxTextArea {
103 /**
104 * @see HyperlinkPage.HyperlinkSyntaxTextArea#getUnderlineForToken(org.fife.ui.rsyntaxtextarea.Token)
105 */
106 @Override
107 public boolean getUnderlineForToken(Token t) {
108 Map.Entry<Integer, HyperlinkData> entry = hyperlinks.floorEntry(t.getOffset());
109 if (entry != null) {
110 HyperlinkData entryData = entry.getValue();
111 if ((entryData != null) && (t.getOffset() < entryData.endPosition) && (t.getOffset() >= entryData.startPosition) && isHyperlinkEnabled(entryData)) {
112 return true;
113 }
114 }
115 return super.getUnderlineForToken(t);
116 }
117 }
118 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.antlr.v4.runtime.ANTLRInputStream;
10 import org.antlr.v4.runtime.ParserRuleContext;
11 import org.antlr.v4.runtime.RuleContext;
12 import org.antlr.v4.runtime.Token;
13 import org.antlr.v4.runtime.tree.ParseTree;
14 import org.antlr.v4.runtime.tree.TerminalNode;
15 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
16 import org.jd.gui.api.API;
17 import org.jd.gui.api.model.Container;
18 import org.jd.gui.util.io.TextReader;
19 import org.jd.gui.util.parser.antlr.ANTLRJavaParser;
20 import org.jd.gui.util.parser.antlr.AbstractJavaListener;
21 import org.jd.gui.util.parser.antlr.JavaParser;
22
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 public class JavaFilePage extends TypePage {
29
30 public JavaFilePage(API api, Container.Entry entry) {
31 super(api, entry);
32 // Load content file
33 String text = TextReader.getText(entry.getInputStream()).replace("\r\n", "\n").replace('\r', '\n');
34 // Parse
35 DeclarationListener declarationListener = new DeclarationListener(entry);
36 ReferenceListener referenceListener = new ReferenceListener(entry);
37
38 ANTLRJavaParser.parse(new ANTLRInputStream(text), declarationListener);
39 referenceListener.init(declarationListener);
40 ANTLRJavaParser.parse(new ANTLRInputStream(text), referenceListener);
41 // Display
42 setText(text);
43 initLineNumbers();
44 }
45
46 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JAVA; }
47
48 // --- ContentSavable --- //
49 public String getFileName() {
50 String path = entry.getPath();
51 int index = path.lastIndexOf('/');
52 return path.substring(index+1);
53 }
54
55 public class DeclarationListener extends AbstractJavaListener {
56 protected StringBuilder sbTypeDeclaration = new StringBuilder();
57 protected String currentInternalTypeName;
58
59 public DeclarationListener(Container.Entry entry) { super(entry); }
60
61 public HashMap<String, String> getNameToInternalTypeName() { return super.nameToInternalTypeName; }
62
63 // --- Add declarations --- //
64 public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
65 super.enterPackageDeclaration(ctx);
66
67 if (! packageName.isEmpty()) {
68 sbTypeDeclaration.append(packageName).append('/');
69 }
70 }
71
72 public void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
73 List<TerminalNode> identifiers = ctx.qualifiedName().Identifier();
74 String internalTypeName = concatIdentifiers(identifiers);
75 String typeName = identifiers.get(identifiers.size()-1).getSymbol().getText();
76
77 nameToInternalTypeName.put(typeName, internalTypeName);
78 }
79
80 public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
81 public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
82
83 public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
84 public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
85
86 public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
87 public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
88
89 public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
90 public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
91
92 public void enterTypeDeclaration(ParserRuleContext ctx) {
93 // Type declaration
94 TerminalNode identifier = ctx.getToken(JavaParser.Identifier, 0);
95 String typeName = identifier.getText();
96 int position = identifier.getSymbol().getStartIndex();
97 int length = sbTypeDeclaration.length();
98
99 if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
100 sbTypeDeclaration.append(typeName);
101 } else {
102 sbTypeDeclaration.append('$').append(typeName);
103 }
104
105 currentInternalTypeName = sbTypeDeclaration.toString();
106 nameToInternalTypeName.put(typeName, currentInternalTypeName);
107
108 // Super type reference
109 JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
110 String superInternalTypeName = (superType != null) ? resolveInternalTypeName(superType.classOrInterfaceType().Identifier()) : null;
111 TypeDeclarationData data = new TypeDeclarationData(position, typeName.length(), currentInternalTypeName, null, null, superInternalTypeName);
112
113 declarations.put(currentInternalTypeName, data);
114 typeDeclarations.put(position, data);
115 }
116
117 public void exitTypeDeclaration() {
118 int index = sbTypeDeclaration.lastIndexOf("$");
119
120 if (index == -1) {
121 index = sbTypeDeclaration.lastIndexOf("/") + 1;
122 }
123
124 if (index == -1) {
125 sbTypeDeclaration.setLength(0);
126 } else {
127 sbTypeDeclaration.setLength(index);
128 }
129
130 currentInternalTypeName = sbTypeDeclaration.toString();
131 }
132
133 public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) {
134 if (ctx.getChildCount() == 2) {
135 ParseTree first = ctx.getChild(0);
136
137 if (first instanceof TerminalNode) {
138 TerminalNode f = (TerminalNode)first;
139
140 if (f.getSymbol().getType() == JavaParser.STATIC) {
141 String name = f.getText();
142 int position = f.getSymbol().getStartIndex();
143 declarations.put(currentInternalTypeName + "-<clinit>-()V", new TypePage.DeclarationData(position, 6, currentInternalTypeName, name, "()V"));
144 }
145 }
146 }
147 }
148
149 public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
150 JavaParser.TypeContext typeContext = ctx.type();
151
152 for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
153 TerminalNode identifier = constantDeclaratorContext.Identifier();
154 String name = identifier.getText();
155 int dimensionOnVariable = countDimension(constantDeclaratorContext.children);
156 String descriptor = createDescriptor(typeContext, dimensionOnVariable);
157 int position = identifier.getSymbol().getStartIndex();
158
159 declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor));
160 }
161 }
162
163 public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
164 JavaParser.TypeContext typeContext = ctx.type();
165
166 for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
167 JavaParser.VariableDeclaratorIdContext variableDeclaratorId = declaration.variableDeclaratorId();
168 TerminalNode identifier = variableDeclaratorId.Identifier();
169 String name = identifier.getText();
170 int dimensionOnVariable = countDimension(variableDeclaratorId.children);
171 String descriptor = createDescriptor(typeContext, dimensionOnVariable);
172 int position = identifier.getSymbol().getStartIndex();
173 TypePage.DeclarationData data = new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor);
174
175 declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, data);
176 }
177 }
178
179 public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
180 enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
181 }
182
183 public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
184 enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
185 }
186
187 public void enterMethodDeclaration(
188 ParserRuleContext ctx, TerminalNode identifier,
189 JavaParser.FormalParametersContext formalParameters, JavaParser.TypeContext returnType) {
190
191 String name = identifier.getText();
192 String paramDescriptors = createParamDescriptors(formalParameters.formalParameterList());
193 String returnDescriptor = createDescriptor(returnType, 0);
194 String descriptor = paramDescriptors + returnDescriptor;
195 int position = identifier.getSymbol().getStartIndex();
196
197 declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor));
198 }
199
200 public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
201 TerminalNode identifier = ctx.Identifier();
202 String name = identifier.getText();
203 String paramDescriptors = createParamDescriptors(ctx.formalParameters().formalParameterList());
204 String descriptor = paramDescriptors + "V";
205 int position = identifier.getSymbol().getStartIndex();
206
207 declarations.put(currentInternalTypeName + "-<init>-" + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor));
208 }
209
210 public String createParamDescriptors(JavaParser.FormalParameterListContext formalParameterList) {
211 StringBuilder paramDescriptors = null;
212
213 if (formalParameterList != null) {
214 List<JavaParser.FormalParameterContext> formalParameters = formalParameterList.formalParameter();
215 paramDescriptors = new StringBuilder("(");
216
217 for (JavaParser.FormalParameterContext formalParameter : formalParameters) {
218 int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children);
219 String descriptor = createDescriptor(formalParameter.type(), dimensionOnParameter);
220
221 paramDescriptors.append(descriptor);
222 }
223 }
224
225 return (paramDescriptors == null) ? "()" : paramDescriptors.append(')').toString();
226 }
227 }
228
229 public class ReferenceListener extends AbstractJavaListener {
230 protected StringBuilder sbTypeDeclaration = new StringBuilder();
231 protected HashMap<String, TypePage.ReferenceData> referencesCache = new HashMap<>();
232 protected String currentInternalTypeName;
233 protected Context currentContext = null;
234
235 public ReferenceListener(Container.Entry entry) { super(entry); }
236
237 public void init(DeclarationListener declarationListener) {
238 this.nameToInternalTypeName.putAll(declarationListener.getNameToInternalTypeName());
239 }
240
241 // --- Add declarations --- //
242 public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
243 super.enterPackageDeclaration(ctx);
244
245 if (! packageName.isEmpty()) {
246 sbTypeDeclaration.append(packageName).append('/');
247 }
248 }
249
250 public void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
251 List<TerminalNode> identifiers = ctx.qualifiedName().Identifier();
252 int position = identifiers.get(0).getSymbol().getStartIndex();
253 String internalTypeName = concatIdentifiers(identifiers);
254
255 addHyperlink(new TypePage.HyperlinkReferenceData(position, internalTypeName.length(), newReferenceData(internalTypeName, null, null, null)));
256 }
257
258 public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
259 public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
260
261 public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
262 public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
263
264 public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
265 public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
266
267 public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
268 public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
269
270 public void enterTypeDeclaration(ParserRuleContext ctx) {
271 // Type declaration
272 TerminalNode identifier = ctx.getToken(JavaParser.Identifier, 0);
273 String typeName = identifier.getText();
274 int length = sbTypeDeclaration.length();
275
276 if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
277 sbTypeDeclaration.append(typeName);
278 } else {
279 sbTypeDeclaration.append('$').append(typeName);
280 }
281
282 currentInternalTypeName = sbTypeDeclaration.toString();
283 currentContext = new Context(currentContext);
284 }
285
286 public void exitTypeDeclaration() {
287 int index = sbTypeDeclaration.lastIndexOf("$");
288
289 if (index == -1) {
290 index = sbTypeDeclaration.lastIndexOf("/") + 1;
291 }
292
293 if (index == -1) {
294 sbTypeDeclaration.setLength(0);
295 } else {
296 sbTypeDeclaration.setLength(index);
297 }
298
299 currentInternalTypeName = sbTypeDeclaration.toString();
300 }
301
302 public void enterFormalParameters(JavaParser.FormalParametersContext ctx) {
303 JavaParser.FormalParameterListContext formalParameterList = ctx.formalParameterList();
304
305 if (formalParameterList != null) {
306 List<JavaParser.FormalParameterContext> formalParameters = formalParameterList.formalParameter();
307
308 for (JavaParser.FormalParameterContext formalParameter : formalParameters) {
309 int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children);
310 String descriptor = createDescriptor(formalParameter.type(), dimensionOnParameter);
311 String name = formalParameter.variableDeclaratorId().Identifier().getSymbol().getText();
312
313 currentContext.nameToDescriptor.put(name, descriptor);
314 }
315 }
316 }
317
318 // --- Add references --- //
319 public void enterType(JavaParser.TypeContext ctx) {
320 // Add type reference
321 JavaParser.ClassOrInterfaceTypeContext classOrInterfaceType = ctx.classOrInterfaceType();
322
323 if (classOrInterfaceType != null) {
324 List<TerminalNode> identifiers = classOrInterfaceType.Identifier();
325 String name = concatIdentifiers(identifiers);
326 String internalTypeName = resolveInternalTypeName(identifiers);
327 int position = identifiers.get(0).getSymbol().getStartIndex();
328
329 addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)));
330 }
331 }
332
333 public void enterLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) {
334 JavaParser.TypeContext typeContext = ctx.type();
335
336 for (JavaParser.VariableDeclaratorContext variableDeclarator : ctx.variableDeclarators().variableDeclarator()) {
337 JavaParser.VariableDeclaratorIdContext variableDeclaratorId = variableDeclarator.variableDeclaratorId();
338 int dimensionOnVariable = countDimension(variableDeclaratorId.children);
339 String descriptor = createDescriptor(typeContext, dimensionOnVariable);
340 String name = variableDeclarator.variableDeclaratorId().Identifier().getSymbol().getText();
341
342 currentContext.nameToDescriptor.put(name, descriptor);
343 }
344 }
345
346 public void enterCreator(JavaParser.CreatorContext ctx) {
347 enterNewExpression(ctx.createdName().Identifier(), ctx.classCreatorRest());
348 }
349
350 public void enterInnerCreator(JavaParser.InnerCreatorContext ctx) {
351 enterNewExpression(Collections.singletonList(ctx.Identifier()), ctx.classCreatorRest());
352 }
353
354 public void enterNewExpression(List<TerminalNode> identifiers, JavaParser.ClassCreatorRestContext classCreatorRest) {
355 if (identifiers.size() > 0) {
356 String name = concatIdentifiers(identifiers);
357 String internalTypeName = resolveInternalTypeName(identifiers);
358 int position = identifiers.get(0).getSymbol().getStartIndex();
359
360 if (classCreatorRest != null) {
361 // Constructor call -> Add a link to the constructor declaration
362 JavaParser.ExpressionListContext expressionList = classCreatorRest.arguments().expressionList();
363 String descriptor = (expressionList != null) ? getParametersDescriptor(expressionList).append('V').toString() : "()V";
364
365 addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, "<init>", descriptor, currentInternalTypeName)));
366 } else {
367 // New type array -> Add a link to the type declaration
368 addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)));
369 }
370 }
371 }
372
373 public void enterExpression(JavaParser.ExpressionContext ctx) {
374 switch (ctx.getChildCount()) {
375 case 1:
376 TerminalNode identifier0 = getToken(ctx.children, JavaParser.Identifier, 0);
377
378 if (identifier0 != null) {
379 if (isAField(ctx)) {
380 JavaParser.PrimaryContext primaryContext = ctx.primary();
381
382 if (primaryContext != null) {
383 String fieldName = primaryContext.literal().StringLiteral().getText();
384
385 if (currentContext.getDescriptor(fieldName) == null) {
386 // Not a local variable or a method parameter
387 String fieldTypeName = searchInternalTypeNameForThisFieldName(currentInternalTypeName, fieldName);
388 int position = ctx.Identifier().getSymbol().getStartIndex();
389
390 addHyperlink(new TypePage.HyperlinkReferenceData(position, fieldName.length(), newReferenceData(fieldTypeName, fieldName, "?", currentInternalTypeName)));
391 }
392 }
393 }
394 } else if (ctx.primary() != null) {
395 TerminalNode identifier = ctx.primary().Identifier();
396
397 if (identifier != null) {
398 Token symbol = identifier.getSymbol();
399 String name = symbol.getText();
400 String internalTypeName = nameToInternalTypeName.get(name);
401
402 if (internalTypeName != null) {
403 int position = symbol.getStartIndex();
404
405 addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)));
406 }
407 }
408 }
409 break;
410 case 3:
411 if (getToken(ctx.children, JavaParser.DOT, 1) != null) {
412 // Search "expression '.' Identifier" : field reference
413 TerminalNode identifier3 = getToken(ctx.children, JavaParser.Identifier, 2);
414
415 if ((identifier3 != null) && isAField(ctx)) {
416 String fieldTypeName = getInternalTypeName(ctx.getChild(0));
417
418 if (fieldTypeName != null) {
419 int position = identifier3.getSymbol().getStartIndex();
420 String fieldName = identifier3.getText();
421
422 addHyperlink(new TypePage.HyperlinkReferenceData(position, fieldName.length(), newReferenceData(fieldTypeName, fieldName, "?", currentInternalTypeName)));
423 }
424 }
425 } else if (getToken(ctx.children, JavaParser.LPAREN, 1) != null) {
426 // Search "expression '(' ')'" : method reference
427 if (getToken(ctx.children, JavaParser.RPAREN, 2) != null) {
428 enterCallMethodExpression(ctx, null);
429 }
430 }
431 break;
432 case 4:
433 if (getToken(ctx.children, JavaParser.LPAREN, 1) != null) {
434 // Search "expression '(' expressionList ')'" : method reference
435 if (getToken(ctx.children, JavaParser.RPAREN, 3) != null) {
436 JavaParser.ExpressionListContext expressionListContext = ctx.expressionList();
437
438 if ((expressionListContext != null) && (expressionListContext == ctx.children.get(2))) {
439 enterCallMethodExpression(ctx, expressionListContext);
440 }
441 }
442 }
443 break;
444 }
445 }
446
447 public void enterCallMethodExpression(JavaParser.ExpressionContext ctx, JavaParser.ExpressionListContext expressionListContext) {
448 ParseTree first = ctx.children.get(0);
449
450 if (first instanceof JavaParser.ExpressionContext) {
451 JavaParser.ExpressionContext f = (JavaParser.ExpressionContext)first;
452
453 switch (f.getChildCount()) {
454 case 1:
455 JavaParser.PrimaryContext primary = f.primary();
456 TerminalNode identifier = primary.Identifier();
457
458 if (identifier != null) {
459 Token symbol = identifier.getSymbol();
460
461 if (symbol != null) {
462 String methodName = symbol.getText();
463 String methodTypeName = searchInternalTypeNameForThisMethodName(currentInternalTypeName, methodName);
464
465 if (methodTypeName != null) {
466 int position = symbol.getStartIndex();
467 String methodDescriptor = (expressionListContext != null) ? getParametersDescriptor(expressionListContext).append('?').toString() : "()?";
468
469 addHyperlink(new TypePage.HyperlinkReferenceData(position, methodName.length(), newReferenceData(methodTypeName, methodName, methodDescriptor, currentInternalTypeName)));
470 }
471 }
472 } else {
473 Token symbol = primary.getChild(TerminalNode.class, 0).getSymbol();
474
475 if (symbol != null) {
476 switch (symbol.getType()) {
477 case JavaParser.THIS:
478 int position = symbol.getStartIndex();
479 String methodDescriptor = (expressionListContext != null) ? getParametersDescriptor(expressionListContext).append('?').toString() : "()?";
480
481 addHyperlink(new TypePage.HyperlinkReferenceData(position, 4, newReferenceData(currentInternalTypeName, "<init>", methodDescriptor, currentInternalTypeName)));
482 break;
483 case JavaParser.SUPER:
484 DeclarationData data = declarations.get(currentInternalTypeName);
485
486 if (data instanceof TypeDeclarationData) {
487 position = symbol.getStartIndex();
488 String methodTypeName = ((TypeDeclarationData) data).superTypeName;
489 methodDescriptor = (expressionListContext != null) ? getParametersDescriptor(expressionListContext).append('?').toString() : "()?";
490
491 addHyperlink(new TypePage.HyperlinkReferenceData(position, 5, newReferenceData(methodTypeName, "<init>", methodDescriptor, currentInternalTypeName)));
492 }
493 break;
494 }
495 }
496 }
497 break;
498 case 3:
499 // Search "expression '.' Identifier"
500 ParseTree dot = first.getChild(1);
501
502 if ((dot instanceof TerminalNode) && (((TerminalNode)dot).getSymbol().getType() == JavaParser.DOT)) {
503 ParseTree identifier3 = first.getChild(2);
504
505 if (identifier3 instanceof TerminalNode) {
506 TerminalNode i3 = (TerminalNode)identifier3;
507
508 if (i3.getSymbol().getType() == JavaParser.Identifier) {
509 String methodTypeName = getInternalTypeName(first.getChild(0));
510
511 if (methodTypeName != null) {
512 int position = i3.getSymbol().getStartIndex();
513 String methodName = i3.getText();
514 String methodDescriptor = (expressionListContext != null) ? getParametersDescriptor(expressionListContext).append('?').toString() : "()?";
515
516 addHyperlink(new TypePage.HyperlinkReferenceData(position, methodName.length(), newReferenceData(methodTypeName, methodName, methodDescriptor, currentInternalTypeName)));
517 }
518 }
519 }
520 }
521 break;
522 }
523 }
524 }
525
526 public StringBuilder getParametersDescriptor(JavaParser.ExpressionListContext expressionListContext) {
527 StringBuilder sb = new StringBuilder('(');
528 for (JavaParser.ExpressionContext exp : expressionListContext.expression()) sb.append('?');
529 sb.append(')');
530 return sb;
531 }
532
533 public boolean isAField(JavaParser.ExpressionContext ctx) {
534 RuleContext parent = ctx.parent;
535
536 if (parent instanceof JavaParser.ExpressionContext) {
537 int size = parent.getChildCount();
538
539 if (parent.getChild(size - 1) != ctx) {
540 for (int i=0; i<size; i++) {
541 if (parent.getChild(i) == ctx) {
542 ParseTree next = parent.getChild(i+1);
543
544 if (next instanceof TerminalNode) {
545 switch (((TerminalNode)next).getSymbol().getType()) {
546 case JavaParser.DOT:
547 case JavaParser.LPAREN:
548 return false;
549 }
550 }
551 }
552 }
553 }
554 }
555
556 return true;
557 }
558
559 public String getInternalTypeName(ParseTree pt) {
560 if (pt instanceof JavaParser.ExpressionContext) {
561
562 if (pt.getChildCount() == 1) {
563 JavaParser.PrimaryContext primary = ((JavaParser.ExpressionContext)pt).primary();
564 TerminalNode identifier = primary.Identifier();
565
566 if (identifier != null) {
567 String name = identifier.getSymbol().getText();
568 String descriptor = (currentContext == null) ? null : currentContext.getDescriptor(name);
569
570 if (descriptor != null) {
571 // Is a local variable or a method parameter
572 if (descriptor.charAt(0) == 'L') {
573 return descriptor.substring(1, descriptor.length() - 1);
574 }
575 } else if (currentInternalTypeName != null) {
576 String internalTypeName = searchInternalTypeNameForThisFieldName(currentInternalTypeName, name);
577
578 if (internalTypeName != null) {
579 // Is a field
580 return internalTypeName;
581 } else {
582 internalTypeName = resolveInternalTypeName(Collections.singletonList(identifier));
583
584 if (internalTypeName != null) {
585 // Is a type
586 return internalTypeName;
587 } else {
588 // Not found
589 return null;
590 }
591 }
592 }
593 } else {
594 TerminalNode tn = primary.getChild(TerminalNode.class, 0);
595 Token symbol = (tn == null) ? null : tn.getSymbol();
596
597 if (symbol != null) {
598 switch (symbol.getType()) {
599 case JavaParser.THIS:
600 return currentInternalTypeName;
601 case JavaParser.SUPER:
602 DeclarationData data = declarations.get(currentInternalTypeName);
603
604 if (data instanceof TypeDeclarationData) {
605 return ((TypeDeclarationData)data).superTypeName;
606 } else {
607 return null;
608 }
609 }
610 }
611 }
612 }
613 }
614
615 return null;
616 }
617
618 public String searchInternalTypeNameForThisFieldName(String internalTypeName, String name) {
619 String prefix = internalTypeName + '-' + name + '-';
620 int length = prefix.length();
621
622 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
623 if (entry.getKey().startsWith(prefix) && (entry.getKey().charAt(length) != '(')) {
624 return entry.getValue().typeName;
625 }
626 }
627
628 // Not found
629 int index = internalTypeName.lastIndexOf('$');
630
631 if (index != -1) {
632 // Search in the outer type
633 internalTypeName = internalTypeName.substring(0, index);
634
635 return searchInternalTypeNameForThisFieldName(internalTypeName, name);
636 }
637
638 // Not found
639 return null;
640 }
641
642 public String searchInternalTypeNameForThisMethodName(String internalTypeName, String name) {
643 String prefix = internalTypeName + '-' + name + "-(";
644
645 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
646 if (entry.getKey().startsWith(prefix)) {
647 return entry.getValue().typeName;
648 }
649 }
650
651 // Not found
652 int index = internalTypeName.lastIndexOf('$');
653
654 if (index != -1) {
655 // Search in the outer type
656 internalTypeName = internalTypeName.substring(0, index);
657
658 return searchInternalTypeNameForThisMethodName(internalTypeName, name);
659 }
660
661 // Not found
662 return null;
663 }
664
665 public TerminalNode getToken(List<ParseTree> children, int type, int i) {
666 ParseTree pt = children.get(i);
667
668 if (pt instanceof TerminalNode) {
669 if (((TerminalNode)pt).getSymbol().getType() == type) {
670 return (TerminalNode)pt;
671 }
672 }
673
674 return null;
675 }
676
677 public void enterBlock(JavaParser.BlockContext ctx) {
678 currentContext = new Context(currentContext);
679 }
680
681 public void exitBlock(JavaParser.BlockContext ctx) {
682 currentContext = currentContext.outerContext;
683 }
684
685 public TypePage.ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
686 String key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName;
687 TypePage.ReferenceData reference = referencesCache.get(key);
688
689 if (reference == null) {
690 reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName);
691 referencesCache.put(key, reference);
692 references.add(reference);
693 }
694
695 return reference;
696 }
697
698 // --- Add strings --- //
699 public void enterLiteral(JavaParser.LiteralContext ctx) {
700 TerminalNode stringLiteral = ctx.StringLiteral();
701
702 if (stringLiteral != null) {
703 String str = stringLiteral.getSymbol().getText();
704 int position = stringLiteral.getSymbol().getStartIndex();
705
706 strings.add(new TypePage.StringData(position, str.length(), str, currentInternalTypeName));
707 }
708 }
709 }
710
711 public static class Context {
712 protected Context outerContext;
713
714 protected HashMap<String, String> nameToDescriptor = new HashMap<>();
715
716 public Context(Context outerContext) {
717 this.outerContext = outerContext;
718 }
719
720 /**
721 * @param name Parameter or variable name
722 * @return Qualified type name
723 */
724 public String getDescriptor(String name) {
725 String descriptor = nameToDescriptor.get(name);
726
727 if ((descriptor == null) && (outerContext != null)) {
728 descriptor = outerContext.getDescriptor(name);
729 }
730
731 return descriptor;
732 }
733 }
734
735 public static class TypeDeclarationData extends TypePage.DeclarationData {
736 protected String superTypeName;
737
738 public TypeDeclarationData(int startPosition, int length, String type, String name, String descriptor, String superTypeName) {
739 super(startPosition, length, type, name, descriptor);
740
741 this.superTypeName = superTypeName;
742 }
743 }
744 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.IndexesChangeListener;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.api.model.Indexes;
14 import org.jd.gui.util.exception.ExceptionUtil;
15 import org.jd.gui.util.index.IndexesUtil;
16
17 import java.awt.*;
18 import java.net.URI;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.concurrent.Future;
24
25 public class LogPage extends HyperlinkPage implements UriGettable, IndexesChangeListener {
26 protected API api;
27 protected URI uri;
28 protected Collection<Future<Indexes>> collectionOfFutureIndexes = Collections.emptyList();
29
30 public LogPage(API api, URI uri, String content) {
31 this.api = api;
32 this.uri = uri;
33 // Parse
34 int index = 0;
35 int eol = content.indexOf('\n');
36
37 while (eol != -1) {
38 parseLine(content, index, eol);
39 index = eol + 1;
40 eol = content.indexOf('\n', index);
41 }
42
43 parseLine(content, index, content.length());
44 // Display
45 setText(content);
46 }
47
48 protected void parseLine(String content, int index, int eol) {
49 int start = content.indexOf("at ", index);
50
51 if ((start != -1) && (start < eol)) {
52 int leftParenthesisIndex = content.indexOf('(', start);
53
54 if ((leftParenthesisIndex != -1) && (leftParenthesisIndex < eol)) {
55 addHyperlink(new LogHyperlinkData(start+3, leftParenthesisIndex));
56 }
57 }
58 }
59
60 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((LogHyperlinkData)hyperlinkData).enabled; }
61
62 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
63 LogHyperlinkData logHyperlinkData = (LogHyperlinkData)hyperlinkData;
64
65 if (logHyperlinkData.enabled) {
66 try {
67 // Save current position in history
68 Point location = textArea.getLocationOnScreen();
69 int offset = textArea.viewToModel(new Point(x - location.x, y - location.y));
70 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
71
72 // Open link
73 String text = getText();
74 String typeAndMethodNames = text.substring(hyperlinkData.startPosition, hyperlinkData.endPosition);
75 int lastDotIndex = typeAndMethodNames.lastIndexOf('.');
76 String methodName = typeAndMethodNames.substring(lastDotIndex + 1);
77 String internalTypeName = typeAndMethodNames.substring(0, lastDotIndex).replace('.', '/');
78 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
79 int leftParenthesisIndex = hyperlinkData.endPosition + 1;
80 int rightParenthesisIndex = text.indexOf(')', leftParenthesisIndex);
81 String lineNumberOrNativeMethodFlag = text.substring(leftParenthesisIndex, rightParenthesisIndex);
82
83 if (lineNumberOrNativeMethodFlag.equals("Native Method")) {
84 // Example: at java.security.AccessController.doPrivileged(Native Method)
85 lastDotIndex = internalTypeName.lastIndexOf('/');
86 String shortTypeName = internalTypeName.substring(lastDotIndex + 1);
87 api.openURI(x, y, entries, null, shortTypeName + '-' + methodName + "-(*)?");
88 } else {
89 // Example: at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
90 int colonIndex = lineNumberOrNativeMethodFlag.indexOf(':');
91 String lineNumber = lineNumberOrNativeMethodFlag.substring(colonIndex + 1);
92 api.openURI(x, y, entries, "lineNumber=" + lineNumber, null);
93 }
94 } catch (Exception e) {
95 assert ExceptionUtil.printStackTrace(e);
96 }
97 }
98 }
99
100 // --- UriGettable --- //
101 public URI getUri() { return uri; }
102
103 // --- ContentSavable --- //
104 public String getFileName() {
105 String path = uri.getPath();
106 int index = path.lastIndexOf('/');
107 return path.substring(index + 1);
108 }
109
110 // --- IndexesChangeListener --- //
111 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
112 // Update the list of containers
113 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
114 // Refresh links
115 boolean refresh = false;
116 String text = getText();
117
118 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
119 LogHyperlinkData entryData = (LogHyperlinkData)entry.getValue();
120 String typeAndMethodNames = text.substring(entryData.startPosition, entryData.endPosition);
121 int lastDotIndex = typeAndMethodNames.lastIndexOf('.');
122 String internalTypeName = typeAndMethodNames.substring(0, lastDotIndex).replace('.', '/');
123 boolean enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
124
125 if (entryData.enabled != enabled) {
126 entryData.enabled = enabled;
127 refresh = true;
128 }
129 }
130
131 if (refresh) {
132 textArea.repaint();
133 }
134 }
135
136 public static class LogHyperlinkData extends HyperlinkData {
137 public boolean enabled = false;
138
139 public LogHyperlinkData(int startPosition, int endPosition) {
140 super(startPosition, endPosition);
141 }
142 }
143 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.IndexesChangeListener;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.api.model.Indexes;
14 import org.jd.gui.util.exception.ExceptionUtil;
15 import org.jd.gui.util.index.IndexesUtil;
16 import org.jd.gui.util.io.TextReader;
17
18 import java.awt.*;
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.util.*;
22 import java.util.List;
23 import java.util.concurrent.Future;
24
25 public class ManifestFilePage extends HyperlinkPage implements UriGettable, IndexesChangeListener {
26 protected API api;
27 protected Container.Entry entry;
28 protected Collection<Future<Indexes>> collectionOfFutureIndexes = Collections.emptyList();
29
30 public ManifestFilePage(API api, Container.Entry entry) {
31 this.api = api;
32 this.entry = entry;
33 // Load content file
34 String text = TextReader.getText(entry.getInputStream());
35 // Parse hyperlinks. Docs:
36 // - http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html
37 // - http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html
38 int startLineIndex = text.indexOf("Main-Class:");
39 if (startLineIndex != -1) {
40 // Example: Main-Class: jd.gui.App
41 int startIndex = skipSeparators(text, startLineIndex + "Main-Class:".length());
42 int endIndex = searchEndIndexOfValue(text, startLineIndex, startIndex);
43 String typeName = text.substring(startIndex, endIndex);
44 String internalTypeName = typeName.replace('.', '/');
45 addHyperlink(new ManifestHyperlinkData(startIndex, endIndex, internalTypeName + "-main-([Ljava/lang/String;)V"));
46 }
47
48 startLineIndex = text.indexOf("Premain-Class:");
49 if (startLineIndex != -1) {
50 // Example: Premain-Class: packge.JavaAgent
51 int startIndex = skipSeparators(text, startLineIndex + "Premain-Class:".length());
52 int endIndex = searchEndIndexOfValue(text, startLineIndex, startIndex);
53 String typeName = text.substring(startIndex, endIndex);
54 String internalTypeName = typeName.replace('.', '/');
55 // Undefined parameters : 2 candidate methods
56 // http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html
57 addHyperlink(new ManifestHyperlinkData(startIndex, endIndex, internalTypeName + "-premain-(*)?"));
58 }
59 // Display
60 setText(text);
61 }
62
63 public int skipSeparators(String text, int index) {
64 int length = text.length();
65
66 while (index < length) {
67 switch (text.charAt(index)) {
68 case ' ': case '\t': case '\n': case '\r':
69 index++;
70 break;
71 default:
72 return index;
73 }
74 }
75
76 return index;
77 }
78
79 public int searchEndIndexOfValue(String text, int startLineIndex, int startIndex) {
80 int length = text.length();
81 int index = startIndex;
82
83 while (index < length) {
84 // MANIFEST.MF Specification: max line length = 72
85 // http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html
86 switch (text.charAt(index)) {
87 case '\r':
88 // CR followed by LF ?
89 if ((index-startLineIndex >= 70) && (index+1 < length) && (text.charAt(index+1) == ' ')) {
90 // Multiline value
91 startLineIndex = index+1;
92 } else if ((index-startLineIndex >= 70) && (index+2 < length) && (text.charAt(index+1) == '\n') && (text.charAt(index+2) == ' ')) {
93 // Multiline value
94 index++;
95 startLineIndex = index+1;
96 } else {
97 // (End of file) or (single line value) => return end index
98 return index;
99 }
100 break;
101 case '\n':
102 if ((index-startLineIndex >= 70) && (index+1 < length) && (text.charAt(index+1) == ' ')) {
103 // Multiline value
104 startLineIndex = index+1;
105 } else {
106 // (End of file) or (single line value) => return end index
107 return index;
108 }
109 break;
110 }
111 index++;
112 }
113
114 return index;
115 }
116
117 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((ManifestHyperlinkData)hyperlinkData).enabled; }
118
119 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
120 ManifestHyperlinkData data = (ManifestHyperlinkData)hyperlinkData;
121
122 if (data.enabled) {
123 try {
124 // Save current position in history
125 Point location = textArea.getLocationOnScreen();
126 int offset = textArea.viewToModel(new Point(x-location.x, y-location.y));
127 URI uri = entry.getUri();
128 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
129 // Open link
130 String text = getText();
131 String textLink = getValue(text, hyperlinkData.startPosition, hyperlinkData.endPosition);
132 String internalTypeName = textLink.replace('.', '/');
133 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
134 String rootUri = entry.getContainer().getRoot().getUri().toString();
135 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
136
137 for (Container.Entry entry : entries) {
138 if (entry.getUri().toString().startsWith(rootUri)) {
139 sameContainerEntries.add(entry);
140 }
141 }
142
143 if (sameContainerEntries.size() > 0) {
144 api.openURI(x, y, sameContainerEntries, null, data.fragment);
145 } else if (entries.size() > 0) {
146 api.openURI(x, y, entries, null, data.fragment);
147 }
148 } catch (URISyntaxException e) {
149 assert ExceptionUtil.printStackTrace(e);
150 }
151 }
152 }
153
154 // --- UriGettable --- //
155 public URI getUri() { return entry.getUri(); }
156
157 // --- ContentSavable --- //
158 public String getFileName() {
159 String path = entry.getPath();
160 int index = path.lastIndexOf('/');
161 return path.substring(index+1);
162 }
163
164 // --- IndexesChangeListener --- //
165 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
166 // Update the list of containers
167 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
168 // Refresh links
169 boolean refresh = false;
170 String text = getText();
171
172 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
173 ManifestHyperlinkData entryData = (ManifestHyperlinkData)entry.getValue();
174 String textLink = getValue(text, entryData.startPosition, entryData.endPosition);
175 String internalTypeName = textLink.replace('.', '/');
176 boolean enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
177
178 if (entryData.enabled != enabled) {
179 entryData.enabled = enabled;
180 refresh = true;
181 }
182 }
183
184 if (refresh) {
185 textArea.repaint();
186 }
187 }
188
189 public static String getValue(String text, int startPosition, int endPosition) {
190 return text
191 // Extract text of link
192 .substring(startPosition, endPosition)
193 // Convert multiline value
194 .replace("\r\n ", "")
195 .replace("\r ", "")
196 .replace("\n ", "");
197 }
198
199 public static class ManifestHyperlinkData extends HyperlinkData {
200 public boolean enabled;
201 public String fragment;
202
203 ManifestHyperlinkData(int startPosition, int endPosition, String fragment) {
204 super(startPosition, endPosition);
205 this.enabled = false;
206 this.fragment = fragment;
207 }
208 }
209 }
210
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.*;
10 import org.fife.ui.rtextarea.Marker;
11 import org.jd.gui.api.API;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.api.model.Indexes;
14 import org.jd.gui.util.decompiler.ContainerLoader;
15 import org.jd.gui.util.decompiler.StringBuilderPrinter;
16 import org.jd.gui.util.exception.ExceptionUtil;
17 import org.jd.gui.util.index.IndexesUtil;
18
19 import javax.swing.text.Segment;
20 import java.awt.*;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.*;
24 import java.util.List;
25 import java.util.concurrent.Future;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import static org.jd.core.v1.api.printer.Printer.MODULE;
30 import static org.jd.core.v1.api.printer.Printer.PACKAGE;
31 import static org.jd.core.v1.api.printer.Printer.TYPE;
32
33 public class ModuleInfoFilePage extends ClassFilePage {
34 public static final String SYNTAX_STYLE_JAVA_MODULE = "text/java-module";
35
36 static {
37 // Add a new token maker for Java 9+ module
38 AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory)TokenMakerFactory.getDefaultInstance();
39 atmf.putMapping(SYNTAX_STYLE_JAVA_MODULE, ModuleInfoTokenMaker.class.getName());
40 }
41
42 public ModuleInfoFilePage(API api, Container.Entry entry) {
43 super(api, entry);
44 }
45
46 @Override
47 public void decompile(Map<String, String> preferences) {
48 try {
49 // Clear ...
50 clearHyperlinks();
51 clearLineNumbers();
52 typeDeclarations.clear();
53
54 // Init preferences
55 boolean unicodeEscape = getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false);
56
57 // Init loader
58 ContainerLoader loader = new ContainerLoader(entry);
59
60 // Init printer
61 ModuleInfoFilePrinter printer = new ModuleInfoFilePrinter();
62 printer.setUnicodeEscape(unicodeEscape);
63
64 // Format internal name
65 String entryPath = entry.getPath();
66 assert entryPath.endsWith(".class");
67 String entryInternalName = entryPath.substring(0, entryPath.length() - 6); // 6 = ".class".length()
68
69 // Decompile class file
70 DECOMPILER.decompile(loader, printer, entryInternalName);
71 } catch (Throwable t) {
72 assert ExceptionUtil.printStackTrace(t);
73 setText("// INTERNAL ERROR //");
74 }
75 }
76
77 @Override
78 public String getSyntaxStyle() { return SYNTAX_STYLE_JAVA_MODULE; }
79
80 @Override
81 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
82 HyperlinkReferenceData hyperlinkReferenceData = (HyperlinkReferenceData)hyperlinkData;
83
84 if (hyperlinkReferenceData.reference.enabled) {
85 try {
86 // Save current position in history
87 Point location = textArea.getLocationOnScreen();
88 int offset = textArea.viewToModel(new Point(x - location.x, y - location.y));
89 URI uri = entry.getUri();
90 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
91
92 // Open link
93 ModuleInfoReferenceData moduleInfoReferenceData = (ModuleInfoReferenceData)hyperlinkReferenceData.reference;
94 List<Container.Entry> entries;
95 String fragment;
96
97 switch (moduleInfoReferenceData.type) {
98 case TYPE:
99 entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, fragment = moduleInfoReferenceData.typeName);
100 break;
101 case PACKAGE:
102 entries = IndexesUtil.find(collectionOfFutureIndexes, "packageDeclarations", moduleInfoReferenceData.typeName);
103 fragment = null;
104 break;
105 default: // MODULE
106 entries = IndexesUtil.find(collectionOfFutureIndexes, "javaModuleDeclarations", moduleInfoReferenceData.name);
107 fragment = moduleInfoReferenceData.typeName;
108 break;
109 }
110
111 if (entries.contains(entry)) {
112 api.openURI(uri);
113 } else {
114 String rootUri = entry.getContainer().getRoot().getUri().toString();
115 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
116
117 for (Container.Entry entry : entries) {
118 if (entry.getUri().toString().startsWith(rootUri)) {
119 sameContainerEntries.add(entry);
120 }
121 }
122
123 if (sameContainerEntries.size() > 0) {
124 api.openURI(x, y, sameContainerEntries, null, fragment);
125 } else if (entries.size() > 0) {
126 api.openURI(x, y, entries, null, fragment);
127 }
128 }
129 } catch (URISyntaxException e) {
130 assert ExceptionUtil.printStackTrace(e);
131 }
132 }
133 }
134
135 // --- UriOpenable --- //
136 @Override
137 public boolean openUri(URI uri) {
138 ArrayList<DocumentRange> ranges = new ArrayList<>();
139 String fragment = uri.getFragment();
140 String query = uri.getQuery();
141
142 Marker.clearMarkAllHighlights(textArea);
143
144 if ((fragment != null) && (declarations.size() == 1)) {
145 DeclarationData declaration = declarations.entrySet().iterator().next().getValue();
146
147 if (fragment.equals(declaration.typeName)) {
148 ranges.add(new DocumentRange(declaration.startPosition, declaration.endPosition));
149 }
150 }
151
152 if (query != null) {
153 Map<String, String> parameters = parseQuery(query);
154
155 String highlightFlags = parameters.get("highlightFlags");
156 String highlightPattern = parameters.get("highlightPattern");
157
158 if ((highlightFlags != null) && (highlightPattern != null)) {
159 String regexp = createRegExp(highlightPattern);
160 Pattern pattern = Pattern.compile(regexp + ".*");
161
162 boolean t = (highlightFlags.indexOf('t') != -1); // Highlight types
163 boolean M = (highlightFlags.indexOf('M') != -1); // Highlight modules
164
165 if (highlightFlags.indexOf('d') != -1) {
166 // Highlight declarations
167 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
168 DeclarationData declaration = entry.getValue();
169
170 if (M) {
171 matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges);
172 }
173 }
174 }
175
176 if (highlightFlags.indexOf('r') != -1) {
177 // Highlight references
178 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
179 HyperlinkData hyperlink = entry.getValue();
180 ReferenceData reference = ((HyperlinkReferenceData)hyperlink).reference;
181 ModuleInfoReferenceData moduleInfoReferenceData = (ModuleInfoReferenceData)reference;
182
183 if (t && (moduleInfoReferenceData.type == TYPE)) {
184 matchAndAddDocumentRange(pattern, getMostInnerTypeName(moduleInfoReferenceData.typeName), hyperlink.startPosition, hyperlink.endPosition, ranges);
185 }
186 if (M && (moduleInfoReferenceData.type == MODULE)) {
187 matchAndAddDocumentRange(pattern, moduleInfoReferenceData.name, hyperlink.startPosition, hyperlink.endPosition, ranges);
188 }
189 }
190 }
191 }
192 }
193
194 if ((ranges != null) && !ranges.isEmpty()) {
195 textArea.setMarkAllHighlightColor(SELECT_HIGHLIGHT_COLOR);
196 Marker.markAll(textArea, ranges);
197 ranges.sort(null);
198 setCaretPositionAndCenter(ranges.get(0));
199 }
200
201 return true;
202 }
203
204 // --- IndexesChangeListener --- //
205 @Override
206 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
207 // Update the list of containers
208 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
209 // Refresh links
210 boolean refresh = false;
211
212 for (ReferenceData reference : references) {
213 ModuleInfoReferenceData moduleInfoReferenceData = (ModuleInfoReferenceData)reference;
214 boolean enabled = false;
215
216 try {
217 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
218 if (futureIndexes.isDone()) {
219 Map<String, Collection> index;
220 String key;
221
222 switch (moduleInfoReferenceData.type) {
223 case TYPE:
224 index = futureIndexes.get().getIndex("typeDeclarations");
225 key = reference.typeName;
226 break;
227 case PACKAGE:
228 index = futureIndexes.get().getIndex("packageDeclarations");
229 key = reference.typeName;
230 break;
231 default: // MODULE
232 index = futureIndexes.get().getIndex("javaModuleDeclarations");
233 key = reference.name;
234 break;
235 }
236
237 if ((index != null) && (index.get(key) != null)) {
238 enabled = true;
239 break;
240 }
241 }
242 }
243 } catch (Exception e) {
244 assert ExceptionUtil.printStackTrace(e);
245 }
246
247 if (reference.enabled != enabled) {
248 reference.enabled = enabled;
249 refresh = true;
250 }
251 }
252
253 if (refresh) {
254 textArea.repaint();
255 }
256 }
257
258 protected static class ModuleInfoReferenceData extends ReferenceData {
259 public int type;
260
261 public ModuleInfoReferenceData(int type, String typeName, String name, String descriptor, String owner) {
262 super(typeName, name, descriptor, owner);
263 this.type = type;
264 }
265 }
266
267 public class ModuleInfoFilePrinter extends StringBuilderPrinter {
268 protected HashMap<String, ReferenceData> referencesCache = new HashMap<>();
269
270 @Override
271 public void start(int maxLineNumber, int majorVersion, int minorVersion) {}
272
273 @Override
274 public void end() {
275 setText(stringBuffer.toString());
276 initLineNumbers();
277 }
278
279 @Override
280 public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
281 declarations.put(internalTypeName, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalTypeName, name, descriptor));
282 super.printDeclaration(type, internalTypeName, name, descriptor);
283 }
284
285 @Override
286 public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) {
287 String key = (type == MODULE) ? name : internalTypeName;
288 ReferenceData reference = referencesCache.get(key);
289
290 if (reference == null) {
291 reference = new ModuleInfoReferenceData(type, internalTypeName, name, descriptor, ownerInternalName);
292 referencesCache.put(key, reference);
293 references.add(reference);
294 }
295
296 addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), reference));
297 super.printReference(type, internalTypeName, name, descriptor, ownerInternalName);
298 }
299 }
300
301 // https://github.com/bobbylight/RSyntaxTextArea/wiki/Adding-Syntax-Highlighting-for-a-new-Language
302 public static class ModuleInfoTokenMaker extends AbstractTokenMaker {
303 @Override
304 public TokenMap getWordsToHighlight() {
305 TokenMap tokenMap = new TokenMap();
306
307 tokenMap.put("exports", Token.RESERVED_WORD);
308 tokenMap.put("module", Token.RESERVED_WORD);
309 tokenMap.put("open", Token.RESERVED_WORD);
310 tokenMap.put("opens", Token.RESERVED_WORD);
311 tokenMap.put("provides", Token.RESERVED_WORD);
312 tokenMap.put("requires", Token.RESERVED_WORD);
313 tokenMap.put("to", Token.RESERVED_WORD);
314 tokenMap.put("transitive", Token.RESERVED_WORD);
315 tokenMap.put("uses", Token.RESERVED_WORD);
316 tokenMap.put("with", Token.RESERVED_WORD);
317
318 return tokenMap;
319 }
320
321 @Override
322 public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
323 // This assumes all keywords, etc. were parsed as "identifiers."
324 if (tokenType==Token.IDENTIFIER) {
325 int value = wordsToHighlight.get(segment, start, end);
326 if (value != -1) {
327 tokenType = value;
328 }
329 }
330 super.addToken(segment, start, end, tokenType, startOffset);
331 }
332
333 @Override
334 public Token getTokenList(Segment text, int startTokenType, int startOffset) {
335 resetTokenList();
336
337 char[] array = text.array;
338 int offset = text.offset;
339 int end = offset + text.count;
340
341 int newStartOffset = startOffset - offset;
342
343 int currentTokenStart = offset;
344 int currentTokenType = startTokenType;
345
346 for (int i=offset; i<end; i++) {
347 char c = array[i];
348
349 switch (currentTokenType) {
350 case Token.NULL:
351 currentTokenStart = i; // Starting a new token here.
352 if (RSyntaxUtilities.isLetter(c) || (c == '_')) {
353 currentTokenType = Token.IDENTIFIER;
354 } else {
355 currentTokenType = Token.WHITESPACE;
356 }
357 break;
358 default: // Should never happen
359 case Token.WHITESPACE:
360 if (RSyntaxUtilities.isLetter(c) || (c == '_')) {
361 addToken(text, currentTokenStart, i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
362 currentTokenStart = i;
363 currentTokenType = Token.IDENTIFIER;
364 }
365 break;
366 case Token.IDENTIFIER:
367 if (!RSyntaxUtilities.isLetterOrDigit(c) && (c != '_') && (c != '.')) {
368 addToken(text, currentTokenStart, i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
369 currentTokenStart = i;
370 currentTokenType = Token.WHITESPACE;
371 }
372 break;
373 }
374 }
375
376 if (currentTokenType == Token.NULL) {
377 addNullToken();
378 }else {
379 addToken(text, currentTokenStart,end-1, currentTokenType, newStartOffset+currentTokenStart);
380 addNullToken();
381 }
382
383 return firstToken;
384 }
385 }
386 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.IndexesChangeListener;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.api.model.Indexes;
14 import org.jd.gui.util.exception.ExceptionUtil;
15 import org.jd.gui.util.index.IndexesUtil;
16
17 import java.awt.*;
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.InputStreamReader;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.*;
24 import java.util.List;
25 import java.util.concurrent.Future;
26
27 public class OneTypeReferencePerLinePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
28 protected API api;
29 protected Container.Entry entry;
30 protected Collection<Future<Indexes>> collectionOfFutureIndexes = Collections.emptyList();
31
32 public OneTypeReferencePerLinePage(API api, Container.Entry entry) {
33 this.api = api;
34 this.entry = entry;
35 // Load content file & Create hyperlinks
36 StringBuilder sb = new StringBuilder();
37 int offset = 0;
38
39 try (BufferedReader br = new BufferedReader(new InputStreamReader(entry.getInputStream()))) {
40 String line;
41
42 while ((line = br.readLine()) != null) {
43 String trim = line.trim();
44
45 if (trim.length() > 0) {
46 int startIndex = offset + line.indexOf(trim);
47 int endIndex = startIndex + trim.length();
48 String internalTypeName = trim.replace('.', '/');
49
50 addHyperlink(new TypeReferencePage.TypeHyperlinkData(startIndex, endIndex, internalTypeName));
51 }
52
53 offset += line.length() + 1;
54 sb.append(line).append('\n');
55 }
56 } catch (IOException e) {
57 assert ExceptionUtil.printStackTrace(e);
58 }
59
60 // Display
61 setText(sb.toString());
62 }
63
64 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((TypeHyperlinkData)hyperlinkData).enabled; }
65
66 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
67 TypeHyperlinkData data = (TypeHyperlinkData)hyperlinkData;
68
69 if (data.enabled) {
70 try {
71 // Save current position in history
72 Point location = textArea.getLocationOnScreen();
73 int offset = textArea.viewToModel(new Point(x-location.x, y-location.y));
74 URI uri = entry.getUri();
75 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
76
77 // Open link
78 String internalTypeName = data.internalTypeName;
79 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
80 String rootUri = entry.getContainer().getRoot().getUri().toString();
81 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
82
83 for (Container.Entry entry : entries) {
84 if (entry.getUri().toString().startsWith(rootUri)) {
85 sameContainerEntries.add(entry);
86 }
87 }
88
89 if (sameContainerEntries.size() > 0) {
90 api.openURI(x, y, sameContainerEntries, null, data.internalTypeName);
91 } else if (entries.size() > 0) {
92 api.openURI(x, y, entries, null, data.internalTypeName);
93 }
94 } catch (URISyntaxException e) {
95 assert ExceptionUtil.printStackTrace(e);
96 }
97 }
98 }
99
100 // --- UriGettable --- //
101 public URI getUri() { return entry.getUri(); }
102
103 // --- ContentSavable --- //
104 public String getFileName() {
105 String path = entry.getPath();
106 int index = path.lastIndexOf('/');
107 return path.substring(index+1);
108 }
109
110 // --- IndexesChangeListener --- //
111 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
112 // Update the list of containers
113 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
114 // Refresh links
115 boolean refresh = false;
116
117 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
118 TypeHyperlinkData entryData = (TypeHyperlinkData)entry.getValue();
119 String internalTypeName = entryData.internalTypeName;
120 boolean enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
121
122 if (entryData.enabled != enabled) {
123 entryData.enabled = enabled;
124 refresh = true;
125 }
126 }
127
128 if (refresh) {
129 textArea.repaint();
130 }
131 }
132 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.DocumentRange;
10 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
11 import org.fife.ui.rsyntaxtextarea.parser.Parser;
12 import org.fife.ui.rsyntaxtextarea.parser.ParserNotice;
13 import org.fife.ui.rsyntaxtextarea.parser.TaskTagParser.TaskNotice;
14 import org.fife.ui.rtextarea.RTextArea;
15
16 import javax.swing.*;
17 import javax.swing.event.CaretEvent;
18 import javax.swing.event.CaretListener;
19 import javax.swing.text.BadLocationException;
20 import java.awt.*;
21 import java.awt.event.MouseAdapter;
22 import java.awt.event.MouseEvent;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.text.MessageFormat;
26 import java.util.*;
27 import java.util.List;
28
29 /*
30 * 'private' access prohibit all changes ==> Copy "ErrorStrip" to JD-GUI project just to change the marker.
31 *
32 * JD-GUI uses two workarounds for RSyntaxTextArea:
33 * - org.fife.ui.rtextarea.Marker
34 * - org.jd.gui.view.component.RoundMarkErrorStrip
35 */
36
37 /*
38 * 08/10/2009
39 *
40 * ErrorStrip.java - A component that can visually show Parser messages (syntax
41 * errors, etc.) in an RSyntaxTextArea.
42 *
43 * This library is distributed under a modified BSD license. See the included
44 * RSyntaxTextArea.License.txt file for details.
45 */
46
47 /**
48 * A component to sit alongside an {@link RSyntaxTextArea} that displays
49 * colored markers for locations of interest (parser errors, marked
50 * occurrences, etc.).<p>
51 *
52 * <code>ErrorStrip</code>s display <code>ParserNotice</code>s from
53 * {@link Parser}s. Currently, the only way to get lines flagged in this
54 * component is to register a <code>Parser</code> on an RSyntaxTextArea and
55 * return <code>ParserNotice</code>s for each line to display an icon for.
56 * The severity of each notice must be at least the threshold set by
57 * {@link #setLevelThreshold(ParserNotice.Level)}
58 * to be displayed in this error strip. The default threshold is
59 * {@link ParserNotice.Level#WARNING}.<p>
60 *
61 * An <code>ErrorStrip</code> can be added to a UI like so:
62 * <pre>
63 * textArea = createTextArea();
64 * textArea.addParser(new MyParser(textArea)); // Identifies lines to display
65 * scrollPane = new RTextScrollPane(textArea, true);
66 * ErrorStrip es = new ErrorStrip(textArea);
67 * JPanel temp = new JPanel(new BorderLayout());
68 * temp.add(scrollPane);
69 * temp.add(es, BorderLayout.LINE_END);
70 * </pre>
71 *
72 * @author Robert Futrell
73 * @version 0.5
74 */
75 /*
76 * Possible improvements:
77 * 1. Handle marked occurrence changes & "mark all" changes separately from
78 * parser changes. For each property change, call a method that removes
79 * the notices being reloaded from the Markers (removing any Markers that
80 * are now "empty").
81 */
82 public class RoundMarkErrorStrip extends JComponent {
83
84 /**
85 * The text area.
86 */
87 private RSyntaxTextArea textArea;
88
89 /**
90 * Listens for events in this component.
91 */
92 private Listener listener;
93
94 /**
95 * Whether "marked occurrences" in the text area should be shown in this
96 * error strip.
97 */
98 private boolean showMarkedOccurrences;
99
100 /**
101 * Whether markers for "mark all" highlights should be shown in this
102 * error strip.
103 */
104 private boolean showMarkAll;
105
106 /**
107 * Mapping of colors to brighter colors. This is kept to prevent
108 * unnecessary creation of the same Colors over and over.
109 */
110 private Map<Color, Color> brighterColors;
111
112 /**
113 * Added for JD-GUI.
114 *
115 * Mapping of colors to darker colors. This is kept to prevent
116 * unnecessary creation of the same Colors over and over.
117 */
118 private Map<Color, Color> darkerColors;
119
120 /**
121 * Only notices of this severity (or worse) will be displayed in this
122 * error strip.
123 */
124 private ParserNotice.Level levelThreshold;
125
126 /**
127 * Whether the caret marker's location should be rendered.
128 */
129 private boolean followCaret;
130
131 /**
132 * The color to use for the caret marker.
133 */
134 private Color caretMarkerColor;
135
136 /**
137 * Where we paint the caret marker.
138 */
139 private int caretLineY;
140
141 /**
142 * The last location of the caret marker.
143 */
144 private int lastLineY;
145
146 /**
147 * The preferred width of this component.
148 */
149 private static final int PREFERRED_WIDTH = 14;
150
151 private static final String MSG = "org.fife.ui.rsyntaxtextarea.ErrorStrip";
152 private static final ResourceBundle msg = ResourceBundle.getBundle(MSG);
153
154 /**
155 * Constructor.
156 *
157 * @param textArea The text area we are examining.
158 */
159 public RoundMarkErrorStrip(RSyntaxTextArea textArea) {
160 this.textArea = textArea;
161 listener = new Listener();
162 ToolTipManager.sharedInstance().registerComponent(this);
163 setLayout(null); // Manually layout Markers as they can overlap
164 addMouseListener(listener);
165 setShowMarkedOccurrences(true);
166 setShowMarkAll(true);
167 setLevelThreshold(ParserNotice.Level.WARNING);
168 setFollowCaret(true);
169 setCaretMarkerColor(new Color(0x96c5fe));
170 }
171
172
173 /**
174 * Overridden so we only start listening for parser notices when this
175 * component (and presumably the text area) are visible.
176 */
177 @Override
178 public void addNotify() {
179 super.addNotify();
180 textArea.addCaretListener(listener);
181 textArea.addPropertyChangeListener(
182 RSyntaxTextArea.PARSER_NOTICES_PROPERTY, listener);
183 textArea.addPropertyChangeListener(
184 RSyntaxTextArea.MARK_OCCURRENCES_PROPERTY, listener);
185 textArea.addPropertyChangeListener(
186 RSyntaxTextArea.MARKED_OCCURRENCES_CHANGED_PROPERTY, listener);
187 textArea.addPropertyChangeListener(
188 RSyntaxTextArea.MARK_ALL_OCCURRENCES_CHANGED_PROPERTY, listener);
189 refreshMarkers();
190 }
191
192
193 /**
194 * Manually manages layout since this component uses no layout manager.
195 */
196 @Override
197 public void doLayout() {
198 for (int i=0; i<getComponentCount(); i++) {
199 Marker m = (Marker)getComponent(i);
200 m.updateLocation();
201 }
202 listener.caretUpdate(null); // Force recalculation of caret line pos
203 }
204
205
206 /**
207 * Returns a "brighter" color.
208 *
209 * @param c The color.
210 * @return A brighter color.
211 */
212 private Color getBrighterColor(Color c) {
213 if (brighterColors==null) {
214 brighterColors = new HashMap<Color, Color>(5); // Usually small
215 }
216 Color brighter = brighterColors.get(c);
217 if (brighter==null) {
218 // Don't use c.brighter() as it doesn't work well for blue, and
219 // also doesn't return something brighter "enough."
220 int r = possiblyBrighter(c.getRed());
221 int g = possiblyBrighter(c.getGreen());
222 int b = possiblyBrighter(c.getBlue());
223 brighter = new Color(r, g, b);
224 brighterColors.put(c, brighter);
225 }
226 return brighter;
227 }
228
229
230 /**
231 * Added for JD-GUI.
232 *
233 * Returns a "brighter" color.
234 *
235 * @param c The color.
236 * @return A brighter color.
237 */
238 private Color getDarkerColor(Color c) {
239 if (darkerColors==null) {
240 darkerColors = new HashMap<Color, Color>(5); // Usually small
241 }
242 Color darker = darkerColors.get(c);
243 if (darker==null) {
244 // Don't use c.brighter() as it doesn't work well for blue, and
245 // also doesn't return something brighter "enough."
246 int r = possiblyDarker(c.getRed());
247 int g = possiblyDarker(c.getGreen());
248 int b = possiblyDarker(c.getBlue());
249 darker = new Color(r, g, b);
250 darkerColors.put(c, darker);
251 }
252 return darker;
253 }
254
255
256 /**
257 * returns the color to use when painting the caret marker.
258 *
259 * @return The caret marker color.
260 * @see #setCaretMarkerColor(Color)
261 */
262 public Color getCaretMarkerColor() {
263 return caretMarkerColor;
264 }
265
266
267 /**
268 * Returns whether the caret's position should be drawn.
269 *
270 * @return Whether the caret's position should be drawn.
271 * @see #setFollowCaret(boolean)
272 */
273 public boolean getFollowCaret() {
274 return followCaret;
275 }
276
277
278 /**
279 * {@inheritDoc}
280 */
281 @Override
282 public Dimension getPreferredSize() {
283 int height = textArea.getPreferredScrollableViewportSize().height;
284 return new Dimension(PREFERRED_WIDTH, height);
285 }
286
287
288 /**
289 * Returns the minimum severity a parser notice must be for it to be
290 * displayed in this error strip. This will be one of the constants
291 * defined in the <code>ParserNotice</code> class.
292 *
293 * @return The minimum severity.
294 * @see #setLevelThreshold(ParserNotice.Level)
295 */
296 public ParserNotice.Level getLevelThreshold() {
297 return levelThreshold;
298 }
299
300
301 /**
302 * Returns whether "mark all" highlights are shown in this error strip.
303 *
304 * @return Whether markers are shown for "mark all" highlights.
305 * @see #setShowMarkAll(boolean)
306 */
307 public boolean getShowMarkAll() {
308 return showMarkAll;
309 }
310
311
312 /**
313 * Returns whether marked occurrences are shown in this error strip.
314 *
315 * @return Whether marked occurrences are shown.
316 * @see #setShowMarkedOccurrences(boolean)
317 */
318 public boolean getShowMarkedOccurrences() {
319 return showMarkedOccurrences;
320 }
321
322
323 /**
324 * {@inheritDoc}
325 */
326 @Override
327 public String getToolTipText(MouseEvent e) {
328 String text = null;
329 int line = yToLine(e.getY());
330 if (line>-1) {
331 text = msg.getString("Line");
332 text = MessageFormat.format(text, Integer.valueOf(line+1));
333 }
334 return text;
335 }
336
337
338 /**
339 * Returns the y-offset in this component corresponding to a line in the
340 * text component.
341 *
342 * @param line The line.
343 * @return The y-offset.
344 * @see #yToLine(int)
345 */
346 private int lineToY(int line) {
347 int h = textArea.getVisibleRect().height;
348 float lineCount = textArea.getLineCount();
349 return (int)(((line-1)/(lineCount-1)) * h) - 2;
350 }
351
352
353 /**
354 * Overridden to (possibly) draw the caret's position.
355 *
356 * @param g The graphics context.
357 */
358 @Override
359 protected void paintComponent(Graphics g) {
360 super.paintComponent(g);
361 if (caretLineY>-1) {
362 g.setColor(getCaretMarkerColor());
363 g.fillRect(0, caretLineY, getWidth(), 2);
364 }
365 }
366
367
368 /**
369 * Returns a possibly brighter component for a color.
370 *
371 * @param i An RGB component for a color (0-255).
372 * @return A possibly brighter value for the component.
373 */
374 private static final int possiblyBrighter(int i) {
375 if (i<255) {
376 i += (int)((255-i)*0.6f);
377 }
378 return i;
379 }
380
381
382 /**
383 * Returns a possibly darker component for a color.
384 *
385 * @param i An RGB component for a color (0-255).
386 * @return A possibly brighter value for the component.
387 */
388 private static final int possiblyDarker(int i) {
389 return i -= (int)(i*0.4f);
390 }
391
392
393 /**
394 * Refreshes the markers displayed in this error strip.
395 */
396 private void refreshMarkers() {
397
398 removeAll(); // listener is removed in Marker.removeNotify()
399 Map<Integer, Marker> markerMap = new HashMap<Integer, Marker>();
400
401 List<ParserNotice> notices = textArea.getParserNotices();
402 for (ParserNotice notice : notices) {
403 if (notice.getLevel().isEqualToOrWorseThan(levelThreshold) ||
404 (notice instanceof TaskNotice)) {
405 Integer key = Integer.valueOf(notice.getLine());
406 Marker m = markerMap.get(key);
407 if (m==null) {
408 m = new Marker(notice);
409 m.addMouseListener(listener);
410 markerMap.put(key, m);
411 add(m);
412 }
413 else {
414 m.addNotice(notice);
415 }
416 }
417 }
418
419 if (getShowMarkedOccurrences() && textArea.getMarkOccurrences()) {
420 List<DocumentRange> occurrences = textArea.getMarkedOccurrences();
421 addMarkersForRanges(occurrences, markerMap, textArea.getMarkOccurrencesColor());
422 }
423
424 if (getShowMarkAll() /*&& textArea.getMarkAll()*/) {
425 Color markAllColor = textArea.getMarkAllHighlightColor();
426 List<DocumentRange> ranges = textArea.getMarkAllHighlightRanges();
427 addMarkersForRanges(ranges, markerMap, markAllColor);
428 }
429
430 revalidate();
431 repaint();
432
433 }
434
435
436 /**
437 * Adds markers for a list of ranges in the document.
438 *
439 * @param ranges The list of ranges in the document.
440 * @param markerMap A mapping from line number to <code>Marker</code>.
441 * @param color The color to use for the markers.
442 */
443 private void addMarkersForRanges(List<DocumentRange> ranges,
444 Map<Integer, Marker> markerMap, Color color) {
445 for (DocumentRange range : ranges) {
446 int line = 0;
447 try {
448 line = textArea.getLineOfOffset(range.getStartOffset());
449 } catch (BadLocationException ble) { // Never happens
450 continue;
451 }
452 ParserNotice notice = new MarkedOccurrenceNotice(range, color);
453 Integer key = Integer.valueOf(line);
454 Marker m = markerMap.get(key);
455 if (m==null) {
456 m = new Marker(notice);
457 m.addMouseListener(listener);
458 markerMap.put(key, m);
459 add(m);
460 }
461 else {
462 if (!m.containsMarkedOccurence()) {
463 m.addNotice(notice);
464 }
465 }
466 }
467 }
468
469
470 /**
471 * {@inheritDoc}
472 */
473 @Override
474 public void removeNotify() {
475 super.removeNotify();
476 textArea.removeCaretListener(listener);
477 textArea.removePropertyChangeListener(
478 RSyntaxTextArea.PARSER_NOTICES_PROPERTY, listener);
479 textArea.removePropertyChangeListener(
480 RSyntaxTextArea.MARK_OCCURRENCES_PROPERTY, listener);
481 textArea.removePropertyChangeListener(
482 RSyntaxTextArea.MARKED_OCCURRENCES_CHANGED_PROPERTY, listener);
483 textArea.removePropertyChangeListener(
484 RSyntaxTextArea.MARK_ALL_OCCURRENCES_CHANGED_PROPERTY, listener);
485 }
486
487
488 /**
489 * Sets the color to use when painting the caret marker.
490 *
491 * @param color The new caret marker color.
492 * @see #getCaretMarkerColor()
493 */
494 public void setCaretMarkerColor(Color color) {
495 if (color!=null) {
496 caretMarkerColor = color;
497 listener.caretUpdate(null); // Force repaint
498 }
499 }
500
501
502 /**
503 * Toggles whether the caret's current location should be drawn.
504 *
505 * @param follow Whether the caret's current location should be followed.
506 * @see #getFollowCaret()
507 */
508 public void setFollowCaret(boolean follow) {
509 if (followCaret!=follow) {
510 if (followCaret) {
511 repaint(0,caretLineY, getWidth(),2); // Erase
512 }
513 caretLineY = -1;
514 lastLineY = -1;
515 followCaret = follow;
516 listener.caretUpdate(null); // Possibly repaint
517 }
518 }
519
520
521 /**
522 * Sets the minimum severity a parser notice must be for it to be displayed
523 * in this error strip. This should be one of the constants defined in
524 * the <code>ParserNotice</code> class. The default value is
525 * {@link ParserNotice.Level#WARNING}.
526 *
527 * @param level The new severity threshold.
528 * @see #getLevelThreshold()
529 * @see ParserNotice
530 */
531 public void setLevelThreshold(ParserNotice.Level level) {
532 levelThreshold = level;
533 if (isDisplayable()) {
534 refreshMarkers();
535 }
536 }
537
538
539 /**
540 * Sets whether "mark all" highlights are shown in this error strip.
541 *
542 * @param show Whether to show markers for "mark all" highlights.
543 * @see #getShowMarkAll()
544 */
545 public void setShowMarkAll(boolean show) {
546 if (show!=showMarkAll) {
547 showMarkAll = show;
548 if (isDisplayable()) { // Skip this when we're first created
549 refreshMarkers();
550 }
551 }
552 }
553
554
555 /**
556 * Sets whether marked occurrences are shown in this error strip.
557 *
558 * @param show Whether to show marked occurrences.
559 * @see #getShowMarkedOccurrences()
560 */
561 public void setShowMarkedOccurrences(boolean show) {
562 if (show!=showMarkedOccurrences) {
563 showMarkedOccurrences = show;
564 if (isDisplayable()) { // Skip this when we're first created
565 refreshMarkers();
566 }
567 }
568 }
569
570
571 /**
572 * Returns the line in the text area corresponding to a y-offset in this
573 * component.
574 *
575 * @param y The y-offset.
576 * @return The line.
577 * @see #lineToY(int)
578 */
579 private final int yToLine(int y) {
580 int line = -1;
581 int h = textArea.getVisibleRect().height;
582 if (y<h) {
583 float at = y/(float)h;
584 line = Math.round((textArea.getLineCount()-1)*at);
585 }
586 return line;
587 }
588
589
590 /**
591 * Listens for events in the error strip and its markers.
592 */
593 private class Listener extends MouseAdapter
594 implements PropertyChangeListener, CaretListener {
595
596 private Rectangle visibleRect = new Rectangle();
597
598 public void caretUpdate(CaretEvent e) {
599 if (getFollowCaret()) {
600 int line = textArea.getCaretLineNumber();
601 float percent = line / (float)(textArea.getLineCount()-1);
602 textArea.computeVisibleRect(visibleRect);
603 caretLineY = (int)(visibleRect.height*percent);
604 if (caretLineY!=lastLineY) {
605 repaint(0,lastLineY, getWidth(), 2); // Erase old position
606 repaint(0,caretLineY, getWidth(), 2);
607 lastLineY = caretLineY;
608 }
609 }
610 }
611
612 @Override
613 public void mouseClicked(MouseEvent e) {
614
615 Component source = (Component)e.getSource();
616 if (source instanceof Marker) {
617 ((Marker)source).mouseClicked(e);
618 return;
619 }
620
621 int line = yToLine(e.getY());
622 if (line>-1) {
623 try {
624 int offs = textArea.getLineStartOffset(line);
625 textArea.setCaretPosition(offs);
626 } catch (BadLocationException ble) { // Never happens
627 UIManager.getLookAndFeel().provideErrorFeedback(textArea);
628 }
629 }
630
631 }
632
633 public void propertyChange(PropertyChangeEvent e) {
634
635 String propName = e.getPropertyName();
636
637 // If they change whether marked occurrences are visible in editor
638 if (RSyntaxTextArea.MARK_OCCURRENCES_PROPERTY.equals(propName)) {
639 if (getShowMarkedOccurrences()) {
640 refreshMarkers();
641 }
642 }
643
644 // If parser notices changed.
645 // TODO: Don't update "mark all/occurrences" markers.
646 else if (RSyntaxTextArea.PARSER_NOTICES_PROPERTY.equals(propName)) {
647 refreshMarkers();
648 }
649
650 // If marked occurrences changed.
651 // TODO: Only update "mark occurrences" markers, not all of them.
652 else if (RSyntaxTextArea.MARKED_OCCURRENCES_CHANGED_PROPERTY.
653 equals(propName)) {
654 if (getShowMarkedOccurrences()) {
655 refreshMarkers();
656 }
657 }
658
659 // If "mark all" occurrences changed.
660 // TODO: Only update "mark all" markers, not all of them.
661 else if (RTextArea.MARK_ALL_OCCURRENCES_CHANGED_PROPERTY.
662 equals(propName)) {
663 if (getShowMarkAll()) {
664 refreshMarkers();
665 }
666 }
667
668 }
669
670 }
671
672
673 /**
674 * A notice that wraps a "marked occurrence."
675 */
676 private class MarkedOccurrenceNotice implements ParserNotice {
677
678 private DocumentRange range;
679 private Color color;
680
681 public MarkedOccurrenceNotice(DocumentRange range, Color color) {
682 this.range = range;
683 this.color = color;
684 }
685
686 public int compareTo(ParserNotice other) {
687 return 0; // Value doesn't matter
688 }
689
690 public boolean containsPosition(int pos) {
691 return pos>=range.getStartOffset() && pos<range.getEndOffset();
692 }
693
694 @Override
695 public boolean equals(Object o) {
696 // FindBugs - Define equals() when defining compareTo()
697 if (!(o instanceof ParserNotice)) {
698 return false;
699 }
700 return compareTo((ParserNotice)o)==0;
701 }
702
703 public Color getColor() {
704 return color;
705 }
706
707 /**
708 * {@inheritDoc}
709 */
710 public boolean getKnowsOffsetAndLength() {
711 return true;
712 }
713
714 public int getLength() {
715 return range.getEndOffset() - range.getStartOffset();
716 }
717
718 public Level getLevel() {
719 return Level.INFO; // Won't matter
720 }
721
722 public int getLine() {
723 try {
724 return textArea.getLineOfOffset(range.getStartOffset())+1;
725 } catch (BadLocationException ble) {
726 return 0;
727 }
728 }
729
730 public String getMessage() {
731 String text = null;
732 try {
733 String word = textArea.getText(range.getStartOffset(),
734 getLength());
735 text = msg.getString("OccurrenceOf");
736 text = MessageFormat.format(text, word);
737 } catch (BadLocationException ble) {
738 UIManager.getLookAndFeel().provideErrorFeedback(textArea);
739 }
740 return text;
741 }
742
743 public int getOffset() {
744 return range.getStartOffset();
745 }
746
747 public Parser getParser() {
748 return null;
749 }
750
751 public boolean getShowInEditor() {
752 return false; // Value doesn't matter
753 }
754
755 public String getToolTipText() {
756 return null;
757 }
758
759 @Override
760 public int hashCode() { // FindBugs, since we override equals()
761 return 0; // Value doesn't matter for us.
762 }
763
764 }
765
766
767 /**
768 * A "marker" in this error strip, representing one or more notices.
769 */
770 private class Marker extends JComponent {
771
772 private List<ParserNotice> notices;
773
774 public Marker(ParserNotice notice) {
775 notices = new ArrayList<ParserNotice>(1); // Usually just 1
776 addNotice(notice);
777 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
778 setSize(getPreferredSize());
779 ToolTipManager.sharedInstance().registerComponent(this);
780 }
781
782 public void addNotice(ParserNotice notice) {
783 notices.add(notice);
784 }
785
786 public boolean containsMarkedOccurence() {
787 boolean result = false;
788 for (int i=0; i<notices.size(); i++) {
789 if (notices.get(i) instanceof MarkedOccurrenceNotice) {
790 result = true;
791 break;
792 }
793 }
794 return result;
795 }
796
797 public Color getColor() {
798 // Return the color for the highest-level parser.
799 Color c = null;
800 int lowestLevel = Integer.MAX_VALUE; // ERROR is 0
801 for (ParserNotice notice : notices) {
802 if (notice.getLevel().getNumericValue()<lowestLevel) {
803 lowestLevel = notice.getLevel().getNumericValue();
804 c = notice.getColor();
805 }
806 }
807 return c;
808 }
809
810 @Override
811 public Dimension getPreferredSize() {
812 int w = PREFERRED_WIDTH - 4; // 2-pixel empty border
813 return new Dimension(w, 5);
814 }
815
816 @Override
817 public String getToolTipText() {
818
819 String text = null;
820
821 if (notices.size()==1) {
822 text = notices.get(0).getMessage();
823 }
824 else { // > 1
825 StringBuilder sb = new StringBuilder("<html>");
826 sb.append(msg.getString("MultipleMarkers"));
827 sb.append("<br>");
828 for (int i=0; i<notices.size(); i++) {
829 ParserNotice pn = notices.get(i);
830 sb.append("&nbsp;&nbsp;&nbsp;- ");
831 sb.append(pn.getMessage());
832 sb.append("<br>");
833 }
834 text = sb.toString();
835 }
836
837 return text;
838
839 }
840
841 protected void mouseClicked(MouseEvent e) {
842 ParserNotice pn = notices.get(0);
843 int offs = pn.getOffset();
844 int len = pn.getLength();
845 if (offs>-1 && len>-1) { // These values are optional
846 textArea.setSelectionStart(offs);
847 textArea.setSelectionEnd(offs+len);
848 }
849 else {
850 int line = pn.getLine();
851 try {
852 offs = textArea.getLineStartOffset(line);
853 textArea.setCaretPosition(offs);
854 } catch (BadLocationException ble) { // Never happens
855 UIManager.getLookAndFeel().provideErrorFeedback(textArea);
856 }
857 }
858 }
859
860 @Override
861 protected void paintComponent(Graphics g) {
862
863 // TODO: Give "priorities" and always pick color of a notice with
864 // highest priority (e.g. parsing errors will usually be red).
865
866 Color color = getColor();
867 if (color==null) {
868 color = Color.GRAY;
869 }
870
871 Color brighterColor = getBrighterColor(color);
872 Color darkerColor = getDarkerColor(color);
873
874 int w = getWidth();
875 int h = getHeight();
876
877 // Draw background
878 g.setColor(color);
879 g.fillRect(0,0, w,h);
880
881 // Draw border
882 w--;
883 h--;
884
885 g.setColor(darkerColor);
886 g.drawLine(w,0, w,h);
887 g.drawRect(0,h, w,h);
888
889 g.setColor(brighterColor);
890 g.drawLine(0,0, w,0);
891 g.drawRect(0,0, 0,h);
892 }
893
894 @Override
895 public void removeNotify() {
896 super.removeNotify();
897 ToolTipManager.sharedInstance().unregisterComponent(this);
898 removeMouseListener(listener);
899 }
900
901 public void updateLocation() {
902 int line = notices.get(0).getLine();
903 int y = lineToY(line);
904 setLocation(2, y);
905 }
906
907 }
908
909
910 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContentCopyable;
11 import org.jd.gui.api.feature.ContentSavable;
12 import org.jd.gui.api.feature.ContentSelectable;
13 import org.jd.gui.util.exception.ExceptionUtil;
14 import org.jd.gui.util.io.NewlineOutputStream;
15
16 import java.awt.datatransfer.StringSelection;
17 import java.io.IOException;
18 import java.io.OutputStream;
19 import java.io.OutputStreamWriter;
20
21 public class TextPage extends AbstractTextPage implements ContentCopyable, ContentSelectable, ContentSavable {
22
23 // --- ContentCopyable --- //
24 @Override
25 public void copy() {
26 if (textArea.getSelectionStart() == textArea.getSelectionEnd()) {
27 getToolkit().getSystemClipboard().setContents(new StringSelection(""), null);
28 } else {
29 textArea.copyAsStyledText();
30 }
31 }
32
33 // --- ContentSelectable --- //
34 @Override
35 public void selectAll() {
36 textArea.selectAll();
37 }
38
39 // --- ContentSavable --- //
40 @Override
41 public String getFileName() { return "file.txt"; }
42
43 @Override
44 public void save(API api, OutputStream os) {
45 try (OutputStreamWriter writer = new OutputStreamWriter(new NewlineOutputStream(os), "UTF-8")) {
46 writer.write(textArea.getText());
47 } catch (IOException e) {
48 assert ExceptionUtil.printStackTrace(e);
49 }
50 }
51 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6 package org.jd.gui.view.component;
7
8 import org.fife.ui.rsyntaxtextarea.DocumentRange;
9 import org.fife.ui.rtextarea.Marker;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.FocusedTypeGettable;
12 import org.jd.gui.api.feature.IndexesChangeListener;
13 import org.jd.gui.api.feature.UriGettable;
14 import org.jd.gui.api.feature.UriOpenable;
15 import org.jd.gui.api.model.Container;
16 import org.jd.gui.api.model.Indexes;
17 import org.jd.gui.api.model.Type;
18 import org.jd.gui.util.exception.ExceptionUtil;
19 import org.jd.gui.util.index.IndexesUtil;
20 import org.jd.gui.util.matcher.DescriptorMatcher;
21
22 import java.awt.*;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.util.*;
26 import java.util.List;
27 import java.util.concurrent.Future;
28 import java.util.function.BiFunction;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31
32 public abstract class TypePage extends CustomLineNumbersPage implements UriGettable, UriOpenable, IndexesChangeListener, FocusedTypeGettable {
33 protected API api;
34 protected Container.Entry entry;
35 protected Collection<Future<Indexes>> collectionOfFutureIndexes = Collections.emptyList();
36
37 protected HashMap<String, DeclarationData> declarations = new HashMap<>();
38 protected TreeMap<Integer, DeclarationData> typeDeclarations = new TreeMap<>();
39 protected ArrayList<ReferenceData> references = new ArrayList<>();
40 protected ArrayList<StringData> strings = new ArrayList<>();
41
42 public TypePage(API api, Container.Entry entry) {
43 // Init attributes
44 this.api = api;
45 this.entry = entry;
46 }
47
48 @Override
49 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) {
50 return ((HyperlinkReferenceData)hyperlinkData).reference.enabled;
51 }
52
53 @Override
54 @SuppressWarnings("unchecked")
55 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
56 HyperlinkReferenceData hyperlinkReferenceData = (HyperlinkReferenceData)hyperlinkData;
57
58 if (hyperlinkReferenceData.reference.enabled) {
59 try {
60 // Save current position in history
61 Point location = textArea.getLocationOnScreen();
62 int offset = textArea.viewToModel(new Point(x - location.x, y - location.y));
63 URI uri = entry.getUri();
64 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
65
66 // Open link
67 ReferenceData reference = hyperlinkReferenceData.reference;
68 String typeName = reference.typeName;
69 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, typeName);
70 String fragment = typeName;
71
72 if (reference.name != null) {
73 fragment += '-' + reference.name;
74 }
75 if (reference.descriptor != null) {
76 fragment += '-' + reference.descriptor;
77 }
78
79 if (entries.contains(entry)) {
80 api.openURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), fragment));
81 } else {
82 String rootUri = entry.getContainer().getRoot().getUri().toString();
83 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
84
85 for (Container.Entry entry : entries) {
86 if (entry.getUri().toString().startsWith(rootUri)) {
87 sameContainerEntries.add(entry);
88 }
89 }
90
91 if (sameContainerEntries.size() > 0) {
92 api.openURI(x, y, sameContainerEntries, null, fragment);
93 } else if (entries.size() > 0) {
94 api.openURI(x, y, entries, null, fragment);
95 }
96 }
97 } catch (URISyntaxException e) {
98 assert ExceptionUtil.printStackTrace(e);
99 }
100 }
101 }
102
103 // --- UriGettable --- //
104 @Override public URI getUri() { return entry.getUri(); }
105
106 // --- UriOpenable --- //
107 /**
108 * @param uri for URI format, @see jd.gui.api.feature.UriOpenable
109 */
110 @Override
111 public boolean openUri(URI uri) {
112 ArrayList<DocumentRange> ranges = new ArrayList<>();
113 String fragment = uri.getFragment();
114 String query = uri.getQuery();
115
116 Marker.clearMarkAllHighlights(textArea);
117
118 if (fragment != null) {
119 matchFragmentAndAddDocumentRange(fragment, declarations, ranges);
120 }
121
122 if (query != null) {
123 Map<String, String> parameters = parseQuery(query);
124
125 if (parameters.containsKey("lineNumber")) {
126 String lineNumber = parameters.get("lineNumber");
127
128 try {
129 goToLineNumber(Integer.parseInt(lineNumber));
130 return true;
131 } catch (NumberFormatException e) {
132 assert ExceptionUtil.printStackTrace(e);
133 }
134 } else if (parameters.containsKey("position")) {
135 String position = parameters.get("position");
136
137 try {
138 int pos = Integer.parseInt(position);
139 if (textArea.getDocument().getLength() > pos) {
140 ranges.add(new DocumentRange(pos, pos));
141 }
142 } catch (NumberFormatException e) {
143 assert ExceptionUtil.printStackTrace(e);
144 }
145 } else {
146 matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges);
147 }
148 }
149
150 if ((ranges != null) && !ranges.isEmpty()) {
151 textArea.setMarkAllHighlightColor(SELECT_HIGHLIGHT_COLOR);
152 Marker.markAll(textArea, ranges);
153 ranges.sort(null);
154 setCaretPositionAndCenter(ranges.get(0));
155 }
156
157 return true;
158 }
159
160 public static void matchFragmentAndAddDocumentRange(String fragment, HashMap<String, DeclarationData> declarations, List<DocumentRange> ranges) {
161 if ((fragment.indexOf('?') != -1) || (fragment.indexOf('*') != -1)) {
162 // Unknown type and/or descriptor ==> Select all and scroll to the first one
163 int lastDash = fragment.lastIndexOf('-');
164
165 if (lastDash == -1) {
166 // Search types
167 String slashAndTypeName = fragment.substring(1);
168 String typeName = fragment.substring(2);
169
170 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
171 if (entry.getKey().endsWith(slashAndTypeName) || entry.getKey().equals(typeName)) {
172 ranges.add(new DocumentRange(entry.getValue().startPosition, entry.getValue().endPosition));
173 }
174 }
175 } else {
176 String prefix = fragment.substring(0, lastDash+1);
177 String suffix = fragment.substring(lastDash+1);
178 BiFunction<String, String, Boolean> matchDescriptors;
179
180 if (suffix.charAt(0) == '(') {
181 matchDescriptors = DescriptorMatcher::matchMethodDescriptors;
182 } else {
183 matchDescriptors = DescriptorMatcher::matchFieldDescriptors;
184 }
185
186 if (fragment.charAt(0) == '*') {
187 // Unknown type
188 String slashAndTypeNameAndName = prefix.substring(1);
189 String typeNameAndName = prefix.substring(2);
190
191 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
192 String key = entry.getKey();
193 if ((key.indexOf(slashAndTypeNameAndName) != -1) || (key.startsWith(typeNameAndName))) {
194 int index = key.lastIndexOf('-') + 1;
195 if (matchDescriptors.apply(suffix, key.substring(index))) {
196 ranges.add(new DocumentRange(entry.getValue().startPosition, entry.getValue().endPosition));
197 }
198 }
199 }
200 } else {
201 // Known type
202 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
203 String key = entry.getKey();
204 if (key.startsWith(prefix)) {
205 int index = key.lastIndexOf('-') + 1;
206 if (matchDescriptors.apply(suffix, key.substring(index))) {
207 ranges.add(new DocumentRange(entry.getValue().startPosition, entry.getValue().endPosition));
208 }
209 }
210 }
211 }
212 }
213 } else {
214 // Known type and descriptor ==> Search and high light item
215 DeclarationData data = declarations.get(fragment);
216 if (data != null) {
217 ranges.add(new DocumentRange(data.startPosition, data.endPosition));
218 } else if (fragment.endsWith("-<clinit>-()V")) {
219 // 'static' bloc not found ==> Select type declaration
220 String typeName = fragment.substring(0, fragment.indexOf('-'));
221 data = declarations.get(typeName);
222 ranges.add(new DocumentRange(data.startPosition, data.endPosition));
223 }
224 }
225 }
226
227 public static void matchQueryAndAddDocumentRange(
228 Map<String, String> parameters,
229 HashMap<String, DeclarationData> declarations, TreeMap<Integer, HyperlinkData> hyperlinks, ArrayList<StringData> strings,
230 List<DocumentRange> ranges) {
231
232 String highlightFlags = parameters.get("highlightFlags");
233 String highlightPattern = parameters.get("highlightPattern");
234
235 if ((highlightFlags != null) && (highlightPattern != null)) {
236 String highlightScope = parameters.get("highlightScope");
237 String regexp = createRegExp(highlightPattern);
238 Pattern pattern = Pattern.compile(regexp + ".*");
239
240 if (highlightFlags.indexOf('s') != -1) {
241 // Highlight strings
242 Pattern patternForString = Pattern.compile(regexp);
243
244 for (StringData data : strings) {
245 if (matchScope(highlightScope, data.owner)) {
246 Matcher matcher = patternForString.matcher(data.text);
247 int offset = data.startPosition;
248
249 while(matcher.find()) {
250 ranges.add(new DocumentRange(offset + matcher.start(), offset + matcher.end()));
251 }
252 }
253 }
254 }
255
256 boolean t = (highlightFlags.indexOf('t') != -1); // Highlight types
257 boolean f = (highlightFlags.indexOf('f') != -1); // Highlight fields
258 boolean m = (highlightFlags.indexOf('m') != -1); // Highlight methods
259 boolean c = (highlightFlags.indexOf('c') != -1); // Highlight constructors
260
261 if (highlightFlags.indexOf('d') != -1) {
262 // Highlight declarations
263 for (Map.Entry<String, DeclarationData> entry : declarations.entrySet()) {
264 DeclarationData declaration = entry.getValue();
265
266 if (matchScope(highlightScope, declaration.typeName)) {
267 if ((t && declaration.isAType()) || (c && declaration.isAConstructor())) {
268 matchAndAddDocumentRange(pattern, getMostInnerTypeName(declaration.typeName), declaration.startPosition, declaration.endPosition, ranges);
269 }
270 if ((f && declaration.isAField()) || (m && declaration.isAMethod())) {
271 matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges);
272 }
273 }
274 }
275 }
276
277 if (highlightFlags.indexOf('r') != -1) {
278 // Highlight references
279 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
280 HyperlinkData hyperlink = entry.getValue();
281 ReferenceData reference = ((HyperlinkReferenceData)hyperlink).reference;
282
283 if (matchScope(highlightScope, reference.owner)) {
284 if ((t && reference.isAType()) || (c && reference.isAConstructor())) {
285 matchAndAddDocumentRange(pattern, getMostInnerTypeName(reference.typeName), hyperlink.startPosition, hyperlink.endPosition, ranges);
286 }
287 if ((f && reference.isAField()) || (m && reference.isAMethod())) {
288 matchAndAddDocumentRange(pattern, reference.name, hyperlink.startPosition, hyperlink.endPosition, ranges);
289 }
290 }
291 }
292 }
293 }
294 }
295
296 public static boolean matchScope(String scope, String type) {
297 if ((scope == null) || scope.isEmpty())
298 return true;
299 if (scope.charAt(0) == '*')
300 return type.endsWith(scope.substring(1)) || type.equals(scope.substring(2));
301 return type.equals(scope);
302 }
303
304 public static void matchAndAddDocumentRange(Pattern pattern, String text, int start, int end, List<DocumentRange> ranges) {
305 if (pattern.matcher(text).matches()) {
306 ranges.add(new DocumentRange(start, end));
307 }
308 }
309
310 public static String getMostInnerTypeName(String typeName) {
311 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
312 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
313 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
314 return typeName.substring(lastIndex);
315 }
316
317 // --- FocusedTypeGettable --- //
318 @Override public String getFocusedTypeName() {
319 Map.Entry<Integer, DeclarationData> entry = typeDeclarations.floorEntry(textArea.getCaretPosition());
320
321 if (entry != null) {
322 DeclarationData data = entry.getValue();
323 if (data != null) {
324 return data.typeName;
325 }
326 }
327
328 return null;
329 }
330
331 @Override public Container.Entry getEntry() { return entry; }
332
333 // --- IndexesChangeListener --- //
334 @Override
335 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
336 // Update the list of containers
337 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
338 // Refresh links
339 boolean refresh = false;
340
341 for (ReferenceData reference : references) {
342 String typeName = reference.typeName;
343 boolean enabled;
344
345 if (reference.name == null) {
346 enabled = false;
347
348 try {
349 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
350 if (futureIndexes.isDone()) {
351 Map<String, Collection> index = futureIndexes.get().getIndex("typeDeclarations");
352 if ((index != null) && (index.get(typeName) != null)) {
353 enabled = true;
354 break;
355 }
356 }
357 }
358 } catch (Exception e) {
359 assert ExceptionUtil.printStackTrace(e);
360 }
361 } else {
362 try {
363 // Recursive search
364 typeName = searchTypeHavingMember(typeName, reference.name, reference.descriptor, entry);
365 if (typeName != null) {
366 // Replace type with the real type having the referenced member
367 reference.typeName = typeName;
368 enabled = true;
369 } else {
370 enabled = false;
371 }
372 } catch (Error e) {
373 // Catch StackOverflowError or OutOfMemoryError
374 assert ExceptionUtil.printStackTrace(e);
375 enabled = false;
376 }
377 }
378
379 if (reference.enabled != enabled) {
380 reference.enabled = enabled;
381 refresh = true;
382 }
383 }
384
385 if (refresh) {
386 textArea.repaint();
387 }
388 }
389
390 @SuppressWarnings("unchecked")
391 protected String searchTypeHavingMember(String typeName, String name, String descriptor, Container.Entry entry) {
392 ArrayList<Container.Entry> entries = new ArrayList<>();
393
394 try {
395 for (Future<Indexes> futureIndexes : collectionOfFutureIndexes) {
396 if (futureIndexes.isDone()) {
397 Map<String, Collection> index = futureIndexes.get().getIndex("typeDeclarations");
398 if (index != null) {
399 Collection<Container.Entry> collection = index.get(typeName);
400 if (collection != null) {
401 entries.addAll(collection);
402 }
403 }
404 }
405 }
406 } catch (Exception e) {
407 assert ExceptionUtil.printStackTrace(e);
408 }
409
410 String rootUri = entry.getContainer().getRoot().getUri().toString();
411 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
412
413 for (Container.Entry e : entries) {
414 if (e.getUri().toString().startsWith(rootUri)) {
415 sameContainerEntries.add(e);
416 }
417 }
418
419 if (sameContainerEntries.size() > 0) {
420 return searchTypeHavingMember(typeName, name, descriptor, sameContainerEntries);
421 } else {
422 return searchTypeHavingMember(typeName, name, descriptor, entries);
423 }
424 }
425
426 protected String searchTypeHavingMember(String typeName, String name, String descriptor, List<Container.Entry> entries) {
427 for (Container.Entry entry : entries) {
428 Type type = api.getTypeFactory(entry).make(api, entry, typeName);
429
430 if (type != null) {
431 if (descriptor.indexOf('(') == -1) {
432 // Search a field
433 for (Type.Field field : type.getFields()) {
434 if (field.getName().equals(name) && DescriptorMatcher.matchFieldDescriptors(field.getDescriptor(), descriptor)) {
435 // Field found
436 return typeName;
437 }
438 }
439 } else {
440 // Search a method
441 for (Type.Method method : type.getMethods()) {
442 if (method.getName().equals(name) && DescriptorMatcher.matchMethodDescriptors(method.getDescriptor(), descriptor)) {
443 // Method found
444 return typeName;
445 }
446 }
447 }
448
449 // Not found -> Search in super type
450 String typeOwnerName = searchTypeHavingMember(type.getSuperName(), name, descriptor, entry);
451 if (typeOwnerName != null) {
452 return typeOwnerName;
453 }
454 }
455 }
456
457 return null;
458 }
459
460 public static class StringData {
461 int startPosition;
462 int endPosition;
463 String text;
464 String owner;
465
466 public StringData(int startPosition, int length, String text, String owner) {
467 this.startPosition = startPosition;
468 this.endPosition = startPosition + length;
469 this.text = text;
470 this.owner = owner;
471 }
472 }
473
474 public static class DeclarationData {
475 int startPosition;
476 int endPosition;
477 String typeName;
478 /**
479 * Field or method name or null for type
480 */
481 String name;
482 String descriptor;
483
484 public DeclarationData(int startPosition, int length, String typeName, String name, String descriptor) {
485 this.startPosition = startPosition;
486 this.endPosition = startPosition + length;
487 this.typeName = typeName;
488 this.name = name;
489 this.descriptor = descriptor;
490 }
491
492 public boolean isAType() { return name == null; }
493 public boolean isAField() { return (descriptor != null) && descriptor.charAt(0) != '('; }
494 public boolean isAMethod() { return (descriptor != null) && descriptor.charAt(0) == '('; }
495 public boolean isAConstructor() { return "<init>".equals(name); }
496 }
497
498 public static class HyperlinkReferenceData extends HyperlinkData {
499 public ReferenceData reference;
500
501 public HyperlinkReferenceData(int startPosition, int length, ReferenceData reference) {
502 super(startPosition, startPosition+length);
503 this.reference = reference;
504 }
505 }
506
507 protected static class ReferenceData {
508 public String typeName;
509 /**
510 * Field or method name or null for type
511 */
512 public String name;
513 /**
514 * Field or method descriptor or null for type
515 */
516 public String descriptor;
517 /**
518 * Internal type name containing reference or null for "import" statement.
519 * Used to high light items matching with URI like "file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=type".
520 */
521 public String owner;
522 /**
523 * "Enabled" flag for link of reference
524 */
525 public boolean enabled = false;
526
527 public ReferenceData(String typeName, String name, String descriptor, String owner) {
528 this.typeName = typeName;
529 this.name = name;
530 this.descriptor = descriptor;
531 this.owner = owner;
532 }
533
534 boolean isAType() { return name == null; }
535 boolean isAField() { return (descriptor != null) && descriptor.charAt(0) != '('; }
536 boolean isAMethod() { return (descriptor != null) && descriptor.charAt(0) == '('; }
537 boolean isAConstructor() { return "<init>".equals(name); }
538 }
539 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.DocumentRange;
10 import org.fife.ui.rtextarea.Marker;
11 import org.jd.gui.util.exception.ExceptionUtil;
12
13 import java.net.URI;
14 import java.util.ArrayList;
15 import java.util.Map;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18
19 /**
20 * Page containing type references (Hyperlinks to pages of type)
21 */
22 public abstract class TypeReferencePage extends HyperlinkPage {
23
24 // --- UriOpenable --- //
25 public boolean openUri(URI uri) {
26 ArrayList<DocumentRange> ranges = new ArrayList<>();
27 String query = uri.getQuery();
28
29 Marker.clearMarkAllHighlights(textArea);
30
31 if (query != null) {
32 Map<String, String> parameters = parseQuery(query);
33
34 if (parameters.containsKey("lineNumber")) {
35 String lineNumber = parameters.get("lineNumber");
36
37 try {
38 goToLineNumber(Integer.parseInt(lineNumber));
39 return true;
40 } catch (NumberFormatException e) {
41 assert ExceptionUtil.printStackTrace(e);
42 }
43 } else if (parameters.containsKey("position")) {
44 String position = parameters.get("position");
45
46 try {
47 int pos = Integer.parseInt(position);
48 if (textArea.getDocument().getLength() > pos) {
49 ranges.add(new DocumentRange(pos, pos));
50 }
51 } catch (NumberFormatException e) {
52 assert ExceptionUtil.printStackTrace(e);
53 }
54 } else {
55 String highlightFlags = parameters.get("highlightFlags");
56 String highlightPattern = parameters.get("highlightPattern");
57
58 if ((highlightFlags != null) && (highlightPattern != null)) {
59 String regexp = createRegExp(highlightPattern);
60
61 if (highlightFlags.indexOf('s') != -1) {
62 // Highlight strings
63 Pattern pattern = Pattern.compile(regexp);
64 Matcher matcher = pattern.matcher(textArea.getText());
65
66 while (matcher.find()) {
67 ranges.add(new DocumentRange(matcher.start(), matcher.end()));
68 }
69 }
70
71 if ((highlightFlags.indexOf('t') != -1) && (highlightFlags.indexOf('r') != -1)) {
72 // Highlight type references
73 Pattern pattern = Pattern.compile(regexp + ".*");
74
75 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
76 TypeHyperlinkData hyperlink = (TypeHyperlinkData)entry.getValue();
77 String name = getMostInnerTypeName(hyperlink.internalTypeName);
78
79 if (pattern.matcher(name).matches()) {
80 ranges.add(new DocumentRange(hyperlink.startPosition, hyperlink.endPosition));
81 }
82 }
83 }
84 }
85 }
86 }
87
88 if ((ranges != null) && !ranges.isEmpty()) {
89 textArea.setMarkAllHighlightColor(SELECT_HIGHLIGHT_COLOR);
90 Marker.markAll(textArea, ranges);
91 ranges.sort(null);
92 setCaretPositionAndCenter(ranges.get(0));
93 }
94
95 return false;
96 }
97
98 public String getMostInnerTypeName(String typeName) {
99 int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1;
100 int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1;
101 int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex);
102 return typeName.substring(lastIndex);
103 }
104
105 public static class TypeHyperlinkData extends HyperlinkData {
106 public boolean enabled;
107 public String internalTypeName;
108
109 TypeHyperlinkData(int startPosition, int endPosition, String internalTypeName) {
110 super(startPosition, endPosition);
111 this.enabled = false;
112 this.internalTypeName = internalTypeName;
113 }
114 }
115 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.IndexesChangeListener;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.api.model.Indexes;
15 import org.jd.gui.util.exception.ExceptionUtil;
16 import org.jd.gui.util.index.IndexesUtil;
17 import org.jd.gui.util.io.TextReader;
18 import org.jd.gui.util.xml.AbstractXmlPathFinder;
19
20 import java.awt.*;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.*;
24 import java.util.List;
25 import java.util.concurrent.Future;
26
27 public class WebXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
28 protected API api;
29 protected Container.Entry entry;
30 protected Collection<Future<Indexes>> collectionOfFutureIndexes;
31
32 public WebXmlFilePage(API api, Container.Entry entry) {
33 this.api = api;
34 this.entry = entry;
35 // Load content file
36 String text = TextReader.getText(entry.getInputStream());
37 // Create hyperlinks
38 new PathFinder().find(text);
39 // Display
40 setText(text);
41 }
42
43 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_XML; }
44
45 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((TypeHyperlinkData)hyperlinkData).enabled; }
46
47 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
48 TypeHyperlinkData data = (TypeHyperlinkData)hyperlinkData;
49
50 if (data.enabled) {
51 try {
52 // Save current position in history
53 Point location = textArea.getLocationOnScreen();
54 int offset = textArea.viewToModel(new Point(x-location.x, y-location.y));
55 URI uri = entry.getUri();
56 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
57
58 // Open link
59 if (hyperlinkData instanceof PathHyperlinkData) {
60 PathHyperlinkData d = (PathHyperlinkData)hyperlinkData;
61 String path = d.path;
62 Container.Entry entry = searchEntry(this.entry.getContainer().getRoot(), path);
63 if (entry != null) {
64 api.openURI(x, y, Collections.singletonList(entry), null, path);
65 }
66 } else {
67 String internalTypeName = data.internalTypeName;
68 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
69 String rootUri = entry.getContainer().getRoot().getUri().toString();
70 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
71
72 for (Container.Entry entry : entries) {
73 if (entry.getUri().toString().startsWith(rootUri)) {
74 sameContainerEntries.add(entry);
75 }
76 }
77
78 if (sameContainerEntries.size() > 0) {
79 api.openURI(x, y, sameContainerEntries, null, data.internalTypeName);
80 } else if (entries.size() > 0) {
81 api.openURI(x, y, entries, null, data.internalTypeName);
82 }
83 }
84 } catch (URISyntaxException e) {
85 assert ExceptionUtil.printStackTrace(e);
86 }
87 }
88 }
89
90 public static Container.Entry searchEntry(Container.Entry parent, String path) {
91 if (path.charAt(0) == '/')
92 path = path.substring(1);
93 return recursiveSearchEntry(parent, path);
94 }
95
96 public static Container.Entry recursiveSearchEntry(Container.Entry parent, String path) {
97 Container.Entry entry = null;
98
99 for (Container.Entry child : parent.getChildren()) {
100 if (path.equals(child.getPath())) {
101 entry = child;
102 break;
103 }
104 }
105
106 if (entry != null) {
107 return entry;
108 } else {
109 for (Container.Entry child : parent.getChildren()) {
110 if (path.startsWith(child.getPath() + '/')) {
111 entry = child;
112 break;
113 }
114 }
115
116 return (entry != null) ? searchEntry(entry, path) : null;
117 }
118 }
119
120 // --- UriGettable --- //
121 public URI getUri() { return entry.getUri(); }
122
123 // --- ContentSavable --- //
124 public String getFileName() {
125 String path = entry.getPath();
126 int index = path.lastIndexOf('/');
127 return path.substring(index+1);
128 }
129
130 // --- IndexesChangeListener --- //
131 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
132 // Update the list of containers
133 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
134 // Refresh links
135 boolean refresh = false;
136
137 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
138 TypeHyperlinkData data = (TypeHyperlinkData)entry.getValue();
139 boolean enabled;
140
141 if (data instanceof PathHyperlinkData) {
142 PathHyperlinkData d = (PathHyperlinkData)data;
143 enabled = searchEntry(this.entry.getContainer().getRoot(), d.path) != null;
144 } else {
145 String internalTypeName = data.internalTypeName;
146 enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
147 }
148
149 if (data.enabled != enabled) {
150 data.enabled = enabled;
151 refresh = true;
152 }
153 }
154
155 if (refresh) {
156 textArea.repaint();
157 }
158 }
159
160 public static class PathHyperlinkData extends TypeHyperlinkData {
161 public boolean enabled;
162 public String path;
163
164 PathHyperlinkData(int startPosition, int endPosition, String path) {
165 super(startPosition, endPosition, null);
166 this.enabled = false;
167 this.path = path;
168 }
169 }
170
171 protected static List<String> typeHyperlinkPaths = Arrays.asList(
172 "web-app/filter/filter-class",
173 "web-app/listener/listener-class",
174 "web-app/servlet/servlet-class");
175
176 protected static List<String> pathHyperlinkPaths = Arrays.asList(
177 "web-app/jsp-config/taglib/taglib-location",
178 "web-app/welcome-file-list/welcome-file",
179 "web-app/login-config/form-login-config/form-login-page",
180 "web-app/login-config/form-login-config/form-error-page",
181 "web-app/jsp-config/jsp-property-group/include-prelude",
182 "web-app/jsp-config/jsp-property-group/include-coda");
183
184 protected static List<String> hyperlinkPaths = new ArrayList<>(typeHyperlinkPaths.size() + pathHyperlinkPaths.size());
185
186 static {
187 hyperlinkPaths.addAll(typeHyperlinkPaths);
188 hyperlinkPaths.addAll(pathHyperlinkPaths);
189 }
190
191 public class PathFinder extends AbstractXmlPathFinder {
192 public PathFinder() {
193 super(hyperlinkPaths);
194 }
195
196 public void handle(String path, String text, int position) {
197 String trim = text.trim();
198 if (trim != null) {
199 int startIndex = position + text.indexOf(trim);
200 int endIndex = startIndex + trim.length();
201
202 if (pathHyperlinkPaths.contains(path)) {
203 addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim));
204 } else {
205 String internalTypeName = trim.replace('.', '/');
206 addHyperlink(new TypeHyperlinkData(startIndex, endIndex, internalTypeName));
207 }
208 }
209 }
210 }
211 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.feature.IndexesChangeListener;
12 import org.jd.gui.api.feature.UriGettable;
13 import org.jd.gui.api.model.Container;
14 import org.jd.gui.api.model.Indexes;
15 import org.jd.gui.util.exception.ExceptionUtil;
16 import org.jd.gui.util.index.IndexesUtil;
17 import org.jd.gui.util.io.TextReader;
18
19 import java.awt.*;
20 import java.net.URI;
21 import java.net.URISyntaxException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.Future;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29
30 public class XmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
31 protected API api;
32 protected Container.Entry entry;
33 protected Collection<Future<Indexes>> collectionOfFutureIndexes;
34
35 public XmlFilePage(API api, Container.Entry entry) {
36 this.api = api;
37 this.entry = entry;
38 // Load content file
39 String text = TextReader.getText(entry.getInputStream());
40 // Create hyperlinks
41 Pattern pattern = Pattern.compile("(?s)<\\s*bean[^<]+class\\s*=\\s*\"([^\"]*)\"");
42 Matcher matcher = pattern.matcher(textArea.getText());
43
44 while (matcher.find()) {
45 // Spring type reference found
46 String value = matcher.group(1);
47 String trim = value.trim();
48
49 if (trim != null) {
50 int startIndex = matcher.start(1) - 1;
51 int endIndex = startIndex + value.length() + 2;
52 String internalTypeName = trim.replace('.', '/');
53 addHyperlink(new TypeHyperlinkData(startIndex, endIndex, internalTypeName));
54 }
55 }
56 // Display
57 setText(text);
58 }
59
60 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_XML; }
61
62 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((TypeHyperlinkData)hyperlinkData).enabled; }
63
64 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
65 TypeHyperlinkData data = (TypeHyperlinkData)hyperlinkData;
66
67 if (data.enabled) {
68 try {
69 // Save current position in history
70 Point location = textArea.getLocationOnScreen();
71 int offset = textArea.viewToModel(new Point(x-location.x, y-location.y));
72 URI uri = entry.getUri();
73 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
74
75 // Open link
76 String internalTypeName = data.internalTypeName;
77 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
78 String rootUri = entry.getContainer().getRoot().getUri().toString();
79 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
80
81 for (Container.Entry entry : entries) {
82 if (entry.getUri().toString().startsWith(rootUri)) {
83 sameContainerEntries.add(entry);
84 }
85 }
86
87 if (sameContainerEntries.size() > 0) {
88 api.openURI(x, y, sameContainerEntries, null, data.internalTypeName);
89 } else if (entries.size() > 0) {
90 api.openURI(x, y, entries, null, data.internalTypeName);
91 }
92 } catch (URISyntaxException e) {
93 assert ExceptionUtil.printStackTrace(e);
94 }
95 }
96 }
97
98 // --- UriGettable --- //
99 public URI getUri() { return entry.getUri(); }
100
101 // --- ContentSavable --- //
102 public String getFileName() {
103 String path = entry.getPath();
104 int index = path.lastIndexOf('/');
105 return path.substring(index+1);
106 }
107
108 // --- IndexesChangeListener --- //
109 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
110 // Update the list of containers
111 this.collectionOfFutureIndexes = collectionOfFutureIndexes;
112 // Refresh links
113 boolean refresh = false;
114
115 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
116 TypeHyperlinkData data = (TypeHyperlinkData)entry.getValue();
117 String internalTypeName = data.internalTypeName;
118 boolean enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
119
120 if (data.enabled != enabled) {
121 data.enabled = enabled;
122 refresh = true;
123 }
124 }
125
126 if (refresh) {
127 textArea.repaint();
128 }
129 }
130 }
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.data;
8
9 import org.jd.gui.api.model.TreeNodeData;
10
11 import javax.swing.*;
12
13 public class TreeNodeBean implements TreeNodeData {
14 protected String label;
15 protected String tip;
16 protected Icon icon;
17 protected Icon openIcon;
18
19 public TreeNodeBean(String label, Icon icon) {
20 this.label = label;
21 this.icon = icon;
22 }
23
24 public TreeNodeBean(String label, String tip, Icon icon) {
25 this.label = label;
26 this.tip = tip;
27 this.icon = icon;
28 }
29
30 public TreeNodeBean(String label, Icon icon, Icon openIcon) {
31 this.label = label;
32 this.icon = icon;
33 this.openIcon = openIcon;
34 }
35
36 public TreeNodeBean(String label, String tip, Icon icon, Icon openIcon) {
37 this.label = label;
38 this.tip = tip;
39 this.icon = icon;
40 this.openIcon = openIcon;
41 }
42
43 public void setLabel(String label) {
44 this.label = label;
45 }
46
47 public void setTip(String tip) {
48 this.tip = tip;
49 }
50
51 public void setIcon(Icon icon) {
52 this.icon = icon;
53 }
54
55 public void setOpenIcon(Icon openIcon) {
56 this.openIcon = openIcon;
57 }
58
59 @Override
60 public String getLabel() {
61
62 return label;
63 }
64
65 @Override
66 public String getTip() {
67 return tip;
68 }
69
70 @Override
71 public Icon getIcon() {
72 return icon;
73 }
74
75 @Override
76 public Icon getOpenIcon() {
77 return openIcon;
78 }
79 }
0 # Order is important : 'GenericContainerFactoryProvider' must be the last
1 org.jd.gui.service.container.KarContainerFactoryProvider
2 org.jd.gui.service.container.JavaModuleContainerFactoryProvider
3 org.jd.gui.service.container.EarContainerFactoryProvider
4 org.jd.gui.service.container.WarContainerFactoryProvider
5 org.jd.gui.service.container.JarContainerFactoryProvider
6 org.jd.gui.service.container.GenericContainerFactoryProvider
0 org.jd.gui.service.actions.CopyQualifiedNameContextualActionsFactory
0 org.jd.gui.service.fileloader.AarFileLoaderProvider
1 org.jd.gui.service.fileloader.ClassFileLoaderProvider
2 org.jd.gui.service.fileloader.EarFileLoaderProvider
3 org.jd.gui.service.fileloader.JarFileLoaderProvider
4 org.jd.gui.service.fileloader.JavaFileLoaderProvider
5 org.jd.gui.service.fileloader.JavaModuleFileLoaderProvider
6 org.jd.gui.service.fileloader.KarFileLoaderProvider
7 org.jd.gui.service.fileloader.LogFileLoaderProvider
8 org.jd.gui.service.fileloader.WarFileLoaderProvider
9 org.jd.gui.service.fileloader.ZipFileLoaderProvider
0 org.jd.gui.service.indexer.DirectoryIndexerProvider
1 org.jd.gui.service.indexer.ClassFileIndexerProvider
2 org.jd.gui.service.indexer.EjbJarXmlFileIndexerProvider
3 org.jd.gui.service.indexer.JavaFileIndexerProvider
4 org.jd.gui.service.indexer.JavaModuleFileIndexerProvider
5 org.jd.gui.service.indexer.JavaModuleInfoFileIndexerProvider
6 org.jd.gui.service.indexer.MetainfServiceFileIndexerProvider
7 org.jd.gui.service.indexer.TextFileIndexerProvider
8 org.jd.gui.service.indexer.WebXmlFileIndexerProvider
9 org.jd.gui.service.indexer.ZipFileIndexerProvider
10 org.jd.gui.service.indexer.XmlBasedFileIndexerProvider
11 org.jd.gui.service.indexer.XmlFileIndexerProvider
0 org.jd.gui.service.pastehandler.LogPasteHandler
0 org.jd.gui.service.preferencespanel.DirectoryIndexerPreferencesProvider
1 org.jd.gui.service.preferencespanel.ClassFileSaverPreferencesProvider
2 org.jd.gui.service.preferencespanel.ClassFileDecompilerPreferencesProvider
3 org.jd.gui.service.preferencespanel.ViewerPreferencesProvider
4 org.jd.gui.service.preferencespanel.MavenOrgSourceLoaderPreferencesProvider
0 org.jd.gui.service.sourceloader.MavenOrgSourceLoaderProvider
0 org.jd.gui.service.sourcesaver.ClassFileSourceSaverProvider
1 org.jd.gui.service.sourcesaver.DirectorySourceSaverProvider
2 org.jd.gui.service.sourcesaver.FileSourceSaverProvider
3 org.jd.gui.service.sourcesaver.PackageSourceSaverProvider
4 org.jd.gui.service.sourcesaver.ZipFileSourceSaverProvider
0 org.jd.gui.service.treenode.ClassesDirectoryTreeNodeFactoryProvider
1 org.jd.gui.service.treenode.ClassFileTreeNodeFactoryProvider
2 org.jd.gui.service.treenode.CssFileTreeNodeFactoryProvider
3 org.jd.gui.service.treenode.DirectoryTreeNodeFactoryProvider
4 org.jd.gui.service.treenode.DtdFileTreeNodeFactoryProvider
5 org.jd.gui.service.treenode.EarFileTreeNodeFactoryProvider
6 org.jd.gui.service.treenode.EjbJarXmlFileTreeNodeFactoryProvider
7 org.jd.gui.service.treenode.FileTreeNodeFactoryProvider
8 org.jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider
9 org.jd.gui.service.treenode.JarFileTreeNodeFactoryProvider
10 org.jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
11 org.jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider
12 org.jd.gui.service.treenode.JavaModuleFileTreeNodeFactoryProvider
13 org.jd.gui.service.treenode.JavaModulePackageTreeNodeFactoryProvider
14 org.jd.gui.service.treenode.JsonFileTreeNodeFactoryProvider
15 org.jd.gui.service.treenode.JspFileTreeNodeFactoryProvider
16 org.jd.gui.service.treenode.KarFileTreeNodeFactoryProvider
17 org.jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider
18 org.jd.gui.service.treenode.MetainfDirectoryTreeNodeFactoryProvider
19 org.jd.gui.service.treenode.MetainfServiceFileTreeNodeFactoryProvider
20 org.jd.gui.service.treenode.ModuleInfoFileTreeNodeFactoryProvider
21 org.jd.gui.service.treenode.PackageTreeNodeFactoryProvider
22 org.jd.gui.service.treenode.PropertiesFileTreeNodeFactoryProvider
23 org.jd.gui.service.treenode.SqlFileTreeNodeFactoryProvider
24 org.jd.gui.service.treenode.SpiFileTreeNodeFactoryProvider
25 org.jd.gui.service.treenode.TextFileTreeNodeFactoryProvider
26 org.jd.gui.service.treenode.WarFileTreeNodeFactoryProvider
27 org.jd.gui.service.treenode.WarPackageTreeNodeFactoryProvider
28 org.jd.gui.service.treenode.WebinfLibDirectoryTreeNodeFactoryProvider
29 org.jd.gui.service.treenode.WebXmlFileTreeNodeFactoryProvider
30 org.jd.gui.service.treenode.XmlBasedFileTreeNodeFactoryProvider
31 org.jd.gui.service.treenode.XmlFileTreeNodeFactoryProvider
32 org.jd.gui.service.treenode.ZipFileTreeNodeFactoryProvider
33 org.jd.gui.service.treenode.ImageFileTreeNodeFactoryProvider
0 org.jd.gui.service.type.ClassFileTypeFactoryProvider
1 org.jd.gui.service.type.JavaFileTypeFactoryProvider
0 org.jd.gui.service.uriloader.FileUriLoaderProvider
0 Copyright (c) 2012, Robert Futrell
1 All rights reserved.
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are met:
5 * Redistributions of source code must retain the above copyright
6 notice, this list of conditions and the following disclaimer.
7 * Redistributions in binary form must reproduce the above copyright
8 notice, this list of conditions and the following disclaimer in the
9 documentation and/or other materials provided with the distribution.
10 * Neither the name of the author nor the names of its contributors may
11 be used to endorse or promote products derived from this software
12 without specific prior written permission.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
18 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 <?xml version="1.0" encoding="UTF-8" ?>
1 <!DOCTYPE RSyntaxTheme SYSTEM "theme.dtd">
2
3 <!--
4 Theme that mimics Eclipse's defaults.
5 See theme.dtd and org.fife.ui.rsyntaxtextarea.Theme for more information.
6 -->
7 <RSyntaxTheme version="1.0">
8
9 <!-- Omitting baseFont will use a system-appropriate monospaced. -->
10 <!--<baseFont family="..." size="13"/>-->
11 <baseFont size="12"/>
12
13 <!-- General editor colors. -->
14 <background color="ffffff"/>
15 <caret color="000000"/>
16 <selection bg="default" fg="default"/>
17 <currentLineHighlight color="e8f2fe" fade="false"/>
18 <marginLine fg="b0b4b9"/>
19 <markAllHighlight color="6b8189"/> <!-- TODO: Fix me -->
20 <markOccurrencesHighlight color="d4d4d4" border="false"/>
21 <matchedBracket fg="c0c0c0" highlightBoth="false" animate="false"/>
22 <hyperlinks fg="0000ff"/>
23 <secondaryLanguages>
24 <language index="1" bg="fff0cc"/>
25 <language index="2" bg="dafeda"/>
26 <language index="3" bg="ffe0f0"/>
27 </secondaryLanguages>
28
29 <!-- Gutter styling. -->
30 <gutterBorder color="dddddd"/>
31 <lineNumbers fg="787878"/>
32 <foldIndicator fg="808080" iconBg="ffffff"/>
33 <iconRowHeader activeLineRange="3399ff"/>
34
35 <!-- Syntax tokens. -->
36 <tokenStyles>
37 <style token="IDENTIFIER" fg="000000"/>
38 <style token="RESERVED_WORD" fg="7f0055" bold="true"/>
39 <style token="RESERVED_WORD_2" fg="7f0055" bold="true"/>
40 <style token="ANNOTATION" fg="808080"/>
41 <style token="COMMENT_DOCUMENTATION" fg="3f5fbf"/>
42 <style token="COMMENT_EOL" fg="3f7f5f"/>
43 <style token="COMMENT_MULTILINE" fg="3f7f5f"/>
44 <style token="COMMENT_KEYWORD" fg="7F9FBF" bold="true"/>
45 <style token="COMMENT_MARKUP" fg="7f7f9f"/>
46 <style token="DATA_TYPE" fg="7f0055" bold="true"/>
47 <style token="FUNCTION" fg="000000"/>
48 <style token="LITERAL_BOOLEAN" fg="7f0055" bold="true"/>
49 <style token="LITERAL_NUMBER_DECIMAL_INT" fg="000000"/>
50 <style token="LITERAL_NUMBER_FLOAT" fg="000000"/>
51 <style token="LITERAL_NUMBER_HEXADECIMAL" fg="000000"/>
52 <style token="LITERAL_STRING_DOUBLE_QUOTE" fg="2900ff"/>
53 <style token="LITERAL_CHAR" fg="2900ff"/>
54 <style token="LITERAL_BACKQUOTE" fg="2900ff"/>
55 <style token="MARKUP_TAG_DELIMITER" fg="008080"/>
56 <style token="MARKUP_TAG_NAME" fg="3f7f7f"/>
57 <style token="MARKUP_TAG_ATTRIBUTE" fg="7f007f"/>
58 <style token="MARKUP_TAG_ATTRIBUTE_VALUE" fg="2a00ff" italic="true"/>
59 <style token="MARKUP_COMMENT" fg="3f5fbf"/>
60 <style token="MARKUP_DTD" fg="008080"/>
61 <style token="MARKUP_PROCESSING_INSTRUCTION" fg="808080"/>
62 <style token="MARKUP_CDATA" fg="000000"/>
63 <style token="MARKUP_CDATA_DELIMITER" fg="008080"/>
64 <style token="MARKUP_ENTITY_REFERENCE" fg="2a00ff"/>
65 <style token="OPERATOR" fg="000000"/>
66 <style token="PREPROCESSOR" fg="808080"/>
67 <style token="REGEX" fg="008040"/>
68 <style token="SEPARATOR" fg="000000"/>
69 <style token="VARIABLE" fg="ff9900" bold="true"/>
70 <style token="WHITESPACE" fg="000000"/>
71
72 <style token="ERROR_IDENTIFIER" fg="000000" bg="ffcccc"/>
73 <style token="ERROR_NUMBER_FORMAT" fg="000000" bg="ffcccc"/>
74 <style token="ERROR_STRING_DOUBLE" fg="000000" bg="ffcccc"/>
75 <style token="ERROR_CHAR" fg="000000" bg="ffcccc"/>
76 </tokenStyles>
77
78 </RSyntaxTheme>
0 package org.jd.gui.util.matcher;
1
2 import junit.framework.TestCase;
3 import org.junit.Assert;
4
5 public class DescriptorMatcherTest extends TestCase {
6 public void testMatchFieldDescriptors() {
7 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "?"));
8
9 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("I", "I"));
10 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "I"));
11 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("I", "?"));
12
13 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("Ltest/Test;", "Ltest/Test;"));
14 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "Ltest/Test;"));
15 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("Ltest/Test;", "?"));
16 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("L*/Test;", "Ltest/Test;"));
17 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("Ltest/Test;", "L*/Test;"));
18
19 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("L*/Test;", "L*/Test;"));
20 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "L*/Test;"));
21 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("L*/Test;", "?"));
22
23 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("[Z", "[Z"));
24 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("[Z", "?"));
25 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "[Z"));
26
27 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("Ltest/Test;", "Ltest/Test;"));
28 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("Ltest/Test;", "?"));
29 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "Ltest/Test;"));
30
31 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("[[[Ltest/Test;", "[[[Ltest/Test;"));
32 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("[[[Ltest/Test;", "?"));
33 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "[[[Ltest/Test;"));
34
35 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("[[[L*/Test;", "[[[L*/Test;"));
36 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("[[[L*/Test;", "?"));
37 Assert.assertTrue(DescriptorMatcher.matchFieldDescriptors("?", "[[[L*/Test;"));
38 }
39
40 public void testMatchMethodDescriptors() {
41 Assert.assertFalse(DescriptorMatcher.matchMethodDescriptors("I", "I"));
42
43 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("()I", "()I"));
44 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "()I"));
45 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("()I", "(*)?"));
46
47 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(I)I", "(I)I"));
48 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "(I)I"));
49 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(I)I", "(*)?"));
50
51 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(IJ)I", "(IJ)I"));
52 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "(IJ)I"));
53 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(IJ)I", "(*)?"));
54
55 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(Ltest/Test;)Ltest/Test;", "(Ltest/Test;)Ltest/Test;"));
56 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "(Ltest/Test;)Ltest/Test;"));
57 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(Ltest/Test;)Ltest/Test;", "(*)?"));
58 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[Ltest/Test;[[Ltest/Test;)Ltest/Test;", "([[L*/Test;[[L*/Test;)L*/Test;"));
59 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[L*/Test;[[L*/Test;)L*/Test;", "([[Ltest/Test;[[Ltest/Test;)Ltest/Test;"));
60
61 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(Ltest/Test;Ltest/Test;)Ltest/Test;", "(Ltest/Test;Ltest/Test;)Ltest/Test;"));
62 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "(Ltest/Test;Ltest/Test;)Ltest/Test;"));
63 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(Ltest/Test;Ltest/Test;)Ltest/Test;", "(*)?"));
64
65 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[Ltest/Test;[[Ltest/Test;)Ltest/Test;", "([[Ltest/Test;[[Ltest/Test;)Ltest/Test;"));
66 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "([[Ltest/Test;[[Ltest/Test;)Ltest/Test;"));
67 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[Ltest/Test;[[Ltest/Test;)Ltest/Test;", "(*)?"));
68 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[L*/Test;[[L*/Test;)L*/Test;", "([[Ltest/Test;[[Ltest/Test;)Ltest/Test;"));
69 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[Ltest/Test;[[Ltest/Test;)Ltest/Test;", "([[L*/Test;[[L*/Test;)L*/Test;"));
70
71 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(L*/Test;)L*/Test;", "(L*/Test;)L*/Test;"));
72 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "(L*/Test;)L*/Test;"));
73 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(L*/Test;)L*/Test;", "(*)?"));
74
75 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(L*/Test;L*/Test;)L*/Test;", "(L*/Test;L*/Test;)L*/Test;"));
76 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "(L*/Test;L*/Test;)L*/Test;"));
77 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(Ltest/Test;Ltest/Test;)Ltest/Test;", "(*)?"));
78
79 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[L*/Test;[[L*/Test;)L*/Test;", "([[L*/Test;[[L*/Test;)L*/Test;"));
80 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("(*)?", "([[L*/Test;[[L*/Test;)L*/Test;"));
81 Assert.assertTrue(DescriptorMatcher.matchMethodDescriptors("([[L*/Test;[[L*/Test;)L*/Test;", "(*)?"));
82 }
83 }
0 package org.jd.gui.view.component;
1
2 import junit.framework.TestCase;
3 import org.fife.ui.rsyntaxtextarea.DocumentRange;
4 import org.junit.Assert;
5
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.TreeMap;
9
10 public class ClassFilePageTest extends TestCase {
11
12 public HashMap<String, TypePage.DeclarationData> initDeclarations() {
13 TypePage.DeclarationData data = new TypePage.DeclarationData(0, 1, "Test", "test", "I");
14 HashMap<String, TypePage.DeclarationData> declarations = new HashMap<>();
15
16 // Init type declarations
17 declarations.put("Test", data);
18 declarations.put("test/Test", data);
19
20 // Init field declarations
21 declarations.put("Test-attributeInt-I", data);
22 declarations.put("Test-attributeBoolean-Z", data);
23 declarations.put("Test-attributeArrayBoolean-[[Z", data);
24 declarations.put("Test-attributeString-Ljava/lang/String;", data);
25
26 declarations.put("test/Test-attributeInt-I", data);
27 declarations.put("test/Test-attributeBoolean-Z", data);
28 declarations.put("test/Test-attributeArrayBoolean-[[Z", data);
29 declarations.put("test/Test-attributeString-Ljava/lang/String;", data);
30
31 // Init method declarations
32 declarations.put("Test-getInt-()I", data);
33 declarations.put("Test-getString-()Ljava/lang/String;", data);
34 declarations.put("Test-add-(JJ)J", data);
35 declarations.put("Test-createBuffer-(I)[C", data);
36
37 declarations.put("test/Test-getInt-()I", data);
38 declarations.put("test/Test-getString-()Ljava/lang/String;", data);
39 declarations.put("test/Test-add-(JJ)J", data);
40 declarations.put("test/Test-createBuffer-(I)[C", data);
41
42 return declarations;
43 }
44
45 public TreeMap<Integer, HyperlinkPage.HyperlinkData> initHyperlinks() {
46 TreeMap<Integer, HyperlinkPage.HyperlinkData> hyperlinks = new TreeMap<>();
47
48 hyperlinks.put(0, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "MAX_VALUE", "I", "Test")));
49 hyperlinks.put(1, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "toString", "()Ljava/lang/String;", "Test")));
50
51 return hyperlinks;
52 }
53
54 public ArrayList<TypePage.StringData> initStrings() {
55 ArrayList<TypePage.StringData> strings = new ArrayList<>();
56
57 strings.add(new TypePage.StringData(0, 3, "abc", "Test"));
58
59 return strings;
60 }
61
62 public void testMatchFragmentAndAddDocumentRange() {
63 HashMap<String, TypePage.DeclarationData> declarations = initDeclarations();
64 ArrayList<DocumentRange> ranges = new ArrayList<>();
65
66 ranges.clear();
67 ClassFilePage.matchFragmentAndAddDocumentRange("Test-attributeBoolean-Z", declarations, ranges);
68 Assert.assertTrue(ranges.size() == 1);
69
70 ranges.clear();
71 ClassFilePage.matchFragmentAndAddDocumentRange("test/Test-attributeBoolean-Z", declarations, ranges);
72 Assert.assertTrue(ranges.size() == 1);
73
74 ranges.clear();
75 ClassFilePage.matchFragmentAndAddDocumentRange("*/Test-attributeBoolean-Z", declarations, ranges);
76 Assert.assertTrue(ranges.size() == 2);
77
78 ranges.clear();
79 ClassFilePage.matchFragmentAndAddDocumentRange("Test-createBuffer-(I)[C", declarations, ranges);
80 Assert.assertTrue(ranges.size() == 1);
81
82 ranges.clear();
83 ClassFilePage.matchFragmentAndAddDocumentRange("test/Test-createBuffer-(I)[C", declarations, ranges);
84 Assert.assertTrue(ranges.size() == 1);
85
86 ranges.clear();
87 ClassFilePage.matchFragmentAndAddDocumentRange("*/Test-getString-(*)?", declarations, ranges);
88 Assert.assertTrue(ranges.size() == 2);
89
90 ranges.clear();
91 ClassFilePage.matchFragmentAndAddDocumentRange("test/Test-add-(?J)?", declarations, ranges);
92 Assert.assertTrue(ranges.size() == 1);
93 }
94
95 public void testMatchQueryAndAddDocumentRange() {
96 HashMap<String, String> parameters = new HashMap<>();
97 HashMap<String, TypePage.DeclarationData> declarations = initDeclarations();
98 TreeMap<Integer, HyperlinkPage.HyperlinkData> hyperlinks = initHyperlinks();
99 ArrayList<TypePage.StringData> strings = initStrings();
100 ArrayList<DocumentRange> ranges = new ArrayList<>();
101
102 parameters.put("highlightPattern", "ab");
103 parameters.put("highlightFlags", "s");
104
105 parameters.put("highlightScope", null);
106 ranges.clear();
107 ClassFilePage.matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges);
108 Assert.assertTrue(ranges.size() == 1);
109
110 parameters.put("highlightScope", "");
111 ranges.clear();
112 ClassFilePage.matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges);
113 Assert.assertTrue(ranges.size() == 1);
114
115 parameters.put("highlightScope", "Test");
116 ranges.clear();
117 ClassFilePage.matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges);
118 Assert.assertTrue(ranges.size() == 1);
119 }
120
121 public void testMatchScope() {
122 Assert.assertTrue(ClassFilePage.matchScope(null, "java/lang/String"));
123 Assert.assertTrue(ClassFilePage.matchScope("", "java/lang/String"));
124
125 Assert.assertTrue(ClassFilePage.matchScope("java/lang/String", "java/lang/String"));
126 Assert.assertTrue(ClassFilePage.matchScope("*/lang/String", "java/lang/String"));
127 Assert.assertTrue(ClassFilePage.matchScope("*/String", "java/lang/String"));
128
129 Assert.assertTrue(ClassFilePage.matchScope(null, "Test"));
130 Assert.assertTrue(ClassFilePage.matchScope("", "Test"));
131
132 Assert.assertTrue(ClassFilePage.matchScope("Test", "Test"));
133 Assert.assertTrue(ClassFilePage.matchScope("*/Test", "Test"));
134 }
135 }
0 package org.jd.gui.view.component;
1
2 import junit.framework.TestCase;
3
4 import java.util.HashMap;
5
6 public class JavaFilePageTest extends TestCase {
7
8 public HashMap<String, TypePage.DeclarationData> initDeclarations() {
9 TypePage.DeclarationData data = new TypePage.DeclarationData(0, 1, "Test", "test", "I");
10 HashMap<String, TypePage.DeclarationData> declarations = new HashMap<>();
11
12 // Init type declarations
13 declarations.put("Test", data);
14 declarations.put("test/Test", data);
15 declarations.put("*/Test", data);
16
17 // Init field declarations
18 declarations.put("Test-attributeInt-I", data);
19 declarations.put("Test-attributeBoolean-Z", data);
20 declarations.put("Test-attributeArrayBoolean-[[Z", data);
21 declarations.put("Test-attributeString-Ljava/lang/String;", data);
22
23 declarations.put("test/Test-attributeInt-I", data);
24 declarations.put("test/Test-attributeBoolean-Z", data);
25 declarations.put("test/Test-attributeArrayBoolean-[[Z", data);
26 declarations.put("test/Test-attributeString-Ljava/lang/String;", data);
27
28 declarations.put("*/Test-attributeBoolean-?", data);
29 declarations.put("*/Test-attributeBoolean-Z", data);
30 declarations.put("test/Test-attributeBoolean-?", data);
31
32 // Init method declarations
33 declarations.put("*/Test-getInt-()I", data);
34 declarations.put("*/Test-getString-()Ljava/lang/String;", data);
35 declarations.put("*/Test-add-(JJ)J", data);
36 declarations.put("*/Test-createBuffer-(I)[C", data);
37
38 declarations.put("test/Test-getInt-(*)?", data);
39 declarations.put("test/Test-getString-(*)?", data);
40 declarations.put("test/Test-add-(*)?", data);
41 declarations.put("test/Test-createBuffer-(*)?", data);
42
43 declarations.put("*/Test-getInt-(*)?", data);
44 declarations.put("*/Test-getString-(*)?", data);
45 declarations.put("*/Test-add-(*)?", data);
46 declarations.put("*/Test-createBuffer-(*)?", data);
47
48 return declarations;
49 }
50
51 public void testMatchFragmentAndAddDocumentRange() {}
52
53 public void testMatchQueryAndAddDocumentRange() {}
54
55 public void testMatchScope() {}
56 }
0 include 'api', 'app', 'services'
1
2 rootProject.name='jd-gui'
3
0 [Desktop Entry]
1 Comment=Java Decompiler JD-GUI
2 Terminal=false
3 Name=JD-GUI
4 Exec=java -jar /opt/jd-gui/jd-gui.jar
5 Type=Application
6 Icon=jd-gui
7 MimeType=application/java;application/java-vm;application/java-archive
8 StartupWMClass=org-jd-gui-App
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2 <plist version="1.0">
3 <dict>
4 <key>CFBundleDevelopmentRegion</key> <string>English</string>
5 <key>CFBundleExecutable</key> <string>universalJavaApplicationStub.sh</string>
6 <key>CFBundleName</key> <string>JD-GUI</string>
7 <key>CFBundleGetInfoString</key> <string>JD-GUI version ${VERSION}, Copyright 2008, 2019 Emmanuel Dupuy</string>
8 <key>CFBundleIconFile</key> <string>jd-gui.icns</string>
9 <key>CFBundleIdentifier</key> <string>jd.jd-gui</string>
10 <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
11 <key>CFBundlePackageType</key> <string>APPL</string>
12 <key>CFBundleLongVersionString</key> <string>${VERSION}, Copyright 2008, 2019 Emmanuel Dupuy</string>
13 <key>CFBundleShortVersionString</key> <string>${VERSION}</string>
14 <key>CSResourcesFileMapped</key> <true/>
15 <key>LSRequiresCarbon</key> <true/>
16 <key>NSHumanReadableCopyright</key> <string>Copyright 2008, 2019 Emmanuel Dupuy</string>
17 <key>NSPrincipalClass</key> <string>NSApplication</string>
18 <key>NSHighResolutionCapable</key> <true/>
19 <key>CFBundleDocumentTypes</key>
20 <array>
21 <dict>
22 <key>CFBundleTypeExtensions</key>
23 <array>
24 <string>class</string>
25 </array>
26 <key>CFBundleTypeMIMETypes</key>
27 <array>
28 <string>application/java</string>
29 </array>
30 <key>CFBundleTypeRole</key> <string>Viewer</string>
31 <key>CFBundleTypeName</key> <string>Class File</string>
32 <key>LSIsAppleDefaultForType</key> <true/>
33 <key>LSTypeIsPackage</key> <false/>
34 </dict>
35 <dict>
36 <key>CFBundleTypeExtensions</key>
37 <array>
38 <string>java</string>
39 </array>
40 <key>CFBundleTypeMIMETypes</key>
41 <array>
42 <string>text/plain</string>
43 </array>
44 <key>CFBundleTypeRole</key> <string>Viewer</string>
45 <key>CFBundleTypeName</key> <string>Java File</string>
46 <key>LSIsAppleDefaultForType</key> <false/>
47 <key>LSTypeIsPackage</key> <false/>
48 </dict>
49 <dict>
50 <key>CFBundleTypeExtensions</key>
51 <array>
52 <string>jar</string>
53 </array>
54 <key>CFBundleTypeMIMETypes</key>
55 <array>
56 <string>application/java-archive</string>
57 </array>
58 <key>CFBundleTypeName</key> <string>Jar File</string>
59 <key>CFBundleTypeRole</key> <string>Viewer</string>
60 <key>LSIsAppleDefaultForType</key> <false/>
61 <key>LSTypeIsPackage</key> <false/>
62 </dict>
63 <dict>
64 <key>CFBundleTypeExtensions</key>
65 <array>
66 <string>war</string>
67 </array>
68 <key>CFBundleTypeMIMETypes</key>
69 <array>
70 <string>application/java-archive</string>
71 </array>
72 <key>CFBundleTypeName</key> <string>War File</string>
73 <key>CFBundleTypeRole</key> <string>Viewer</string>
74 <key>LSIsAppleDefaultForType</key> <false/>
75 <key>LSTypeIsPackage</key> <false/>
76 </dict>
77 <dict>
78 <key>CFBundleTypeExtensions</key>
79 <array>
80 <string>ear</string>
81 </array>
82 <key>CFBundleTypeMIMETypes</key>
83 <array>
84 <string>application/java-archive</string>
85 </array>
86 <key>CFBundleTypeName</key> <string>Ear File</string>
87 <key>CFBundleTypeRole</key> <string>Viewer</string>
88 <key>LSIsAppleDefaultForType</key> <false/>
89 <key>LSTypeIsPackage</key> <false/>
90 </dict>
91 <dict>
92 <key>CFBundleTypeExtensions</key>
93 <array>
94 <string>aar</string>
95 </array>
96 <key>CFBundleTypeName</key> <string>Android archive File</string>
97 <key>CFBundleTypeRole</key> <string>Viewer</string>
98 <key>LSIsAppleDefaultForType</key> <false/>
99 <key>LSTypeIsPackage</key> <false/>
100 </dict>
101 <dict>
102 <key>CFBundleTypeExtensions</key>
103 <array>
104 <string>jmod</string>
105 </array>
106 <key>CFBundleTypeMIMETypes</key>
107 <array>
108 <string>application/java-archive</string>
109 </array>
110 <key>CFBundleTypeName</key> <string>Java module File</string>
111 <key>CFBundleTypeRole</key> <string>Viewer</string>
112 <key>LSIsAppleDefaultForType</key> <false/>
113 <key>LSTypeIsPackage</key> <false/>
114 </dict>
115 <dict>
116 <key>CFBundleTypeExtensions</key>
117 <array>
118 <string>zip</string>
119 </array>
120 <key>CFBundleTypeMIMETypes</key>
121 <array>
122 <string>application/zip</string>
123 </array>
124 <key>CFBundleTypeName</key> <string>Zip File</string>
125 <key>CFBundleTypeRole</key> <string>Viewer</string>
126 <key>LSIsAppleDefaultForType</key> <false/>
127 <key>LSTypeIsPackage</key> <false/>
128 </dict>
129 <dict>
130 <key>CFBundleTypeExtensions</key>
131 <array>
132 <string>log</string>
133 <string>txt</string>
134 </array>
135 <key>CFBundleTypeMIMETypes</key>
136 <array>
137 <string>text/plain</string>
138 </array>
139 <key>CFBundleTypeName</key> <string>Log File</string>
140 <key>CFBundleTypeRole</key> <string>Viewer</string>
141 <key>LSIsAppleDefaultForType</key> <false/>
142 <key>LSTypeIsPackage</key> <false/>
143 </dict>
144 </array>
145 <key>JavaX</key>
146 <dict>
147 <key>MainClass</key> <string>org.jd.gui.OsxApp</string>
148 <key>JVMVersion</key> <string>1.8+</string>
149 <key>ClassPath</key> <string>\$JAVAROOT/${JAR}</string>
150 <key>WorkingDirectory</key> <string>\$JAVAROOT</string>
151 <key>Properties</key>
152 <dict>
153 <key>apple.laf.useScreenMenuBar</key>
154 <string>true</string>
155 </dict>
156 <key>VMOptions</key> <string>-Xms512m</string>
157 </dict>
158 </dict>
159 </plist>
0 #!/bin/sh
1 ##################################################################################
2 # #
3 # universalJavaApplicationStub #
4 # #
5 # #
6 # A shellscript JavaApplicationStub for Java Apps on Mac OS X #
7 # that works with both Apple's and Oracle's plist format. #
8 # #
9 # Inspired by Ian Roberts stackoverflow answer #
10 # at http://stackoverflow.com/a/17546508/1128689 #
11 # #
12 # #
13 # @author Tobias Fischer #
14 # @url https://github.com/tofi86/universalJavaApplicationStub #
15 # @date 2015-05-15 #
16 # @version 0.9.0 #
17 # #
18 # #
19 ##################################################################################
20 # #
21 # #
22 # The MIT License (MIT) #
23 # #
24 # Copyright (c) 2015 Tobias Fischer #
25 # #
26 # Permission is hereby granted, free of charge, to any person obtaining a copy #
27 # of this software and associated documentation files (the "Software"), to deal #
28 # in the Software without restriction, including without limitation the rights #
29 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
30 # copies of the Software, and to permit persons to whom the Software is #
31 # furnished to do so, subject to the following conditions: #
32 # #
33 # The above copyright notice and this permission notice shall be included in all #
34 # copies or substantial portions of the Software. #
35 # #
36 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
37 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
38 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
39 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
40 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
41 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
42 # SOFTWARE. #
43 # #
44 ##################################################################################
45
46
47
48
49 #
50 # resolve symlinks
51 #####################
52
53 PRG=$0
54
55 while [ -h "$PRG" ]; do
56 ls=`ls -ld "$PRG"`
57 link=`expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null`
58 if expr "$link" : '^/' 2> /dev/null >/dev/null; then
59 PRG="$link"
60 else
61 PRG="`dirname "$PRG"`/$link"
62 fi
63 done
64
65 # set the directory abspath of the current shell script
66 PROGDIR=`dirname "$PRG"`
67
68
69
70
71 #
72 # set files and folders
73 ############################################
74
75 # the absolute path of the app package
76 cd "$PROGDIR"/../../
77 AppPackageFolder=`pwd`
78
79 # the base path of the app package
80 cd ..
81 AppPackageRoot=`pwd`
82
83 # set Apple's Java folder
84 AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java
85
86 # set Apple's Resources folder
87 AppleResourcesFolder="${AppPackageFolder}"/Contents/Resources
88
89 # set Oracle's Java folder
90 OracleJavaFolder="${AppPackageFolder}"/Contents/Java
91
92 # set Oracle's Resources folder
93 OracleResourcesFolder="${AppPackageFolder}"/Contents/Resources
94
95 # set path to Info.plist in bundle
96 InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist
97
98 # set the default JVM Version to a null string
99 JVMVersion=""
100
101
102
103 #
104 # read Info.plist and extract JVM options
105 ############################################
106
107
108 # read the program name from CFBundleName
109 CFBundleName=`/usr/libexec/PlistBuddy -c "print :CFBundleName" "${InfoPlistFile}"`
110
111 # read the icon file name
112 CFBundleIconFile=`/usr/libexec/PlistBuddy -c "print :CFBundleIconFile" "${InfoPlistFile}"`
113
114
115 # check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode
116 /usr/libexec/PlistBuddy -c "print :Java" "${InfoPlistFile}" > /dev/null 2>&1
117 exitcode=$?
118 JavaKey=":Java"
119
120 # if no :Java key is present, check Info.plist for universalJavaApplication style JavaX keys -> if key :JavaX is present, parse in apple mode
121 if [ $exitcode -ne 0 ]; then
122 /usr/libexec/PlistBuddy -c "print :JavaX" "${InfoPlistFile}" > /dev/null 2>&1
123 exitcode=$?
124 JavaKey=":JavaX"
125 fi
126
127
128 # read Info.plist in Apple style if exit code returns 0 (true, :Java key is present)
129 if [ $exitcode -eq 0 ]; then
130
131 # set Java and Resources folder
132 JavaFolder="${AppleJavaFolder}"
133 ResourcesFolder="${AppleResourcesFolder}"
134
135 APP_PACKAGE="${AppPackageFolder}"
136 JAVAROOT="${AppleJavaFolder}"
137 USER_HOME="$HOME"
138
139
140 # read the Java WorkingDirectory
141 JVMWorkDir=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:WorkingDirectory" "${InfoPlistFile}" 2> /dev/null | xargs`
142
143 # set Working Directory based upon Plist info
144 if [[ ! -z ${JVMWorkDir} ]]; then
145 WorkingDirectory="${JVMWorkDir}"
146 else
147 # AppPackageRoot is the standard WorkingDirectory when the script is started
148 WorkingDirectory="${AppPackageRoot}"
149 fi
150
151 # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
152 WorkingDirectory=`eval "echo ${WorkingDirectory}"`
153
154
155 # read the MainClass name
156 JVMMainClass=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:MainClass" "${InfoPlistFile}" 2> /dev/null`
157
158 # read the JVM Options
159 JVMOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Properties" "${InfoPlistFile}" 2> /dev/null | grep " =" | sed 's/^ */-D/g' | tr '\n' ' ' | sed 's/ */ /g' | sed 's/ = /=/g' | xargs`
160
161 # read StartOnMainThread
162 JVMStartOnMainThread=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:StartOnMainThread" "${InfoPlistFile}" 2> /dev/null`
163 if [ "${JVMStartOnMainThread}" == "true" ]; then
164 echo ${JVMStartOnMainThread} > ~/Desktop/test.txt
165 JVMOptions+=" -XstartOnFirstThread"
166 fi
167
168 # read the ClassPath in either Array or String style
169 JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null`
170 if [[ $JVMClassPath_RAW == *Array* ]] ; then
171 JVMClassPath=.`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs`
172 else
173 JVMClassPath=${JVMClassPath_RAW}
174 fi
175 # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
176 JVMClassPath=`eval "echo ${JVMClassPath}"`
177
178 # read the JVM Default Options
179 JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:VMOptions" "${InfoPlistFile}" 2> /dev/null | xargs`
180
181 # read the JVM Arguments
182 JVMArguments=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Arguments" "${InfoPlistFile}" 2> /dev/null | xargs`
183
184 # read the Java version we want to find
185 JVMVersion=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:JVMVersion" "${InfoPlistFile}" 2> /dev/null | xargs`
186
187 # read Info.plist in Oracle style
188 else
189
190 # set Working Directory and Java and Resources folder
191 JavaFolder="${OracleJavaFolder}"
192 ResourcesFolder="${OracleResourcesFolder}"
193 WorkingDirectory="${OracleJavaFolder}"
194
195 APP_ROOT="${AppPackageFolder}"
196
197 # read the MainClass name
198 JVMMainClass=`/usr/libexec/PlistBuddy -c "print :JVMMainClassName" "${InfoPlistFile}" 2> /dev/null`
199
200 # read the JVM Options
201 JVMOptions=`/usr/libexec/PlistBuddy -c "print :JVMOptions" "${InfoPlistFile}" 2> /dev/null | grep " -" | tr -d '\n' | sed 's/ */ /g' | xargs`
202 # replace occurances of $APP_ROOT with it's content
203 JVMOptions=`eval "echo ${JVMOptions}"`
204
205 JVMClassPath="${JavaFolder}/*"
206
207 # read the JVM Default Options
208 JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print :JVMDefaultOptions" "${InfoPlistFile}" 2> /dev/null | grep -o "\-.*" | tr -d '\n' | xargs`
209
210 # read the JVM Arguments
211 JVMArguments=`/usr/libexec/PlistBuddy -c "print :JVMArguments" "${InfoPlistFile}" 2> /dev/null | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g' | xargs`
212 # replace occurances of $APP_ROOT with it's content
213 JVMArguments=`eval "echo ${JVMArguments}"`
214 fi
215
216
217
218
219 #
220 # find installed Java versions
221 #################################
222
223 # first check system variable "$JAVA_HOME"
224 if [ -n "$JAVA_HOME" ] ; then
225 JAVACMD="$JAVA_HOME/bin/java"
226
227 # check for specified JVMversion in "/usr/libexec/java_home" symlinks
228 elif [ ! -z ${JVMVersion} ] && [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then
229
230 if /usr/libexec/java_home -F -v ${JVMVersion}; then
231 JAVACMD="`/usr/libexec/java_home -F -v ${JVMVersion} 2> /dev/null`/bin/java"
232 else
233 # display error message with applescript
234 osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'\n\nNo suitable Java version found on your system!\nThis program requires Java ${JVMVersion}\nMake sure you install the required Java version.\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
235 # exit with error
236 exit 3
237 fi
238
239 # otherwise check "/usr/libexec/java_home" symlinks
240 elif [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then
241 JAVACMD="`/usr/libexec/java_home 2> /dev/null`/bin/java"
242
243 # otherwise check Java standard symlink (old Apple Java)
244 elif [ -h /Library/Java/Home ]; then
245 JAVACMD="/Library/Java/Home/bin/java"
246
247 # fallback: public JRE plugin (Oracle Java)
248 else
249 JAVACMD="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"
250 fi
251
252 # fallback fallback: /usr/bin/java
253 # but this would prompt to install deprecated Apple Java 6
254
255
256
257
258 #
259 # execute JAVA commandline and do some pre-checks
260 ####################################################
261
262 # display error message if MainClassName is empty
263 if [ -z ${JVMMainClass} ]; then
264 # display error message with applescript
265 osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'!\n\n'MainClass' isn't specified!\nJava application cannot be started!\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
266 # exit with error
267 exit 2
268
269
270 # check whether $JAVACMD is a file and executable
271 elif [ -f "$JAVACMD" ] && [ -x "$JAVACMD" ] ; then
272
273 # enable drag&drop to the dock icon
274 export CFProcessPath="$0"
275
276 # change to Working Directory based upon Apple/Oracle Plist info
277 cd "${WorkingDirectory}"
278
279 # execute Java and set
280 # - classpath
281 # - dock icon
282 # - application name
283 # - JVM options
284 # - JVM default options
285 # - main class
286 # - JVM arguments
287 exec "$JAVACMD" \
288 -cp "${JVMClassPath}" \
289 -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \
290 -Xdock:name="${CFBundleName}" \
291 ${JVMOptions:+$JVMOptions }\
292 ${JVMDefaultOptions:+$JVMDefaultOptions }\
293 ${JVMMainClass}\
294 ${JVMArguments:+ $JVMArguments}
295
296
297 else
298
299 # display error message with applescript
300 osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'!\n\nYou need to have JAVA installed on your Mac!\nVisit http://java.com for more information...\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
301
302 # and open java.com
303 open http://java.com
304
305 # exit with error
306 exit 1
307 fi
0 # java -jar proguard.jar @proguard.config.txt
1
2 #-injars jd-gui-1.4.2.jar
3 #-outjars jd-gui-1.4.2-min.jar
4 #-libraryjars C:/Program Files/Java/jre1.8.0_121/lib/rt.jar
5 #-printmapping myapplication.map
6
7 -keep public class org.jd.gui.App {
8 public static void main(java.lang.String[]);
9 }
10
11 -keep public class org.jd.gui.OsxApp {
12 public static void main(java.lang.String[]);
13 }
14
15 -dontwarn com.apple.eawt.**
16 -keepattributes Signature
17
18 -keep public interface org.jd.gui.api.** {*;}
19 -keep public interface org.jd.gui.spi.** {*;}
20 -keep public class * extends org.jd.gui.spi.*
21
22 -keep class org.fife.ui.rsyntaxtextarea.TokenTypes {public static final <fields>;}
23 -keep class org.fife.ui.rsyntaxtextarea.DefaultTokenMakerFactory
24
25 -keep class org.fife.ui.rsyntaxtextarea.modes.CSSTokenMaker
26 -keep class org.fife.ui.rsyntaxtextarea.modes.DtdTokenMaker
27 -keep class org.fife.ui.rsyntaxtextarea.modes.HTMLTokenMaker
28 -keep class org.fife.ui.rsyntaxtextarea.modes.JavaScriptTokenMaker
29 -keep class org.fife.ui.rsyntaxtextarea.modes.JavaTokenMaker
30 -keep class org.fife.ui.rsyntaxtextarea.modes.JsonTokenMaker
31 -keep class org.fife.ui.rsyntaxtextarea.modes.JSPTokenMaker
32 -keep class org.fife.ui.rsyntaxtextarea.modes.PlainTextTokenMaker
33 -keep class org.fife.ui.rsyntaxtextarea.modes.PropertiesFileTokenMaker
34 -keep class org.fife.ui.rsyntaxtextarea.modes.SQLTokenMaker
35 -keep class org.fife.ui.rsyntaxtextarea.modes.XMLTokenMaker
36
37 -adaptresourcefilenames ErrorStrip.properties
38 -adaptresourcefilenames RSyntaxTextArea.properties
39 -adaptresourcefilenames FocusableTip.properties
Binary diff not shown