├── .gitignore ├── LICENSE ├── README.md ├── src └── main │ ├── assets │ └── debugger │ │ ├── abstract_co.png │ │ ├── default_co.png │ │ ├── editable.png │ │ ├── field_default_obj.png │ │ ├── field_private_obj.png │ │ ├── field_protected_obj.png │ │ ├── field_public_obj.png │ │ ├── final_co.png │ │ ├── folder.png │ │ ├── method_default_obj.png │ │ ├── method_private_obj.png │ │ ├── method_protected_obj.png │ │ ├── method_public_obj.png │ │ ├── native_co.png │ │ ├── runnable.png │ │ ├── static_co.png │ │ ├── synchronized_co.png │ │ ├── transient_co.png │ │ └── volatile_co.png │ └── com │ └── thistestuser │ └── debugger │ ├── Debugger.java │ └── DebuggerHook.java └── wiki ├── attach_1.PNG ├── attach_2.PNG ├── breakpoints_1.PNG ├── breakpoints_2.PNG ├── fields_1.PNG ├── fields_2.PNG ├── fields_3.PNG ├── methods_1.PNG ├── methods_2.PNG ├── search_1.PNG └── search_2.PNG /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /bin/ 3 | 4 | /src/test/ 5 | /export/ 6 | .classpath 7 | .project -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Debugger 2 | Java Debugger is a attachable debugger to your java application. It can modify fields, execute methods, or even analyze local variables. 3 | 4 | To get started, grab a download [from our releases page](https://github.com/ThisTestUser/Java-Debugger/releases) and visit our [wiki](https://github.com/ThisTestUser/Java-Debugger/wiki) to get instuctions on how to debug applications. 5 | 6 | If you have any issues or requests, please open an issue or a pull request and we'll look into it as soon as possible! 7 | 8 | ![javadebugger](https://user-images.githubusercontent.com/15678918/47621857-0d8bfc80-dad4-11e8-87c0-3fb84948120c.PNG) 9 | 10 | ## Credits 11 | Much of the GUI layout from this debugger is inspired from [Monster Debugger](https://demonsters.nl/nl/projects/monsterdebugger). 12 | 13 | The access icons are inspired from [JByteMod](https://github.com/GraxCode/JByteMod-Beta). 14 | 15 | ## License 16 | This project uses the Apache 2.0 license. 17 | -------------------------------------------------------------------------------- /src/main/assets/debugger/abstract_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/abstract_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/default_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/default_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/editable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/editable.png -------------------------------------------------------------------------------- /src/main/assets/debugger/field_default_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/field_default_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/field_private_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/field_private_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/field_protected_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/field_protected_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/field_public_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/field_public_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/final_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/final_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/folder.png -------------------------------------------------------------------------------- /src/main/assets/debugger/method_default_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/method_default_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/method_private_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/method_private_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/method_protected_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/method_protected_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/method_public_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/method_public_obj.png -------------------------------------------------------------------------------- /src/main/assets/debugger/native_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/native_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/runnable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/runnable.png -------------------------------------------------------------------------------- /src/main/assets/debugger/static_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/static_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/synchronized_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/synchronized_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/transient_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/transient_co.png -------------------------------------------------------------------------------- /src/main/assets/debugger/volatile_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/src/main/assets/debugger/volatile_co.png -------------------------------------------------------------------------------- /src/main/com/thistestuser/debugger/Debugger.java: -------------------------------------------------------------------------------- 1 | package com.thistestuser.debugger; 2 | 3 | import java.awt.*; 4 | import java.awt.event.*; 5 | import java.awt.font.TextAttribute; 6 | import java.awt.image.BufferedImage; 7 | import java.beans.PropertyChangeEvent; 8 | import java.beans.PropertyChangeListener; 9 | import java.io.File; 10 | import java.io.FileOutputStream; 11 | import java.io.InputStream; 12 | import java.io.PrintWriter; 13 | import java.io.StringWriter; 14 | import java.lang.reflect.Array; 15 | import java.lang.reflect.Field; 16 | import java.lang.reflect.Method; 17 | import java.lang.reflect.Modifier; 18 | import java.net.URI; 19 | import java.text.SimpleDateFormat; 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.Date; 23 | import java.util.Enumeration; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.concurrent.atomic.AtomicBoolean; 28 | 29 | import javax.swing.*; 30 | import javax.swing.border.Border; 31 | import javax.swing.border.EmptyBorder; 32 | import javax.swing.event.DocumentEvent; 33 | import javax.swing.event.DocumentListener; 34 | import javax.swing.event.TreeExpansionEvent; 35 | import javax.swing.event.TreeSelectionEvent; 36 | import javax.swing.event.TreeSelectionListener; 37 | import javax.swing.event.TreeWillExpandListener; 38 | import javax.swing.plaf.basic.BasicSplitPaneDivider; 39 | import javax.swing.plaf.basic.BasicSplitPaneUI; 40 | import javax.swing.plaf.basic.BasicTreeUI; 41 | import javax.swing.table.DefaultTableCellRenderer; 42 | import javax.swing.table.DefaultTableModel; 43 | import javax.swing.table.TableCellRenderer; 44 | import javax.swing.table.TableColumn; 45 | import javax.swing.table.TableColumnModel; 46 | import javax.swing.tree.*; 47 | 48 | @SuppressWarnings("serial") 49 | public class Debugger extends JFrame 50 | { 51 | private ImageIcon folder = new ImageIcon(Debugger.class.getResource("/assets/debugger/folder.png")); 52 | private ImageIcon defaultField = new ImageIcon(Debugger.class.getResource("/assets/debugger/field_default_obj.png")); 53 | private ImageIcon privateField = new ImageIcon(Debugger.class.getResource("/assets/debugger/field_private_obj.png")); 54 | private ImageIcon protectedField = new ImageIcon(Debugger.class.getResource("/assets/debugger/field_protected_obj.png")); 55 | private ImageIcon publicField = new ImageIcon(Debugger.class.getResource("/assets/debugger/field_public_obj.png")); 56 | private ImageIcon defaultMethod = new ImageIcon(Debugger.class.getResource("/assets/debugger/method_default_obj.png")); 57 | private ImageIcon privateMethod = new ImageIcon(Debugger.class.getResource("/assets/debugger/method_private_obj.png")); 58 | private ImageIcon protectedMethod = new ImageIcon(Debugger.class.getResource("/assets/debugger/method_protected_obj.png")); 59 | private ImageIcon publicMethod = new ImageIcon(Debugger.class.getResource("/assets/debugger/method_public_obj.png")); 60 | private ImageIcon finalCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/final_co.png")); 61 | private ImageIcon staticCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/static_co.png")); 62 | private ImageIcon transientCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/transient_co.png")); 63 | private ImageIcon volatileCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/volatile_co.png")); 64 | private ImageIcon abstractCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/abstract_co.png")); 65 | private ImageIcon nativeCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/native_co.png")); 66 | private ImageIcon synchronizedCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/synchronized_co.png")); 67 | private ImageIcon defaultCo = new ImageIcon(Debugger.class.getResource("/assets/debugger/default_co.png")); 68 | private ImageIcon editable = new ImageIcon(Debugger.class.getResource("/assets/debugger/editable.png")); 69 | private ImageIcon runnable = new ImageIcon(Debugger.class.getResource("/assets/debugger/runnable.png")); 70 | private List instances = new ArrayList<>(); 71 | private JTabbedPane tabbedPane; 72 | private boolean showAllFields = false; 73 | private boolean showAllMethods = false; 74 | private static boolean isOnTop = false; 75 | private static final String VERSION = "2.0"; 76 | 77 | public Debugger() 78 | { 79 | setTitle("Java Debugger"); 80 | setBounds(100, 100, 1300, 900); 81 | setMinimumSize(new Dimension(750, 500)); 82 | getContentPane().setLayout(new GridBagLayout()); 83 | 84 | JMenuBar menuBar = new JMenuBar(); 85 | setJMenuBar(menuBar); 86 | 87 | JMenu fileMenu = new JMenu("File"); 88 | JMenuItem forceEndItem = new JMenuItem("Force end"); 89 | forceEndItem.setToolTipText("Closes the application and the debugger"); 90 | forceEndItem.addActionListener(a -> System.exit(0)); 91 | fileMenu.add(forceEndItem); 92 | menuBar.add(fileMenu); 93 | 94 | JMenu viewMenu = new JMenu("View"); 95 | JCheckBoxMenuItem enableBreakpointsItem = new JCheckBoxMenuItem("Enable Breakpoints", DebuggerHook.enableBreakpoints); 96 | enableBreakpointsItem.setToolTipText("If false, new breakpoints will not be processed"); 97 | enableBreakpointsItem.addActionListener(a -> DebuggerHook.enableBreakpoints = !DebuggerHook.enableBreakpoints); 98 | viewMenu.add(enableBreakpointsItem); 99 | viewMenu.addSeparator(); 100 | JCheckBoxMenuItem onTopItem = new JCheckBoxMenuItem("Always on top"); 101 | onTopItem.addActionListener(a -> { 102 | isOnTop = !isOnTop; 103 | setAlwaysOnTop(!isAlwaysOnTop()); 104 | }); 105 | viewMenu.add(onTopItem); 106 | menuBar.add(viewMenu); 107 | 108 | JMenu miscMenu = new JMenu("Misc"); 109 | JCheckBoxMenuItem fieldsItem = new JCheckBoxMenuItem("Show all fields"); 110 | fieldsItem.setToolTipText("If true, all dynamic fields will be loaded from superclasses"); 111 | fieldsItem.addActionListener(a -> showAllFields = !showAllFields); 112 | miscMenu.add(fieldsItem); 113 | JCheckBoxMenuItem methodsItem = new JCheckBoxMenuItem("Show all methods"); 114 | methodsItem.setToolTipText("If true, all dynamic methods will be loaded from superclasses"); 115 | methodsItem.addActionListener(a -> showAllMethods = !showAllMethods); 116 | miscMenu.add(methodsItem); 117 | miscMenu.addSeparator(); 118 | JMenuItem nullManagerItem = new JMenuItem("Null security manager"); 119 | nullManagerItem.addActionListener(a -> { 120 | try 121 | { 122 | System.setSecurityManager(null); 123 | }catch(SecurityException e) 124 | { 125 | showErrorDialog("Could not null SecurityManager.", e); 126 | } 127 | }); 128 | miscMenu.add(nullManagerItem); 129 | JMenuItem dumpClassItem = new JMenuItem("Dump Resource"); 130 | dumpClassItem.addActionListener(a -> { 131 | JFrame newFrame = new JFrame(); 132 | newFrame.setTitle("Dump Resource"); 133 | newFrame.setBounds(100, 100, 500, 260); 134 | newFrame.setResizable(true); 135 | newFrame.getContentPane().setLayout(new GridBagLayout()); 136 | 137 | JLabel label = new JLabel("Dumps a resource file (first text box) to the specified location below (second box). " 138 | + "This uses the current tab's classloader (or the system classloader if loader is null/no tabs are selected). " 139 | + "This could be used to dump classes, but be sure to use slashes " 140 | + "instead of dots and place a .class at the end. "); 141 | GridBagConstraints labelC = new GridBagConstraints(); 142 | labelC.fill = GridBagConstraints.BOTH; 143 | labelC.insets = new Insets(15, 5, 5, 5); 144 | labelC.gridwidth = 2; 145 | newFrame.getContentPane().add(label, labelC); 146 | 147 | JTextField textField = new JTextField(); 148 | GridBagConstraints textFieldC = new GridBagConstraints(); 149 | textFieldC.insets = new Insets(2, 10, 5, 10); 150 | textFieldC.gridy = 1; 151 | textFieldC.gridwidth = 2; 152 | textFieldC.weightx = 1; 153 | textFieldC.fill = GridBagConstraints.BOTH; 154 | newFrame.getContentPane().add(textField, textFieldC); 155 | 156 | JTextField dumpLocField = new JTextField(); 157 | GridBagConstraints dumpLocFieldC = new GridBagConstraints(); 158 | dumpLocFieldC.insets = new Insets(5, 10, 0, 10); 159 | dumpLocFieldC.gridy = 2; 160 | dumpLocFieldC.weightx = 1; 161 | dumpLocFieldC.fill = GridBagConstraints.BOTH; 162 | newFrame.getContentPane().add(dumpLocField, dumpLocFieldC); 163 | JButton selectButton = new JButton("Select"); 164 | selectButton.addActionListener(new ActionListener() 165 | { 166 | @Override 167 | public void actionPerformed(ActionEvent e) 168 | { 169 | JFileChooser chooser = new JFileChooser(); 170 | chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 171 | int action = chooser.showOpenDialog(null); 172 | if(action == JFileChooser.APPROVE_OPTION) 173 | { 174 | String path = chooser.getSelectedFile().toString(); 175 | dumpLocField.setText(path); 176 | } 177 | } 178 | }); 179 | GridBagConstraints selectButtonC = new GridBagConstraints(); 180 | selectButtonC.insets = new Insets(5, 0, 0, 10); 181 | selectButtonC.gridy = 2; 182 | selectButtonC.gridx = 1; 183 | newFrame.getContentPane().add(selectButton, selectButtonC); 184 | 185 | JCheckBox tabIsLoader = new JCheckBox("Tab Selected is ClassLoader"); 186 | GridBagConstraints tabIsLoaderC = new GridBagConstraints(); 187 | tabIsLoaderC.insets = new Insets(2, 10, 5, 10); 188 | tabIsLoaderC.gridy = 3; 189 | tabIsLoaderC.fill = GridBagConstraints.BOTH; 190 | newFrame.getContentPane().add(tabIsLoader, tabIsLoaderC); 191 | 192 | JButton submit = new JButton("Dump"); 193 | GridBagConstraints submitC = new GridBagConstraints(); 194 | submitC.insets = new Insets(0, 0, 10, 0); 195 | submitC.anchor = GridBagConstraints.SOUTH; 196 | submitC.gridy = 4; 197 | submitC.gridwidth = 2; 198 | submitC.weightx = 1; 199 | submitC.weighty = 1; 200 | newFrame.getContentPane().add(submit, submitC); 201 | submit.addActionListener(a2 -> { 202 | try 203 | { 204 | ClassLoader loader = null; 205 | if(tabbedPane.getSelectedIndex() > 0) 206 | { 207 | if(tabIsLoader.isSelected()) 208 | loader = (ClassLoader)instances.get(tabbedPane.getSelectedIndex() - 1).instance; 209 | else 210 | loader = instances.get(tabbedPane.getSelectedIndex() - 1).clazz.getClassLoader(); 211 | } 212 | InputStream stream; 213 | if(loader == null) 214 | stream = getClass().getResourceAsStream(textField.getText()); 215 | else 216 | stream = loader.getResourceAsStream(textField.getText()); 217 | if(stream == null) 218 | throw new NullPointerException("Resource not found"); 219 | File folder = new File(dumpLocField.getText()); 220 | if(!folder.exists()) 221 | throw new IllegalArgumentException("Dump directory does not exist"); 222 | File dumpFile = new File(folder, textField.getText().replace('/', '.')); 223 | dumpFile.createNewFile(); 224 | byte[] buffer = new byte[stream.available()]; 225 | stream.read(buffer); 226 | FileOutputStream outStream = new FileOutputStream(dumpFile); 227 | outStream.write(buffer); 228 | outStream.close(); 229 | }catch(Exception e) 230 | { 231 | showErrorDialog("Error dumping resource.", e); 232 | } 233 | newFrame.dispose(); 234 | }); 235 | 236 | Toolkit toolkit = Toolkit.getDefaultToolkit(); 237 | Dimension screenSize = toolkit.getScreenSize(); 238 | newFrame.setLocation((screenSize.width - newFrame.getWidth()) / 2, (screenSize.height - newFrame.getHeight()) / 2); 239 | newFrame.setAlwaysOnTop(isOnTop); 240 | newFrame.setVisible(true); 241 | }); 242 | dumpClassItem.setToolTipText("Dump class using one of the selected ClassLoaders"); 243 | miscMenu.add(dumpClassItem); 244 | miscMenu.addSeparator(); 245 | JMenuItem loadClassItem = new JMenuItem("Load class"); 246 | loadClassItem.addActionListener(a -> { 247 | JFrame newFrame = new JFrame(); 248 | newFrame.setTitle("Load Class"); 249 | newFrame.setBounds(100, 100, 500, 230); 250 | newFrame.setResizable(true); 251 | newFrame.getContentPane().setLayout(new GridBagLayout()); 252 | 253 | JLabel label = new JLabel("Input the class name (with dots) in the box below. This uses the current " 254 | + "tab's classloader (or the system classloader if loader is null/no tabs are selected) to load the class here. " 255 | + "Note that this does not allow to access instance fields/methods."); 256 | GridBagConstraints labelC = new GridBagConstraints(); 257 | labelC.fill = GridBagConstraints.BOTH; 258 | labelC.insets = new Insets(15, 5, 5, 5); 259 | newFrame.getContentPane().add(label, labelC); 260 | 261 | JTextField textField = new JTextField(); 262 | GridBagConstraints textFieldC = new GridBagConstraints(); 263 | textFieldC.insets = new Insets(2, 10, 5, 10); 264 | textFieldC.gridy = 1; 265 | textFieldC.weightx = 1; 266 | textFieldC.fill = GridBagConstraints.BOTH; 267 | newFrame.getContentPane().add(textField, textFieldC); 268 | 269 | JCheckBox tabIsLoader = new JCheckBox("Tab Selected is ClassLoader"); 270 | GridBagConstraints tabIsLoaderC = new GridBagConstraints(); 271 | tabIsLoaderC.insets = new Insets(2, 10, 5, 10); 272 | tabIsLoaderC.gridy = 2; 273 | tabIsLoaderC.fill = GridBagConstraints.BOTH; 274 | newFrame.getContentPane().add(tabIsLoader, tabIsLoaderC); 275 | 276 | JButton submit = new JButton("Submit"); 277 | GridBagConstraints submitC = new GridBagConstraints(); 278 | submitC.insets = new Insets(0, 0, 10, 0); 279 | submitC.anchor = GridBagConstraints.SOUTH; 280 | submitC.gridy = 3; 281 | submitC.weightx = 1; 282 | submitC.weighty = 1; 283 | newFrame.getContentPane().add(submit, submitC); 284 | submit.addActionListener(a2 -> { 285 | try 286 | { 287 | ClassLoader loader = null; 288 | if(tabbedPane.getSelectedIndex() > 0) 289 | { 290 | if(tabIsLoader.isSelected()) 291 | loader = (ClassLoader)instances.get(tabbedPane.getSelectedIndex() - 1).instance; 292 | else 293 | loader = instances.get(tabbedPane.getSelectedIndex() - 1).clazz.getClassLoader(); 294 | } 295 | DebuggerHook.injectDebugger(textField.getText(), null, loader); 296 | }catch(Exception e) 297 | { 298 | showErrorDialog("Error loading class.", e); 299 | } 300 | newFrame.dispose(); 301 | }); 302 | 303 | Toolkit toolkit = Toolkit.getDefaultToolkit(); 304 | Dimension screenSize = toolkit.getScreenSize(); 305 | newFrame.setLocation((screenSize.width - newFrame.getWidth()) / 2, (screenSize.height - newFrame.getHeight()) / 2); 306 | newFrame.setAlwaysOnTop(isOnTop); 307 | newFrame.setVisible(true); 308 | }); 309 | loadClassItem.setToolTipText("Load class to Debugger. Only static fields will be editable"); 310 | miscMenu.add(loadClassItem); 311 | menuBar.add(miscMenu); 312 | 313 | tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT); 314 | GridBagConstraints tabbedPaneC = new GridBagConstraints(); 315 | tabbedPaneC.anchor = GridBagConstraints.NORTHWEST; 316 | tabbedPaneC.fill = GridBagConstraints.BOTH; 317 | tabbedPaneC.weightx = 1.0; 318 | tabbedPaneC.weighty = 1.0; 319 | getContentPane().add(tabbedPane, tabbedPaneC); 320 | setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 321 | addWindowListener(new WindowAdapter() 322 | { 323 | @Override 324 | public void windowClosing(WindowEvent we) 325 | { 326 | int dialogResult = JOptionPane.showConfirmDialog(Debugger.this, "Do you want to close the main program?", 327 | "Debugger", JOptionPane.YES_NO_CANCEL_OPTION); 328 | if(dialogResult == JOptionPane.YES_OPTION) 329 | System.exit(0); 330 | else if(dialogResult == JOptionPane.NO_OPTION) 331 | dispose(); 332 | else 333 | setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 334 | } 335 | }); 336 | JPanel panel = new JPanel(new GridBagLayout()); 337 | panel.setBackground(Color.WHITE); 338 | 339 | JLabel debuggerLabel = new JLabel("Java Debugger " + VERSION + " By ThisTestUser"); 340 | debuggerLabel.setFont(new Font("Tahoma", Font.ITALIC | Font.BOLD, 15)); 341 | GridBagConstraints debuggerLabelC = new GridBagConstraints(); 342 | debuggerLabelC.fill = GridBagConstraints.HORIZONTAL; 343 | debuggerLabelC.anchor = GridBagConstraints.NORTHWEST; 344 | debuggerLabelC.gridx = 0; 345 | debuggerLabelC.gridy = 0; 346 | debuggerLabelC.weightx = 1; 347 | debuggerLabelC.insets = new Insets(40, 35, 0, 0); 348 | panel.add(debuggerLabel, debuggerLabelC); 349 | JLabel text1 = new JLabel("Welcome to Java Debugger! You should be able to see tabs loading above based on your injection locations."); 350 | text1.setFont(new Font("Arial", Font.PLAIN, 15)); 351 | GridBagConstraints text1C = new GridBagConstraints(); 352 | text1C.fill = GridBagConstraints.HORIZONTAL; 353 | text1C.anchor = GridBagConstraints.NORTHWEST; 354 | text1C.gridx = 0; 355 | text1C.gridy = 1; 356 | text1C.weightx = 1; 357 | text1C.insets = new Insets(20, 35, 0, 0); 358 | panel.add(text1, text1C); 359 | JLabel text2 = new JLabel("To edit a field, press the wrench icon at the properties tab to edit it. An exclamation mark means that the field is null."); 360 | text2.setFont(new Font("Arial", Font.PLAIN, 15)); 361 | GridBagConstraints text2C = new GridBagConstraints(); 362 | text2C.fill = GridBagConstraints.HORIZONTAL; 363 | text2C.anchor = GridBagConstraints.NORTHWEST; 364 | text2C.gridx = 0; 365 | text2C.gridy = 2; 366 | text2C.weightx = 1; 367 | text2C.insets = new Insets(0, 35, 0, 0); 368 | panel.add(text2, text2C); 369 | JLabel text3 = new JLabel("To run methods, press the methods tab and double click the method. " 370 | + "Note that only methods with primitive arguments are executable. Also note that the stacktrace will be visible."); 371 | text3.setFont(new Font("Arial", Font.PLAIN, 15)); 372 | GridBagConstraints text3C = new GridBagConstraints(); 373 | text3C.fill = GridBagConstraints.HORIZONTAL; 374 | text3C.anchor = GridBagConstraints.NORTHWEST; 375 | text3C.gridx = 0; 376 | text3C.gridy = 3; 377 | text3C.weightx = 1; 378 | text3C.insets = new Insets(0, 35, 0, 0); 379 | panel.add(text3, text3C); 380 | JLabel text4 = new JLabel("For additional information, go the the repository link below."); 381 | text4.setFont(new Font("Arial", Font.PLAIN, 15)); 382 | GridBagConstraints text4C = new GridBagConstraints(); 383 | text4C.fill = GridBagConstraints.HORIZONTAL; 384 | text4C.anchor = GridBagConstraints.NORTHWEST; 385 | text4C.gridx = 0; 386 | text4C.gridy = 4; 387 | text4C.weightx = 1; 388 | text4C.insets = new Insets(0, 35, 0, 0); 389 | panel.add(text4, text4C); 390 | JLabel text5 = new JLabel("https://github.com/ThisTestUser/Java-Debugger"); 391 | Map fontAttributes = new HashMap<>(); 392 | fontAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); 393 | text5.setFont(new Font("Arial", Font.PLAIN, 15).deriveFont(fontAttributes)); 394 | text5.addMouseListener(new MouseAdapter() 395 | { 396 | @Override 397 | public void mouseClicked(MouseEvent e) 398 | { 399 | try 400 | { 401 | Desktop.getDesktop().browse(new URI("https://github.com/ThisTestUser/Java-Debugger")); 402 | }catch(Exception ex) 403 | { 404 | ex.printStackTrace(); 405 | } 406 | } 407 | 408 | @Override 409 | public void mouseEntered(MouseEvent e) 410 | { 411 | text5.setForeground(Color.GRAY); 412 | } 413 | 414 | @Override 415 | public void mouseExited(MouseEvent e) 416 | { 417 | text5.setForeground(Color.BLACK); 418 | } 419 | }); 420 | GridBagConstraints text5C = new GridBagConstraints(); 421 | text5C.anchor = GridBagConstraints.NORTHWEST; 422 | text5C.gridx = 0; 423 | text5C.gridy = 5; 424 | text5C.weightx = 1; 425 | text5C.weighty = 1; 426 | text5C.insets = new Insets(20, 35, 0, 0); 427 | panel.add(text5, text5C); 428 | 429 | tabbedPane.addTab("Home", panel); 430 | tabbedPane.setTabComponentAt(0, getTabComponent("Home", tabbedPane, null, false)); 431 | getContentPane().setBackground(new Color(105, 105, 105)); 432 | setVisible(true); 433 | } 434 | 435 | public boolean isInstInit(String clazz, Object instance, ClassLoader loader) throws Exception 436 | { 437 | //Check duplicates 438 | Instance inst = null; 439 | Class cl; 440 | if(loader != null) 441 | cl = Class.forName(clazz, true, loader); 442 | else 443 | cl = Class.forName(clazz); 444 | List instancesCopy = new ArrayList<>(instances); 445 | for(Instance in : instancesCopy) 446 | if(in != null && in.clazz == cl && in.instance == instance) 447 | { 448 | inst = in; 449 | break; 450 | } 451 | if(inst == null) 452 | return false; 453 | return inst.init; 454 | } 455 | 456 | public void addClass(String clazz, Object instance, ClassLoader loader) throws Exception 457 | { 458 | //Check duplicates 459 | Class cl; 460 | if(loader != null) 461 | cl = Class.forName(clazz, true, loader); 462 | else 463 | cl = Class.forName(clazz); 464 | for(Instance inst : instances) 465 | if(inst.clazz == cl && inst.instance == instance) 466 | return; 467 | Instance inst = new Instance(cl, instance); 468 | instances.add(inst); 469 | JPanel panel = inst.setupJPanel(); 470 | tabbedPane.addTab(clazz, panel); 471 | tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(panel), getTabComponent(clazz, tabbedPane, panel, true)); 472 | } 473 | 474 | public void injectBreakpoint(String clazz, Object instance, ClassLoader loader, 475 | int id, Object[] input, int mode, boolean override) throws Exception 476 | { 477 | Class cl; 478 | if(loader != null) 479 | cl = Class.forName(clazz, true, loader); 480 | else 481 | cl = Class.forName(clazz); 482 | Instance inst = null; 483 | for(Instance in : instances) 484 | if(in.clazz == cl && in.instance == instance) 485 | inst = in; 486 | if(inst == null) 487 | inst = new Instance(cl, instance); 488 | if(!instances.contains(inst)) 489 | { 490 | instances.add(inst); 491 | JPanel panel = inst.setupJPanel(); 492 | tabbedPane.addTab(clazz, panel); 493 | tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(panel), getTabComponent(clazz, tabbedPane, panel, true)); 494 | } 495 | DefaultTableModel model = (DefaultTableModel)inst.breakpointsTable.getModel(); 496 | int index = -1; 497 | for(int i = 0; i < model.getRowCount(); i++) 498 | if((int)model.getValueAt(i, 0) == id) 499 | { 500 | index = i; 501 | break; 502 | } 503 | if(index != -1 && !override) 504 | return; 505 | AtomicBoolean bool = new AtomicBoolean((mode == 0 && inst.passBox.isSelected()) || mode == 1); 506 | if(index != -1) 507 | { 508 | long prevTime = (long)model.getValueAt(index, 1); 509 | ((AtomicBoolean)model.getValueAt(index, 4)).set(true); 510 | model.removeRow(index); 511 | model.insertRow(index, new Object[] {id, System.currentTimeMillis(), System.currentTimeMillis() - prevTime, 512 | mode, bool, new Data(new Object[] {input, "View"})}); 513 | }else 514 | model.addRow(new Object[] {id, System.currentTimeMillis(), 0L, 515 | mode, bool, new Data(new Object[] {input, "View"})}); 516 | while(!bool.get()) 517 | { 518 | Thread.sleep(100); 519 | } 520 | } 521 | 522 | public static void showErrorDialog(String message, Exception e) 523 | { 524 | JFrame newFrame = new JFrame(); 525 | newFrame.setTitle("Error"); 526 | newFrame.setBounds(100, 100, 500, 400); 527 | newFrame.setResizable(true); 528 | newFrame.getContentPane().setLayout(new GridBagLayout()); 529 | 530 | JLabel yourConfiguration = new JLabel(message); 531 | GridBagConstraints gbc_yourConfiguration = new GridBagConstraints(); 532 | gbc_yourConfiguration.anchor = GridBagConstraints.PAGE_START; 533 | gbc_yourConfiguration.insets = new Insets(15, 5, 5, 5); 534 | gbc_yourConfiguration.gridx = 0; 535 | gbc_yourConfiguration.gridy = 0; 536 | newFrame.getContentPane().add(yourConfiguration, gbc_yourConfiguration); 537 | 538 | JScrollPane scrollPane = new JScrollPane(); 539 | JTextPane textPane = new JTextPane(); 540 | textPane.setEditable(false); 541 | scrollPane.setViewportView(textPane); 542 | GridBagConstraints gbc_scrollPane = new GridBagConstraints(); 543 | gbc_scrollPane.insets = new Insets(2, 10, 5, 10); 544 | gbc_scrollPane.gridx = 0; 545 | gbc_scrollPane.gridy = 1; 546 | gbc_scrollPane.weightx = 1; 547 | gbc_scrollPane.weighty = 1; 548 | gbc_scrollPane.fill = GridBagConstraints.BOTH; 549 | newFrame.getContentPane().add(scrollPane, gbc_scrollPane); 550 | StringWriter stringWriter = new StringWriter(); 551 | PrintWriter writer = new PrintWriter(stringWriter); 552 | e.printStackTrace(writer); 553 | textPane.setText(stringWriter.toString()); 554 | Toolkit toolkit = Toolkit.getDefaultToolkit(); 555 | Dimension screenSize = toolkit.getScreenSize(); 556 | newFrame.setLocation((screenSize.width - newFrame.getWidth()) / 2, (screenSize.height - newFrame.getHeight()) / 2); 557 | newFrame.setAlwaysOnTop(isOnTop); 558 | newFrame.setVisible(true); 559 | } 560 | 561 | private JPanel getTabComponent(String text, JTabbedPane pane, JPanel panel, boolean withButton) 562 | { 563 | JPanel component = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5)); 564 | if(withButton) 565 | component.setToolTipText(text); 566 | component.setOpaque(false); 567 | component.addMouseListener(new MouseAdapter() 568 | { 569 | @Override 570 | public void mousePressed(MouseEvent e) 571 | { 572 | tabbedPane.dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, tabbedPane)); 573 | } 574 | 575 | @Override 576 | public void mouseEntered(MouseEvent e) 577 | { 578 | tabbedPane.dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, tabbedPane)); 579 | } 580 | 581 | @Override 582 | public void mouseExited(MouseEvent e) 583 | { 584 | tabbedPane.dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, tabbedPane)); 585 | } 586 | }); 587 | JLabel label = new JLabel(text); 588 | label.setFont(new Font("Tahoma", Font.BOLD, 12)); 589 | component.add(label); 590 | if(withButton) 591 | { 592 | label.setPreferredSize(new Dimension(200, label.getPreferredSize().height)); 593 | JButton button = new JButton(); 594 | button.setText("\u2716"); 595 | button.setForeground(Color.GRAY); 596 | button.setContentAreaFilled(false); 597 | button.setFocusable(false); 598 | button.setBorder(new EmptyBorder(0, 0, 0, 0)); 599 | button.addMouseListener(new MouseAdapter() 600 | { 601 | @Override 602 | public void mouseClicked(MouseEvent e) 603 | { 604 | pane.remove(panel); 605 | for(Instance inst : instances) 606 | if(inst.panel == panel) 607 | { 608 | instances.remove(inst); 609 | break; 610 | } 611 | } 612 | 613 | @Override 614 | public void mouseEntered(MouseEvent e) 615 | { 616 | button.setForeground(Color.RED); 617 | } 618 | 619 | @Override 620 | public void mouseExited(MouseEvent e) 621 | { 622 | button.setForeground(Color.GRAY); 623 | } 624 | }); 625 | component.add(button); 626 | } 627 | return component; 628 | } 629 | 630 | public String getArrayName(Class clazz) 631 | { 632 | if(clazz.isArray()) 633 | return getArrayName(clazz.getComponentType()) + "[]"; 634 | return clazz.getName(); 635 | } 636 | 637 | public Class getRealComponentType(Class clazz) 638 | { 639 | if(clazz.isArray()) 640 | return getRealComponentType(clazz.getComponentType()); 641 | return clazz; 642 | } 643 | 644 | private class Instance 645 | { 646 | public final Class clazz; 647 | public final Object instance; 648 | private JTree tree; 649 | private List expanded = new ArrayList<>(); 650 | private DefaultMutableTreeNode top; 651 | public JPanel panel; 652 | private JPanel mainPanel; 653 | private JPanel propertiesPanel; 654 | private JPanel breakpointPanel; 655 | private MyTable fieldsTable; 656 | private MyTable methodsTable; 657 | private MyTable breakpointsTable; 658 | private JCheckBox passBox; 659 | private TreePath specificSearch = null; 660 | private Class tableClazz; 661 | private Object tableValue; 662 | public boolean init; 663 | 664 | public Instance(Class clazz, Object instance) 665 | { 666 | this.clazz = clazz; 667 | this.instance = instance; 668 | } 669 | 670 | public JPanel setupJPanel() 671 | { 672 | panel = new JPanel(new GridBagLayout()); 673 | 674 | mainPanel = new JPanel(new BorderLayout()); 675 | mainPanel.setPreferredSize(mainPanel.getPreferredSize()); 676 | JLabel clazzLabel = new JLabel(" Class"); 677 | clazzLabel.setFont(new Font("Tahoma", Font.BOLD, 15)); 678 | clazzLabel.setPreferredSize(new Dimension(clazzLabel.getPreferredSize().width, clazzLabel.getPreferredSize().height + 6)); 679 | clazzLabel.setOpaque(true); 680 | clazzLabel.setBackground(new Color(105, 105, 105)); 681 | clazzLabel.setForeground(Color.WHITE); 682 | mainPanel.add(clazzLabel, BorderLayout.NORTH); 683 | top = new HideableTreeNode(clazz.getName().substring(clazz.getName().lastIndexOf('.') + 1), true); 684 | tree = new JTree(top, true) 685 | { 686 | @Override 687 | public void paintComponent(Graphics g) 688 | { 689 | g.setColor(getBackground()); 690 | g.fillRect(0, 0, getWidth(), getHeight()); 691 | if(getSelectionCount() > 0) 692 | { 693 | for(int i : getSelectionRows()) 694 | { 695 | Rectangle r = getRowBounds(i); 696 | g.setColor(UIManager.getColor("List.selectionBackground")); 697 | g.fillRect(0, r.y, getWidth(), r.height); 698 | } 699 | } 700 | if(specificSearch != null && getRowForPath(specificSearch) != getLeadSelectionRow()) 701 | { 702 | Rectangle r = getRowBounds(getRowForPath(specificSearch)); 703 | g.setColor(Color.GREEN.brighter()); 704 | g.fillRect(0, r.y, getWidth(), r.height); 705 | } 706 | super.paintComponent(g); 707 | } 708 | }; 709 | tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 710 | tree.setRowHeight(30); 711 | tree.setOpaque(false); 712 | tree.setFont(tree.getFont().deriveFont(15)); 713 | tree.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); 714 | tree.setShowsRootHandles(true); 715 | tree.setToggleClickCount(0); 716 | tree.setCellRenderer(new DefaultTreeCellRenderer() 717 | { 718 | private JLabel label = new JLabel(); 719 | 720 | @Override 721 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, 722 | boolean leaf, int row, boolean hasFocus) 723 | { 724 | label.setOpaque(true); 725 | if(value instanceof FieldTreeNode) 726 | { 727 | ImageIcon icon = null; 728 | Field field = ((FieldTreeNode)value).field; 729 | if(field != null) 730 | { 731 | if(Modifier.isPublic(field.getModifiers())) 732 | icon = publicField; 733 | else if (Modifier.isPrivate(field.getModifiers())) 734 | icon = privateField; 735 | else if (Modifier.isProtected(field.getModifiers())) 736 | icon = protectedField; 737 | else 738 | icon = defaultField; 739 | if(Modifier.isTransient(field.getModifiers())) 740 | icon = combineAccess(icon, transientCo, 2); 741 | boolean placedFinal = false; 742 | boolean placedVolatile = false; 743 | boolean placedStatic = false; 744 | if(Modifier.isFinal(field.getModifiers())) 745 | { 746 | icon = combineAccess(icon, finalCo, 0); 747 | placedFinal = true; 748 | }else if(Modifier.isVolatile(field.getModifiers())) 749 | { 750 | icon = combineAccess(icon, volatileCo, 0); 751 | placedVolatile = true; 752 | }else if(Modifier.isStatic(field.getModifiers())) 753 | { 754 | icon = combineAccess(icon, staticCo, 0); 755 | placedStatic = true; 756 | } 757 | if(Modifier.isFinal(field.getModifiers()) && !placedFinal) 758 | icon = combineAccess(icon, finalCo, 1); 759 | else if(Modifier.isVolatile(field.getModifiers()) && !placedVolatile) 760 | icon = combineAccess(icon, volatileCo, 1); 761 | else if(Modifier.isStatic(field.getModifiers()) && !placedStatic) 762 | icon = combineAccess(icon, staticCo, 1); 763 | }else 764 | icon = publicField; 765 | label.setIcon(icon); 766 | }else 767 | label.setIcon(folder); 768 | label.setText((String)((DefaultMutableTreeNode)value).getUserObject()); 769 | if(selected) 770 | label.setBackground(backgroundSelectionColor); 771 | else if(specificSearch != null && specificSearch.getLastPathComponent() == value) 772 | label.setBackground(Color.GREEN.brighter()); 773 | else 774 | label.setBackground(backgroundNonSelectionColor); 775 | return label; 776 | } 777 | }); 778 | tree.setUI(new BasicTreeUI() 779 | { 780 | @Override 781 | public Rectangle getPathBounds(JTree tree, TreePath path) 782 | { 783 | if(tree != null && treeState != null) 784 | { 785 | Rectangle bounds = new Rectangle(); 786 | bounds = treeState.getBounds(path, bounds); 787 | if(bounds != null) 788 | { 789 | bounds.width = tree.getWidth(); 790 | bounds.y += tree.getInsets().top; 791 | } 792 | return bounds; 793 | } 794 | return null; 795 | } 796 | }); 797 | JScrollPane scrollPane = new JScrollPane(tree); 798 | scrollPane.setBorder(BorderFactory.createEmptyBorder()); 799 | scrollPane.getViewport().setBackground(Color.WHITE); 800 | mainPanel.add(scrollPane, BorderLayout.CENTER); 801 | JPanel bottomClazzPanel = new JPanel(new GridBagLayout()); 802 | JLabel filterP = new JLabel(" filter: "); 803 | filterP.setMinimumSize(filterP.getPreferredSize()); 804 | bottomClazzPanel.add(filterP, new GridBagConstraints()); 805 | JTextField textField = new JTextField(20); 806 | textField.setMinimumSize(textField.getPreferredSize()); 807 | GridBagConstraints textFieldC = new GridBagConstraints(); 808 | textFieldC.gridx = 1; 809 | bottomClazzPanel.add(textField, textFieldC); 810 | JButton clearSpecificSearch = new JButton("Clear Specific Search"); 811 | clearSpecificSearch.setEnabled(false); 812 | clearSpecificSearch.addActionListener(a -> { 813 | specificSearch = null; 814 | clearSpecificSearch.setEnabled(false); 815 | List expandedCopy = new ArrayList<>(expanded); 816 | updateFilter(specificSearch != null ? (HideableTreeNode)specificSearch.getLastPathComponent() : 817 | (HideableTreeNode)tree.getModel().getRoot(), textField.getText(), true); 818 | for(TreePath path : expandedCopy) 819 | tree.expandPath(path); 820 | }); 821 | GridBagConstraints clearSpecificSearchC = new GridBagConstraints(); 822 | clearSpecificSearchC.anchor = GridBagConstraints.WEST; 823 | clearSpecificSearchC.gridx = 2; 824 | bottomClazzPanel.add(clearSpecificSearch, clearSpecificSearchC); 825 | textField.getDocument().addDocumentListener(new DocumentListener() 826 | { 827 | @Override 828 | public void insertUpdate(DocumentEvent e) 829 | { 830 | List expandedCopy = new ArrayList<>(expanded); 831 | updateFilter(specificSearch != null ? (HideableTreeNode)specificSearch.getLastPathComponent() : 832 | (HideableTreeNode)tree.getModel().getRoot(), textField.getText(), true); 833 | for(TreePath path : expandedCopy) 834 | tree.expandPath(path); 835 | } 836 | 837 | @Override 838 | public void removeUpdate(DocumentEvent e) 839 | { 840 | List expandedCopy = new ArrayList<>(expanded); 841 | updateFilter(specificSearch != null ? (HideableTreeNode)specificSearch.getLastPathComponent() : 842 | (HideableTreeNode)tree.getModel().getRoot(), textField.getText(), true); 843 | for(TreePath path : expandedCopy) 844 | tree.expandPath(path); 845 | } 846 | 847 | @Override 848 | public void changedUpdate(DocumentEvent e) 849 | { 850 | List expandedCopy = new ArrayList<>(expanded); 851 | updateFilter(specificSearch != null ? (HideableTreeNode)specificSearch.getLastPathComponent() : 852 | (HideableTreeNode)tree.getModel().getRoot(), textField.getText(), true); 853 | for(TreePath path : expandedCopy) 854 | tree.expandPath(path); 855 | } 856 | }); 857 | JButton button = new JButton("Refresh"); 858 | button.addActionListener(a -> { 859 | refreshTree(textField.getText()); 860 | clearSpecificSearch.setEnabled(false); 861 | }); 862 | GridBagConstraints buttonC = new GridBagConstraints(); 863 | buttonC.anchor = GridBagConstraints.EAST; 864 | buttonC.weightx = 1; 865 | buttonC.gridx = 3; 866 | buttonC.insets = new Insets(0, 0, 0, 10); 867 | bottomClazzPanel.add(button, buttonC); 868 | tree.addTreeWillExpandListener(new TreeWillExpandListener() 869 | { 870 | @Override 871 | public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException 872 | { 873 | TreePath path = event.getPath(); 874 | expanded.add(path); 875 | if(path.getLastPathComponent() instanceof FieldTreeNode) 876 | { 877 | FieldTreeNode node = (FieldTreeNode)path.getLastPathComponent(); 878 | node.loadChildren(textField.getText()); 879 | } 880 | } 881 | 882 | @Override 883 | public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException 884 | { 885 | expanded.remove(event.getPath()); 886 | } 887 | }); 888 | tree.addMouseListener(new MouseAdapter() 889 | { 890 | @Override 891 | public void mousePressed(MouseEvent e) 892 | { 893 | if(SwingUtilities.isRightMouseButton(e)) 894 | { 895 | TreePath path = tree.getPathForLocation(e.getX(), e.getY()); 896 | Rectangle pathBounds = tree.getUI().getPathBounds(tree, path); 897 | if(pathBounds != null && pathBounds.contains(e.getX(), e.getY())) 898 | { 899 | JPopupMenu menu = new JPopupMenu(); 900 | JMenuItem onlySearch = new JMenuItem("Only Search In Here"); 901 | menu.add(onlySearch); 902 | onlySearch.addActionListener(a -> { 903 | specificSearch = path; 904 | clearSpecificSearch.setEnabled(specificSearch != null); 905 | List expandedCopy = new ArrayList<>(expanded); 906 | updateFilter(specificSearch != null ? (HideableTreeNode)specificSearch.getLastPathComponent() : 907 | (HideableTreeNode)tree.getModel().getRoot(), textField.getText(), true); 908 | for(TreePath pth : expandedCopy) 909 | tree.expandPath(pth); 910 | }); 911 | JMenuItem loadAsTab = new JMenuItem("Load As Tab"); 912 | menu.add(loadAsTab); 913 | loadAsTab.addActionListener(a -> { 914 | try 915 | { 916 | if(path.getLastPathComponent() instanceof FieldTreeNode) 917 | { 918 | FieldTreeNode treeNode = (FieldTreeNode)path.getLastPathComponent(); 919 | if(treeNode.value != null && !treeNode.value.getClass().isArray()) 920 | { 921 | boolean accessible = false; 922 | int modifier = 0; 923 | accessible = treeNode.field.isAccessible(); 924 | modifier = treeNode.field.getModifiers(); 925 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 926 | treeNode.field.setAccessible(true); 927 | modifiersField.setAccessible(true); 928 | modifiersField.setInt(treeNode.field, 929 | treeNode.field.getModifiers() & ~Modifier.FINAL); 930 | addClass(treeNode.value.getClass().getName(), treeNode.value, 931 | treeNode.value.getClass().getClassLoader()); 932 | treeNode.field.setAccessible(accessible); 933 | modifiersField.setInt(treeNode.field, modifier); 934 | modifiersField.setAccessible(false); 935 | } 936 | } 937 | }catch(Exception ex) 938 | { 939 | showErrorDialog("Could not load result.", ex); 940 | } 941 | }); 942 | menu.show(tree, e.getX(), e.getY()); 943 | } 944 | } 945 | } 946 | }); 947 | tree.addTreeSelectionListener(new TreeSelectionListener() 948 | { 949 | @Override 950 | public void valueChanged(TreeSelectionEvent e) 951 | { 952 | TreePath path = e.getNewLeadSelectionPath(); 953 | if(path == null) 954 | return; 955 | if(!(path.getLastPathComponent() instanceof FieldTreeNode)) 956 | { 957 | tableClazz = clazz; 958 | tableValue = instance; 959 | reloadFields(tableClazz, tableClazz); 960 | reloadMethods(tableClazz, tableClazz); 961 | }else 962 | { 963 | FieldTreeNode node = (FieldTreeNode)path.getLastPathComponent(); 964 | tableClazz = node.field != null ? node.field.getType() : node.type; 965 | tableValue = node.value; 966 | reloadFields(tableClazz, node.owner); 967 | reloadMethods(tableClazz, node.owner); 968 | } 969 | } 970 | }); 971 | bottomClazzPanel.setMinimumSize(new Dimension(0, 0)); 972 | mainPanel.add(bottomClazzPanel, BorderLayout.SOUTH); 973 | mainPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); 974 | 975 | propertiesPanel = new JPanel(new GridBagLayout()); 976 | propertiesPanel.setPreferredSize(propertiesPanel.getPreferredSize()); 977 | JTabbedPane fieldMethodsTab = new JTabbedPane(); 978 | fieldMethodsTab.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); 979 | JPanel jMethod = new JPanel(new BorderLayout()); 980 | methodsTable = new MyTable(0, 3, 0); 981 | methodsTable.setAutoCreateRowSorter(true); 982 | methodsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 983 | methodsTable.addMouseListener(new MouseAdapter() 984 | { 985 | private Object result; 986 | 987 | @Override 988 | public void mousePressed(MouseEvent mouseEvent) 989 | { 990 | JTable table = (JTable)mouseEvent.getSource(); 991 | if(mouseEvent.getClickCount() == 2 && table.getSelectedRow() != -1) 992 | { 993 | JFrame newFrame = new JFrame(); 994 | newFrame.setTitle("Java Debugger - Method"); 995 | newFrame.setBounds(100, 100, 800, 500); 996 | newFrame.setMinimumSize(new Dimension(400, 300)); 997 | newFrame.setResizable(true); 998 | newFrame.getContentPane().setLayout(new GridBagLayout()); 999 | 1000 | JPanel leftPanel = new JPanel(new GridBagLayout()); 1001 | 1002 | Data data = (Data)table.getValueAt(table.getSelectedRow(), 2); 1003 | Method method = (Method)data.data[1]; 1004 | 1005 | GridBagConstraints ownerLabelC = new GridBagConstraints(); 1006 | ownerLabelC.insets = new Insets(10, 10, 0, 0); 1007 | ownerLabelC.anchor = GridBagConstraints.NORTHWEST; 1008 | ownerLabelC.fill = GridBagConstraints.HORIZONTAL; 1009 | ownerLabelC.weightx = 1; 1010 | leftPanel.add(new JLabel("Owner: " + method.getDeclaringClass().getName()), ownerLabelC); 1011 | GridBagConstraints accessModC = new GridBagConstraints(); 1012 | accessModC.insets = new Insets(10, 10, 0, 0); 1013 | accessModC.anchor = GridBagConstraints.NORTHWEST; 1014 | accessModC.fill = GridBagConstraints.HORIZONTAL; 1015 | accessModC.weightx = 1; 1016 | accessModC.gridy = 1; 1017 | String methodString = "" + Modifier.toString(method.getModifiers()) + ""; 1018 | if(method.isDefault()) 1019 | methodString += " default"; 1020 | if(method.isVarArgs()) 1021 | methodString += " varargs"; 1022 | if(method.isSynthetic()) 1023 | methodString += " synthetic"; 1024 | if(method.isBridge()) 1025 | methodString += " bridge"; 1026 | if(method.getReturnType().isPrimitive()) 1027 | methodString += " " + getArrayName(method.getReturnType()) + ""; 1028 | methodString += " " + method.getName() + "("; 1029 | int argIndex = Modifier.isStatic(method.getModifiers()) ? 0 : 1; 1030 | for(Class clazz : method.getParameterTypes()) 1031 | methodString += (clazz.isPrimitive() ? "" : "") + 1032 | getArrayName(clazz) + (clazz.isPrimitive() ? "" : "") + 1033 | " var" + argIndex++ + ", "; 1034 | if(method.getParameterTypes().length > 0) 1035 | methodString = methodString.substring(0, methodString.length() - 2); 1036 | methodString += ")"; 1037 | leftPanel.add(new JLabel("" + methodString + ""), accessModC); 1038 | JPanel panel = new JPanel(new GridBagLayout()); 1039 | GridBagConstraints panelC = new GridBagConstraints(); 1040 | panelC.insets = new Insets(10, 10, 0, 0); 1041 | panelC.anchor = GridBagConstraints.NORTHWEST; 1042 | panelC.fill = GridBagConstraints.BOTH; 1043 | panelC.gridy = 2; 1044 | panelC.weightx = 1; 1045 | leftPanel.add(panel, panelC); 1046 | 1047 | int gridY = 0; 1048 | for(Class clazz : method.getParameterTypes()) 1049 | { 1050 | if(clazz == boolean.class || Enum.class.isAssignableFrom(clazz)) 1051 | { 1052 | JPanel innerPnl = new JPanel(); 1053 | innerPnl.setLayout(new BoxLayout(innerPnl, BoxLayout.X_AXIS)); 1054 | innerPnl.add(new JLabel(clazz == boolean.class ? "Boolean: " : "Enum: ")); 1055 | JComboBox comboBox = new JComboBox<>(); 1056 | List enumFields = new ArrayList<>(); 1057 | if(clazz == boolean.class) 1058 | { 1059 | comboBox.addItem("true"); 1060 | comboBox.addItem("false"); 1061 | }else 1062 | { 1063 | for(Field f : clazz.getDeclaredFields()) 1064 | if(f.getType() == clazz && Modifier.isStatic(f.getModifiers())) 1065 | enumFields.add(f); 1066 | for(Field f : enumFields) 1067 | comboBox.addItem(f.getName()); 1068 | } 1069 | innerPnl.add(comboBox); 1070 | JCheckBox nullBox = new JCheckBox("Null"); 1071 | nullBox.addActionListener(a -> { 1072 | if(nullBox.isSelected()) 1073 | comboBox.setEnabled(false); 1074 | else 1075 | comboBox.setEnabled(true); 1076 | }); 1077 | if(clazz == boolean.class) 1078 | nullBox.setEnabled(false); 1079 | innerPnl.add(nullBox); 1080 | GridBagConstraints innerPnlC = new GridBagConstraints(); 1081 | innerPnlC.anchor = GridBagConstraints.NORTHWEST; 1082 | innerPnlC.fill = GridBagConstraints.HORIZONTAL; 1083 | innerPnlC.gridy = gridY++; 1084 | innerPnlC.weightx = 1; 1085 | panel.add(innerPnl, innerPnlC); 1086 | }else if(clazz.isArray()) 1087 | { 1088 | JPanel innerPnl = new JPanel(); 1089 | innerPnl.setLayout(new BoxLayout(innerPnl, BoxLayout.X_AXIS)); 1090 | JLabel text = new JLabel("Value: "); 1091 | innerPnl.add(text); 1092 | ListButton arrButton = new ListButton("Edit Array", Array.newInstance(clazz.getComponentType(), 1093 | 0), clazz.getComponentType(), panel); 1094 | innerPnl.add(arrButton); 1095 | JCheckBox nullBox = new JCheckBox("Null"); 1096 | nullBox.addActionListener(a -> { 1097 | if(nullBox.isSelected()) 1098 | arrButton.setEnabled(false); 1099 | else 1100 | arrButton.setEnabled(true); 1101 | }); 1102 | innerPnl.add(nullBox); 1103 | GridBagConstraints innerPnlC = new GridBagConstraints(); 1104 | innerPnlC.anchor = GridBagConstraints.NORTHWEST; 1105 | innerPnlC.fill = GridBagConstraints.HORIZONTAL; 1106 | innerPnlC.gridy = gridY++; 1107 | innerPnlC.weightx = 1; 1108 | panel.add(innerPnl, innerPnlC); 1109 | }else 1110 | { 1111 | JPanel innerPnl = new JPanel(); 1112 | innerPnl.setLayout(new BoxLayout(innerPnl, BoxLayout.X_AXIS)); 1113 | JLabel text = new JLabel("Value: "); 1114 | innerPnl.add(text); 1115 | JTextField textField = new JTextField(20); 1116 | innerPnl.add(textField); 1117 | JCheckBox nullBox = new JCheckBox("Null"); 1118 | nullBox.addActionListener(a -> { 1119 | if(nullBox.isSelected()) 1120 | textField.setEnabled(false); 1121 | else 1122 | textField.setEnabled(true); 1123 | }); 1124 | if(clazz.isPrimitive()) 1125 | nullBox.setEnabled(false); 1126 | innerPnl.add(nullBox); 1127 | GridBagConstraints innerPnlC = new GridBagConstraints(); 1128 | innerPnlC.anchor = GridBagConstraints.NORTHWEST; 1129 | innerPnlC.fill = GridBagConstraints.HORIZONTAL; 1130 | innerPnlC.gridy = gridY++; 1131 | innerPnlC.weightx = 1; 1132 | panel.add(innerPnl, innerPnlC); 1133 | } 1134 | } 1135 | 1136 | JButton run = new JButton("Run"); 1137 | if(table.getValueAt(table.getSelectedRow(), 0) == null) 1138 | { 1139 | run.setEnabled(false); 1140 | for(Component comp : panel.getComponents()) 1141 | for(Component comp2 : ((JPanel)comp).getComponents()) 1142 | comp2.setEnabled(false); 1143 | } 1144 | GridBagConstraints runC = new GridBagConstraints(); 1145 | runC.insets = new Insets(0, 0, 20, 0); 1146 | runC.anchor = GridBagConstraints.SOUTH; 1147 | runC.weighty = 1; 1148 | runC.gridy = 3; 1149 | leftPanel.add(run, runC); 1150 | 1151 | GridBagConstraints leftPanelC = new GridBagConstraints(); 1152 | leftPanelC.anchor = GridBagConstraints.NORTHWEST; 1153 | leftPanelC.fill = GridBagConstraints.BOTH; 1154 | leftPanelC.weighty = 1; 1155 | newFrame.add(leftPanel, leftPanelC); 1156 | 1157 | HideableTreeNode root = new HideableTreeNode("Returns: " + getArrayName(method.getReturnType()), true); 1158 | JTree tree = new JTree(root, true) 1159 | { 1160 | @Override 1161 | public void paintComponent(Graphics g) 1162 | { 1163 | g.setColor(getBackground()); 1164 | g.fillRect(0, 0, getWidth(), getHeight()); 1165 | if(getSelectionCount() > 0) 1166 | { 1167 | for(int i : getSelectionRows()) 1168 | { 1169 | Rectangle r = getRowBounds(i); 1170 | g.setColor(UIManager.getColor("List.selectionBackground")); 1171 | g.fillRect(0, r.y, getWidth(), r.height); 1172 | } 1173 | } 1174 | super.paintComponent(g); 1175 | } 1176 | }; 1177 | run.addActionListener(a -> { 1178 | try 1179 | { 1180 | boolean access = method.isAccessible(); 1181 | method.setAccessible(true); 1182 | List args = new ArrayList<>(); 1183 | for(int i = 0; i < panel.getComponents().length; i++) 1184 | { 1185 | JComponent comp = (JComponent)panel.getComponents()[i]; 1186 | JCheckBox box = (JCheckBox)((JPanel)comp).getComponent(2); 1187 | if(box.isSelected()) 1188 | args.add(null); 1189 | else if(((JPanel)comp).getComponent(1) instanceof JTextField) 1190 | { 1191 | JTextField field = (JTextField)((JPanel)comp).getComponent(1); 1192 | if(method.getParameterTypes()[i] == byte.class) 1193 | args.add(Byte.parseByte(field.getText())); 1194 | else if(method.getParameterTypes()[i] == short.class) 1195 | args.add(Short.parseShort(field.getText())); 1196 | else if(method.getParameterTypes()[i] == int.class) 1197 | args.add(Integer.parseInt(field.getText())); 1198 | else if(method.getParameterTypes()[i] == long.class) 1199 | args.add(Long.parseLong(field.getText())); 1200 | else if(method.getParameterTypes()[i] == char.class) 1201 | { 1202 | if(field.getText().length() == 1) 1203 | throw new IllegalArgumentException("Length of char must be 1"); 1204 | args.add(field.getText().charAt(0)); 1205 | }else if(method.getParameterTypes()[i] == float.class) 1206 | args.add(Float.parseFloat(field.getText())); 1207 | else if(method.getParameterTypes()[i] == double.class) 1208 | args.add(Double.parseDouble(field.getText())); 1209 | else if(String.class.isAssignableFrom(method.getParameterTypes()[i])) 1210 | args.add(field.getText()); 1211 | else 1212 | throw new IllegalStateException(method.getParameterTypes()[i].getName()); 1213 | }else if(((JPanel)comp).getComponent(1) instanceof JComboBox) 1214 | { 1215 | JComboBox comboBox = (JComboBox)((JPanel)comp).getComponent(1); 1216 | if(method.getParameterTypes()[i] == boolean.class) 1217 | args.add(comboBox.getSelectedIndex() == 0); 1218 | else if(Enum.class.isAssignableFrom(method.getParameterTypes()[i])) 1219 | { 1220 | List enumFields = new ArrayList<>(); 1221 | for(Field f : method.getParameterTypes()[i].getDeclaredFields()) 1222 | if(f.getType() == method.getParameterTypes()[i] && Modifier.isStatic(f.getModifiers())) 1223 | enumFields.add(f); 1224 | if(comboBox.getSelectedIndex() < enumFields.size() && comboBox.getSelectedIndex() != -1) 1225 | { 1226 | try 1227 | { 1228 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1229 | modifiersField.setAccessible(true); 1230 | boolean accessible = false; 1231 | int modifier = 0; 1232 | accessible = enumFields.get(comboBox.getSelectedIndex()).isAccessible(); 1233 | modifier = enumFields.get(comboBox.getSelectedIndex()).getModifiers(); 1234 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(true); 1235 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), 1236 | enumFields.get(comboBox.getSelectedIndex()).getModifiers() & ~Modifier.FINAL); 1237 | args.add(enumFields.get(comboBox.getSelectedIndex()).get(null)); 1238 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(accessible); 1239 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), modifier); 1240 | modifiersField.setAccessible(false); 1241 | }catch(Exception ex) 1242 | { 1243 | showErrorDialog("Exception occurred while adding Enum (arg " + i + "), using null instead", ex); 1244 | args.add(null); 1245 | } 1246 | }else 1247 | args.add(null); 1248 | }else 1249 | throw new IllegalStateException(method.getParameterTypes()[i].getName()); 1250 | }else if(((JPanel)comp).getComponent(1) instanceof ListButton) 1251 | args.add(((ListButton)((JPanel)comp).getComponent(1)).array); 1252 | } 1253 | result = method.invoke(data.data[2], args.toArray(new Object[args.size()])); 1254 | if(method.getReturnType() == void.class) 1255 | root.setUserObject("void"); 1256 | else if(result == null) 1257 | root.setUserObject("null"); 1258 | else if(method.getReturnType().isPrimitive()) 1259 | root.setUserObject(result + " (" + method.getReturnType().getName() + ")"); 1260 | else 1261 | { 1262 | if(String.class.isAssignableFrom(method.getReturnType())) 1263 | root.setUserObject((String)result + " (" + result.getClass().getName() + ")"); 1264 | else if(Enum.class.isAssignableFrom(method.getReturnType())) 1265 | root.setUserObject(((Enum)result).name() + " (" + result.getClass().getName() + ")"); 1266 | else 1267 | root.setUserObject("(" + getArrayName(result.getClass()) + ")"); 1268 | Class type = result.getClass(); 1269 | deleteChildren((HideableTreeNode)tree.getModel().getRoot()); 1270 | if(result.getClass().isArray()) 1271 | { 1272 | for(int i = 0; i < Array.getLength(result); i++) 1273 | { 1274 | Object o = Array.get(result, i); 1275 | String name = "(" + getArrayName(result.getClass().getComponentType()) + ")"; 1276 | if((result.getClass().getComponentType().isPrimitive() 1277 | || String.class.isAssignableFrom(result.getClass().getComponentType()) 1278 | || Enum.class.isAssignableFrom(result.getClass().getComponentType())) 1279 | && o != null) 1280 | name += " = " + o; 1281 | FieldTreeNode node = new FieldTreeNode(name, result.getClass().getComponentType(), 1282 | result.getClass(), o, !result.getClass().getComponentType().isPrimitive()); 1283 | root.add(node); 1284 | } 1285 | }else 1286 | { 1287 | for(Field f : type.getDeclaredFields()) 1288 | { 1289 | String name = f.getName() + " (" + getArrayName(f.getType()) + ")"; 1290 | Object inst = null; 1291 | if(Modifier.isStatic(f.getModifiers()) || result != null) 1292 | try 1293 | { 1294 | boolean old = f.isAccessible(); 1295 | f.setAccessible(true); 1296 | if((f.getType().isPrimitive() || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType())) 1297 | && f.get(result) != null) 1298 | name += " = " + f.get(result); 1299 | inst = f.get(result); 1300 | f.setAccessible(old); 1301 | }catch(Exception ex) 1302 | { 1303 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + type.getName() + ")"); 1304 | } 1305 | FieldTreeNode node = new FieldTreeNode(name, f, inst, !f.getType().isPrimitive()); 1306 | root.add(node); 1307 | } 1308 | if(showAllFields) 1309 | { 1310 | Class clazz1 = type.getSuperclass(); 1311 | while(clazz1 != null) 1312 | { 1313 | for(Field f : clazz1.getDeclaredFields()) 1314 | { 1315 | String name = f.getName() + " (" + getArrayName(f.getType()) + ")"; 1316 | Object inst = null; 1317 | if(!Modifier.isStatic(f.getModifiers()) || result != null) 1318 | try 1319 | { 1320 | boolean old = f.isAccessible(); 1321 | f.setAccessible(true); 1322 | if((f.getType().isPrimitive() || String.class.isAssignableFrom(f.getType()) 1323 | || Enum.class.isAssignableFrom(f.getType())) 1324 | && f.get(result) != null) 1325 | name += " = " + f.get(result); 1326 | inst = f.get(result); 1327 | f.setAccessible(old); 1328 | }catch(Exception ex) 1329 | { 1330 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz1.getName() + ")"); 1331 | } 1332 | FieldTreeNode node = new FieldTreeNode(name, f, inst, !f.getType().isPrimitive()); 1333 | root.add(node); 1334 | } 1335 | clazz1 = clazz1.getSuperclass(); 1336 | } 1337 | } 1338 | } 1339 | tree.collapsePath(tree.getPathForRow(0)); 1340 | } 1341 | ((DefaultTreeModel)tree.getModel()).reload(); 1342 | method.setAccessible(access); 1343 | }catch(Exception ex) 1344 | { 1345 | showErrorDialog("Exception occurred while invoking method.", ex); 1346 | } 1347 | }); 1348 | tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 1349 | tree.setRowHeight(30); 1350 | tree.setOpaque(false); 1351 | tree.setFont(tree.getFont().deriveFont(15)); 1352 | tree.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); 1353 | tree.setShowsRootHandles(true); 1354 | tree.setToggleClickCount(0); 1355 | tree.setCellRenderer(new DefaultTreeCellRenderer() 1356 | { 1357 | private JLabel label = new JLabel(); 1358 | 1359 | @Override 1360 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, 1361 | boolean leaf, int row, boolean hasFocus) 1362 | { 1363 | label.setOpaque(true); 1364 | if(value instanceof FieldTreeNode) 1365 | { 1366 | ImageIcon icon = null; 1367 | Field field = ((FieldTreeNode)value).field; 1368 | if(field != null) 1369 | { 1370 | if(Modifier.isPublic(field.getModifiers())) 1371 | icon = publicField; 1372 | else if (Modifier.isPrivate(field.getModifiers())) 1373 | icon = privateField; 1374 | else if (Modifier.isProtected(field.getModifiers())) 1375 | icon = protectedField; 1376 | else 1377 | icon = defaultField; 1378 | if(Modifier.isTransient(field.getModifiers())) 1379 | icon = combineAccess(icon, transientCo, 2); 1380 | boolean placedFinal = false; 1381 | boolean placedVolatile = false; 1382 | boolean placedStatic = false; 1383 | if(Modifier.isFinal(field.getModifiers())) 1384 | { 1385 | icon = combineAccess(icon, finalCo, 0); 1386 | placedFinal = true; 1387 | }else if(Modifier.isVolatile(field.getModifiers())) 1388 | { 1389 | icon = combineAccess(icon, volatileCo, 0); 1390 | placedVolatile = true; 1391 | }else if(Modifier.isStatic(field.getModifiers())) 1392 | { 1393 | icon = combineAccess(icon, staticCo, 0); 1394 | placedStatic = true; 1395 | } 1396 | if(Modifier.isFinal(field.getModifiers()) && !placedFinal) 1397 | icon = combineAccess(icon, finalCo, 1); 1398 | else if(Modifier.isVolatile(field.getModifiers()) && !placedVolatile) 1399 | icon = combineAccess(icon, volatileCo, 1); 1400 | else if(Modifier.isStatic(field.getModifiers()) && !placedStatic) 1401 | icon = combineAccess(icon, staticCo, 1); 1402 | }else 1403 | icon = publicField; 1404 | label.setIcon(icon); 1405 | }else 1406 | label.setIcon(folder); 1407 | label.setText((String)((DefaultMutableTreeNode)value).getUserObject()); 1408 | if(selected) 1409 | label.setBackground(backgroundSelectionColor); 1410 | else 1411 | label.setBackground(backgroundNonSelectionColor); 1412 | return label; 1413 | } 1414 | }); 1415 | tree.setUI(new BasicTreeUI() 1416 | { 1417 | @Override 1418 | public Rectangle getPathBounds(JTree tree, TreePath path) 1419 | { 1420 | if(tree != null && treeState != null) 1421 | { 1422 | Rectangle bounds = new Rectangle(); 1423 | bounds = treeState.getBounds(path, bounds); 1424 | if(bounds != null) 1425 | { 1426 | bounds.width = tree.getWidth(); 1427 | bounds.y += tree.getInsets().top; 1428 | } 1429 | return bounds; 1430 | } 1431 | return null; 1432 | } 1433 | }); 1434 | tree.addTreeWillExpandListener(new TreeWillExpandListener() 1435 | { 1436 | @Override 1437 | public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException 1438 | { 1439 | TreePath path = event.getPath(); 1440 | if(path.getLastPathComponent() instanceof FieldTreeNode) 1441 | { 1442 | FieldTreeNode node = (FieldTreeNode)path.getLastPathComponent(); 1443 | node.loadChildren(""); 1444 | } 1445 | } 1446 | 1447 | @Override 1448 | public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException 1449 | { 1450 | } 1451 | }); 1452 | tree.addMouseListener(new MouseAdapter() 1453 | { 1454 | @Override 1455 | public void mousePressed(MouseEvent e) 1456 | { 1457 | if(SwingUtilities.isRightMouseButton(e)) 1458 | { 1459 | TreePath path = tree.getPathForLocation(e.getX(), e.getY()); 1460 | Rectangle pathBounds = tree.getUI().getPathBounds(tree, path); 1461 | if(pathBounds != null && pathBounds.contains(e.getX(), e.getY())) 1462 | { 1463 | JPopupMenu menu = new JPopupMenu(); 1464 | JMenuItem loadAsTab = new JMenuItem("Load As Tab"); 1465 | menu.add(loadAsTab); 1466 | loadAsTab.addActionListener(a -> { 1467 | try 1468 | { 1469 | if(path.getLastPathComponent() instanceof FieldTreeNode) 1470 | { 1471 | FieldTreeNode treeNode = (FieldTreeNode)path.getLastPathComponent(); 1472 | if(treeNode.value != null && !treeNode.value.getClass().isArray()) 1473 | { 1474 | boolean accessible = false; 1475 | int modifier = 0; 1476 | accessible = treeNode.field.isAccessible(); 1477 | modifier = treeNode.field.getModifiers(); 1478 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1479 | treeNode.field.setAccessible(true); 1480 | modifiersField.setAccessible(true); 1481 | modifiersField.setInt(treeNode.field, 1482 | treeNode.field.getModifiers() & ~Modifier.FINAL); 1483 | addClass(treeNode.value.getClass().getName(), treeNode.value, 1484 | treeNode.value.getClass().getClassLoader()); 1485 | treeNode.field.setAccessible(accessible); 1486 | modifiersField.setInt(treeNode.field, modifier); 1487 | modifiersField.setAccessible(false); 1488 | } 1489 | }else if(result != null && !result.getClass().isArray()) 1490 | addClass(result.getClass().getName(), result, 1491 | result.getClass().getClassLoader()); 1492 | }catch(Exception ex) 1493 | { 1494 | showErrorDialog("Could not load result.", ex); 1495 | } 1496 | }); 1497 | menu.show(tree, e.getX(), e.getY()); 1498 | } 1499 | } 1500 | } 1501 | }); 1502 | GridBagConstraints treeC = new GridBagConstraints(); 1503 | treeC.insets = new Insets(0, 10, 0, 0); 1504 | treeC.anchor = GridBagConstraints.SOUTH; 1505 | treeC.fill = GridBagConstraints.BOTH; 1506 | treeC.weightx = 1; 1507 | treeC.weighty = 1; 1508 | treeC.gridx = 1; 1509 | JScrollPane scrollPane = new JScrollPane(tree); 1510 | scrollPane.setBorder(BorderFactory.createEmptyBorder()); 1511 | scrollPane.getViewport().setBackground(Color.WHITE); 1512 | newFrame.add(scrollPane, treeC); 1513 | newFrame.setAlwaysOnTop(isOnTop); 1514 | newFrame.setVisible(true); 1515 | } 1516 | } 1517 | }); 1518 | TableColumnModel colModM = methodsTable.getTableHeader().getColumnModel(); 1519 | TableColumn tabColM0 = colModM.getColumn(0); 1520 | tabColM0.setCellRenderer(new DefaultTableCellRenderer() 1521 | { 1522 | JLabel lbl = new JLabel(); 1523 | @Override 1524 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 1525 | { 1526 | if(isSelected) 1527 | lbl.setBackground(table.getSelectionBackground()); 1528 | else 1529 | lbl.setBackground(table.getBackground()); 1530 | lbl.setIcon((ImageIcon)value); 1531 | lbl.setOpaque(true); 1532 | return lbl; 1533 | } 1534 | }); 1535 | tabColM0.setHeaderValue(""); 1536 | tabColM0.setMinWidth(25); 1537 | tabColM0.setMaxWidth(25); 1538 | TableColumn tabColM1 = colModM.getColumn(1); 1539 | tabColM1.setCellRenderer(new DefaultTableCellRenderer() 1540 | { 1541 | JLabel lbl = new JLabel(); 1542 | @Override 1543 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 1544 | { 1545 | if(isSelected) 1546 | lbl.setBackground(table.getSelectionBackground()); 1547 | else 1548 | lbl.setBackground(table.getBackground()); 1549 | lbl.setIcon((ImageIcon)value); 1550 | lbl.setOpaque(true); 1551 | return lbl; 1552 | } 1553 | }); 1554 | tabColM1.setHeaderValue(""); 1555 | tabColM1.setMinWidth(25); 1556 | tabColM1.setMaxWidth(25); 1557 | TableColumn tabColM2 = colModM.getColumn(2); 1558 | tabColM2.setHeaderValue("name"); 1559 | tabColM2.setMinWidth(35); 1560 | methodsTable.setShowHorizontalLines(false); 1561 | methodsTable.setGridColor(Color.LIGHT_GRAY); 1562 | methodsTable.setRowHeight(25); 1563 | jMethod.add(new JScrollPane(methodsTable), BorderLayout.CENTER); 1564 | JPanel jField = new JPanel(new BorderLayout()); 1565 | fieldsTable = new MyTable(0, 4, 1); 1566 | fieldsTable.setAutoCreateRowSorter(true); 1567 | fieldsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 1568 | fieldsTable.addMouseListener(new MouseAdapter() 1569 | { 1570 | @Override 1571 | public void mousePressed(MouseEvent mouseEvent) 1572 | { 1573 | JTable table = (JTable)mouseEvent.getSource(); 1574 | if(mouseEvent.getClickCount() == 2 && table.getSelectedRow() != -1) 1575 | { 1576 | JFrame newFrame = new JFrame(); 1577 | newFrame.setTitle("Java Debugger - Field"); 1578 | newFrame.setBounds(100, 100, 400, 300); 1579 | newFrame.setMinimumSize(new Dimension(400, 300)); 1580 | newFrame.setResizable(true); 1581 | newFrame.getContentPane().setLayout(new GridBagLayout()); 1582 | 1583 | Data data = (Data)table.getValueAt(table.getSelectedRow(), 2); 1584 | boolean isField = data.data[1] instanceof Field; 1585 | Class type = isField ? ((Field)data.data[1]).getType() 1586 | : ((Class)data.data[4]).getComponentType(); 1587 | 1588 | GridBagConstraints ownerLabelC = new GridBagConstraints(); 1589 | ownerLabelC.insets = new Insets(10, 10, 0, 0); 1590 | ownerLabelC.anchor = GridBagConstraints.NORTHWEST; 1591 | ownerLabelC.fill = GridBagConstraints.HORIZONTAL; 1592 | ownerLabelC.weightx = 1; 1593 | if(isField) 1594 | newFrame.add(new JLabel("Owner: " + ((Field)data.data[1]).getDeclaringClass().getName()), ownerLabelC); 1595 | else 1596 | newFrame.add(new JLabel("Owner: " + ((Class)((Data)table. 1597 | getValueAt(table.getSelectedRow(), 2)).data[0]).getName()), ownerLabelC); 1598 | if(isField) 1599 | { 1600 | GridBagConstraints accessModC = new GridBagConstraints(); 1601 | accessModC.insets = new Insets(10, 10, 0, 0); 1602 | accessModC.anchor = GridBagConstraints.NORTHWEST; 1603 | accessModC.fill = GridBagConstraints.HORIZONTAL; 1604 | accessModC.gridy = 1; 1605 | accessModC.weightx = 1; 1606 | Field field = (Field)data.data[1]; 1607 | String fieldString = "" + Modifier.toString(field.getModifiers()) + ""; 1608 | if(field.isSynthetic()) 1609 | fieldString += " synthetic"; 1610 | if(field.getType().isPrimitive()) 1611 | fieldString += " " + getArrayName(field.getType()) + ""; 1612 | else 1613 | fieldString += " " + getArrayName(field.getType()); 1614 | fieldString += " " + field.getName() + ""; 1615 | newFrame.add(new JLabel("" + fieldString + ""), accessModC); 1616 | }else 1617 | { 1618 | GridBagConstraints accessModC = new GridBagConstraints(); 1619 | accessModC.insets = new Insets(10, 10, 0, 0); 1620 | accessModC.anchor = GridBagConstraints.NORTHWEST; 1621 | accessModC.fill = GridBagConstraints.HORIZONTAL; 1622 | accessModC.gridy = 1; 1623 | accessModC.weightx = 1; 1624 | newFrame.add(new JLabel(getArrayName(type)), accessModC); 1625 | } 1626 | Object value = null; 1627 | try 1628 | { 1629 | boolean accessible = false; 1630 | if(isField) 1631 | { 1632 | accessible = ((Field)data.data[1]).isAccessible(); 1633 | ((Field)data.data[1]).setAccessible(true); 1634 | } 1635 | if(table.getValueAt(table.getSelectedRow(), 0) != null) 1636 | value = isField ? ((Field)data.data[1]).get(data.data[2]) : Array.get(data.data[1], 1637 | (int)data.data[2]); 1638 | if(isField) 1639 | ((Field)data.data[1]).setAccessible(accessible); 1640 | }catch(Exception e) 1641 | { 1642 | showErrorDialog("Cannot get field value.", e); 1643 | } 1644 | JPanel panel = new JPanel(new GridBagLayout()); 1645 | GridBagConstraints panelC = new GridBagConstraints(); 1646 | panelC.insets = new Insets(10, 10, 0, 0); 1647 | panelC.anchor = GridBagConstraints.NORTHWEST; 1648 | panelC.fill = GridBagConstraints.BOTH; 1649 | panelC.gridy = 2; 1650 | panelC.weightx = 1; 1651 | newFrame.add(panel, panelC); 1652 | JCheckBox nullBox = new JCheckBox("Null"); 1653 | JButton setValue = new JButton("Set Value"); 1654 | if(table.getValueAt(table.getSelectedRow(), 0) == null) 1655 | setValue.setEnabled(false); 1656 | if(type == boolean.class || Enum.class.isAssignableFrom(type)) 1657 | { 1658 | GridBagConstraints textC = new GridBagConstraints(); 1659 | textC.anchor = GridBagConstraints.NORTHWEST; 1660 | textC.insets = new Insets(3, 0, 10, 0); 1661 | panel.add(new JLabel(type == boolean.class ? "Boolean: " : "Enum: "), textC); 1662 | JComboBox comboBox = new JComboBox<>(); 1663 | List enumFields = new ArrayList<>(); 1664 | if(type == boolean.class) 1665 | { 1666 | comboBox.addItem("true"); 1667 | comboBox.addItem("false"); 1668 | if(value != null && value.equals(true)) 1669 | comboBox.setSelectedIndex(0); 1670 | else 1671 | comboBox.setSelectedIndex(1); 1672 | nullBox.setEnabled(false); 1673 | }else 1674 | { 1675 | for(Field f : type.getDeclaredFields()) 1676 | if(f.getType() == type && Modifier.isStatic(f.getModifiers())) 1677 | enumFields.add(f); 1678 | for(Field f : enumFields) 1679 | comboBox.addItem(f.getName()); 1680 | if(table.getValueAt(table.getSelectedRow(), 0) == null) 1681 | { 1682 | nullBox.setEnabled(false); 1683 | comboBox.setEnabled(false); 1684 | }else if(value == null) 1685 | { 1686 | nullBox.setSelected(true); 1687 | comboBox.setEnabled(false); 1688 | }else 1689 | { 1690 | comboBox.setSelectedItem(((Enum)value).name()); 1691 | if(comboBox.getItemCount() == 0) 1692 | comboBox.addItem(((Enum)value).name()); 1693 | } 1694 | } 1695 | GridBagConstraints valueC = new GridBagConstraints(); 1696 | valueC.anchor = GridBagConstraints.NORTHWEST; 1697 | valueC.gridx = 1; 1698 | valueC.weightx = 1; 1699 | panel.add(comboBox, valueC); 1700 | nullBox.addActionListener(a -> { 1701 | if(nullBox.isSelected()) 1702 | comboBox.setEnabled(false); 1703 | else 1704 | comboBox.setEnabled(true); 1705 | }); 1706 | setValue.addActionListener(a -> { 1707 | try 1708 | { 1709 | if(nullBox.isSelected()) 1710 | { 1711 | if(isField) 1712 | { 1713 | if(!Enum.class.isAssignableFrom(type)) 1714 | throw new IllegalStateException(type.getName()); 1715 | boolean accessible = false; 1716 | int modifier = 0; 1717 | accessible = ((Field)data.data[1]).isAccessible(); 1718 | modifier = ((Field)data.data[1]).getModifiers(); 1719 | ((Field)data.data[1]).setAccessible(true); 1720 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1721 | modifiersField.setAccessible(true); 1722 | modifiersField.setInt(((Field)data.data[1]), 1723 | ((Field)data.data[1]).getModifiers() & ~Modifier.FINAL); 1724 | ((Field)data.data[1]).set(data.data[2], null); 1725 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1726 | { 1727 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1728 | if(data1 == data) 1729 | { 1730 | fieldsTable.getModel().setValueAt(null, i, 3); 1731 | data.data[3] = ((Field)data.data[1]).get(data.data[2]) == null; 1732 | break; 1733 | } 1734 | } 1735 | ((Field)data.data[1]).setAccessible(accessible); 1736 | modifiersField.setInt(((Field)data.data[1]), modifier); 1737 | modifiersField.setAccessible(false); 1738 | }else 1739 | { 1740 | if(!Enum.class.isAssignableFrom(type)) 1741 | throw new IllegalStateException(type.getName()); 1742 | Array.set(data.data[1], (int)data.data[2], null); 1743 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1744 | { 1745 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1746 | if(data1 == data) 1747 | { 1748 | fieldsTable.getModel().setValueAt(null, i, 3); 1749 | data.data[3] = true; 1750 | break; 1751 | } 1752 | } 1753 | } 1754 | }else 1755 | { 1756 | if(isField) 1757 | { 1758 | boolean accessible = false; 1759 | int modifier = 0; 1760 | accessible = ((Field)data.data[1]).isAccessible(); 1761 | modifier = ((Field)data.data[1]).getModifiers(); 1762 | ((Field)data.data[1]).setAccessible(true); 1763 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1764 | modifiersField.setAccessible(true); 1765 | modifiersField.setInt(((Field)data.data[1]), 1766 | ((Field)data.data[1]).getModifiers() & ~Modifier.FINAL); 1767 | try 1768 | { 1769 | if(type == boolean.class) 1770 | { 1771 | boolean prim = comboBox.getSelectedIndex() == 0; 1772 | ((Field)data.data[1]).setBoolean(data.data[2], prim); 1773 | }else if(Enum.class.isAssignableFrom(type)) 1774 | { 1775 | if(comboBox.getSelectedIndex() < enumFields.size() && comboBox.getSelectedIndex() != -1) 1776 | { 1777 | boolean accessible1 = false; 1778 | int modifier1 = 0; 1779 | accessible1 = enumFields.get(comboBox.getSelectedIndex()).isAccessible(); 1780 | modifier1 = enumFields.get(comboBox.getSelectedIndex()).getModifiers(); 1781 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(true); 1782 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), 1783 | enumFields.get(comboBox.getSelectedIndex()).getModifiers() & ~Modifier.FINAL); 1784 | ((Field)data.data[1]).set(data.data[2], enumFields.get(comboBox.getSelectedIndex()).get(null)); 1785 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(accessible1); 1786 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), modifier1); 1787 | }else 1788 | ((Field)data.data[1]).set(data.data[2], null); 1789 | }else 1790 | throw new IllegalStateException(type.getName()); 1791 | }finally 1792 | { 1793 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1794 | { 1795 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1796 | if(data1 == data) 1797 | { 1798 | fieldsTable.getModel().setValueAt(((Field)data.data[1]).get( 1799 | data.data[2]), i, 3); 1800 | data.data[3] = ((Field)data.data[1]).get(data.data[2]) == null; 1801 | break; 1802 | } 1803 | } 1804 | ((Field)data.data[1]).setAccessible(accessible); 1805 | modifiersField.setInt(((Field)data.data[1]), modifier); 1806 | modifiersField.setAccessible(false); 1807 | } 1808 | }else 1809 | { 1810 | if(type == boolean.class) 1811 | { 1812 | boolean prim = comboBox.getSelectedIndex() == 0; 1813 | Array.setBoolean(data.data[1], (int)data.data[2], prim); 1814 | }else if(Enum.class.isAssignableFrom(type)) 1815 | { 1816 | if(comboBox.getSelectedIndex() < enumFields.size() && comboBox.getSelectedIndex() != -1) 1817 | { 1818 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1819 | modifiersField.setAccessible(true); 1820 | boolean accessible1 = false; 1821 | int modifier1 = 0; 1822 | accessible1 = enumFields.get(comboBox.getSelectedIndex()).isAccessible(); 1823 | modifier1 = enumFields.get(comboBox.getSelectedIndex()).getModifiers(); 1824 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(true); 1825 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), 1826 | enumFields.get(comboBox.getSelectedIndex()).getModifiers() & ~Modifier.FINAL); 1827 | Array.set(data.data[1], (int)data.data[2], enumFields.get(comboBox.getSelectedIndex()).get(null)); 1828 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(accessible1); 1829 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), modifier1); 1830 | modifiersField.setAccessible(false); 1831 | }else 1832 | Array.set(data.data[1], (int)data.data[2], null); 1833 | }else 1834 | throw new IllegalStateException(type.getName()); 1835 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1836 | { 1837 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1838 | if(data1 == data) 1839 | { 1840 | fieldsTable.getModel().setValueAt(Array.get(data.data[1], 1841 | (int)data.data[2]), i, 3); 1842 | data.data[3] = Array.get(data.data[1], (int)data.data[2]) == null; 1843 | break; 1844 | } 1845 | } 1846 | } 1847 | } 1848 | }catch(Exception e) 1849 | { 1850 | showErrorDialog("Error setting field.", e); 1851 | } 1852 | newFrame.dispose(); 1853 | }); 1854 | }else if(type.isArray()) 1855 | { 1856 | JLabel text = new JLabel("Value: "); 1857 | GridBagConstraints textC = new GridBagConstraints(); 1858 | textC.anchor = GridBagConstraints.NORTHWEST; 1859 | textC.insets = new Insets(3, 0, 10, 0); 1860 | panel.add(text, textC); 1861 | ListButton arrButton = new ListButton("Edit Array", value == null ? 1862 | Array.newInstance(type.getComponentType(), 0) : value, type.getComponentType(), panel); 1863 | GridBagConstraints arrButtonC = new GridBagConstraints(); 1864 | arrButtonC.anchor = GridBagConstraints.NORTHWEST; 1865 | arrButtonC.gridx = 1; 1866 | arrButtonC.weightx = 1; 1867 | panel.add(arrButton, arrButtonC); 1868 | 1869 | if(table.getValueAt(table.getSelectedRow(), 0) == null) 1870 | { 1871 | nullBox.setEnabled(false); 1872 | arrButton.setEnabled(false); 1873 | }else if(value == null) 1874 | { 1875 | nullBox.setSelected(true); 1876 | arrButton.setEnabled(false); 1877 | } 1878 | Class compType = getRealComponentType(type); 1879 | if(!String.class.isAssignableFrom(compType) && !compType.isPrimitive() 1880 | && !Enum.class.isAssignableFrom(compType)) 1881 | { 1882 | nullBox.setEnabled(false); 1883 | arrButton.setEnabled(false); 1884 | setValue.setEnabled(false); 1885 | } 1886 | nullBox.addActionListener(a -> { 1887 | if(nullBox.isSelected()) 1888 | arrButton.setEnabled(false); 1889 | else 1890 | arrButton.setEnabled(true); 1891 | }); 1892 | setValue.addActionListener(a -> { 1893 | try 1894 | { 1895 | if(nullBox.isSelected()) 1896 | { 1897 | if(isField) 1898 | { 1899 | boolean accessible = false; 1900 | int modifier = 0; 1901 | accessible = ((Field)data.data[1]).isAccessible(); 1902 | modifier = ((Field)data.data[1]).getModifiers(); 1903 | ((Field)data.data[1]).setAccessible(true); 1904 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1905 | modifiersField.setAccessible(true); 1906 | modifiersField.setInt(((Field)data.data[1]), 1907 | ((Field)data.data[1]).getModifiers() & ~Modifier.FINAL); 1908 | ((Field)data.data[1]).set(data.data[2], null); 1909 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1910 | { 1911 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1912 | if(data1 == data) 1913 | { 1914 | fieldsTable.getModel().setValueAt(null, i, 3); 1915 | data.data[3] = ((Field)data.data[1]).get(data.data[2]) == null; 1916 | break; 1917 | } 1918 | } 1919 | ((Field)data.data[1]).setAccessible(accessible); 1920 | modifiersField.setInt(((Field)data.data[1]), modifier); 1921 | modifiersField.setAccessible(false); 1922 | }else 1923 | { 1924 | Array.set(data.data[1], (int)data.data[2], null); 1925 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1926 | { 1927 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1928 | if(data1 == data) 1929 | { 1930 | fieldsTable.getModel().setValueAt(null, i, 3); 1931 | data.data[3] = true; 1932 | break; 1933 | } 1934 | } 1935 | } 1936 | }else 1937 | { 1938 | if(isField) 1939 | { 1940 | boolean accessible = false; 1941 | int modifier = 0; 1942 | accessible = ((Field)data.data[1]).isAccessible(); 1943 | modifier = ((Field)data.data[1]).getModifiers(); 1944 | ((Field)data.data[1]).setAccessible(true); 1945 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 1946 | modifiersField.setAccessible(true); 1947 | modifiersField.setInt(((Field)data.data[1]), 1948 | ((Field)data.data[1]).getModifiers() & ~Modifier.FINAL); 1949 | try 1950 | { 1951 | ((Field)data.data[1]).set(data.data[2], arrButton.array); 1952 | }finally 1953 | { 1954 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1955 | { 1956 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1957 | if(data1 == data) 1958 | { 1959 | Object valueAt = ((Field)data.data[1]).get(data.data[2]); 1960 | if(valueAt != null) 1961 | valueAt = getArrayName(((Field)data.data[1]).get(data.data[2]).getClass()); 1962 | fieldsTable.getModel().setValueAt(valueAt, i, 3); 1963 | data.data[3] = ((Field)data.data[1]).get(data.data[2]) == null; 1964 | break; 1965 | } 1966 | } 1967 | ((Field)data.data[1]).setAccessible(accessible); 1968 | modifiersField.setInt(((Field)data.data[1]), modifier); 1969 | modifiersField.setAccessible(false); 1970 | } 1971 | }else 1972 | { 1973 | Array.set(data.data[1], (int)data.data[2], arrButton.array); 1974 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 1975 | { 1976 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 1977 | if(data1 == data) 1978 | { 1979 | Object valueAt = ((Field)data.data[1]).get(data.data[2]); 1980 | if(valueAt != null) 1981 | valueAt = getArrayName(((Field)data.data[1]).get(data.data[2]).getClass()); 1982 | fieldsTable.getModel().setValueAt(valueAt, i, 3); 1983 | data.data[3] = Array.get(data.data[1], (int)data.data[2]) == null; 1984 | break; 1985 | } 1986 | } 1987 | } 1988 | } 1989 | }catch(Exception e) 1990 | { 1991 | showErrorDialog("Error setting field.", e); 1992 | } 1993 | newFrame.dispose(); 1994 | }); 1995 | }else 1996 | { 1997 | JLabel text = new JLabel("Value: "); 1998 | GridBagConstraints textC = new GridBagConstraints(); 1999 | textC.anchor = GridBagConstraints.NORTHWEST; 2000 | textC.insets = new Insets(3, 0, 10, 0); 2001 | panel.add(text, textC); 2002 | JTextField textField = new JTextField(20); 2003 | GridBagConstraints valueC = new GridBagConstraints(); 2004 | valueC.anchor = GridBagConstraints.NORTHWEST; 2005 | valueC.gridx = 1; 2006 | valueC.weightx = 1; 2007 | panel.add(textField, valueC); 2008 | 2009 | if(table.getValueAt(table.getSelectedRow(), 0) == null) 2010 | { 2011 | nullBox.setEnabled(false); 2012 | textField.setEnabled(false); 2013 | }else if(value == null) 2014 | { 2015 | nullBox.setSelected(true); 2016 | textField.setEnabled(false); 2017 | if(!String.class.isAssignableFrom(type) && !type.isPrimitive()) 2018 | { 2019 | setValue.setEnabled(false); 2020 | nullBox.setEnabled(false); 2021 | } 2022 | }else if(String.class.isAssignableFrom(type)) 2023 | textField.setText(value.toString()); 2024 | else if(type.isPrimitive()) 2025 | { 2026 | textField.setText(value.toString()); 2027 | nullBox.setEnabled(false); 2028 | }else 2029 | { 2030 | nullBox.setEnabled(false); 2031 | textField.setEnabled(false); 2032 | setValue.setEnabled(false); 2033 | text.setEnabled(false); 2034 | } 2035 | nullBox.addActionListener(a -> { 2036 | if(nullBox.isSelected()) 2037 | textField.setEnabled(false); 2038 | else 2039 | textField.setEnabled(true); 2040 | }); 2041 | setValue.addActionListener(a -> { 2042 | try 2043 | { 2044 | if(nullBox.isSelected()) 2045 | { 2046 | if(isField) 2047 | { 2048 | if(!String.class.isAssignableFrom(type)) 2049 | throw new IllegalStateException(type.getName()); 2050 | boolean accessible = false; 2051 | int modifier = 0; 2052 | accessible = ((Field)data.data[1]).isAccessible(); 2053 | modifier = ((Field)data.data[1]).getModifiers(); 2054 | ((Field)data.data[1]).setAccessible(true); 2055 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 2056 | modifiersField.setAccessible(true); 2057 | modifiersField.setInt(((Field)data.data[1]), 2058 | ((Field)data.data[1]).getModifiers() & ~Modifier.FINAL); 2059 | ((Field)data.data[1]).set(data.data[2], null); 2060 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 2061 | { 2062 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 2063 | if(data1 == data) 2064 | { 2065 | fieldsTable.getModel().setValueAt(null, i, 3); 2066 | data.data[3] = ((Field)data.data[1]).get(data.data[2]) == null; 2067 | break; 2068 | } 2069 | } 2070 | ((Field)data.data[1]).setAccessible(accessible); 2071 | modifiersField.setInt(((Field)data.data[1]), modifier); 2072 | modifiersField.setAccessible(false); 2073 | }else 2074 | { 2075 | if(!String.class.isAssignableFrom(type)) 2076 | throw new IllegalStateException(type.getName()); 2077 | Array.set(data.data[1], (int)data.data[2], null); 2078 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 2079 | { 2080 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 2081 | if(data1 == data) 2082 | { 2083 | fieldsTable.getModel().setValueAt(null, i, 3); 2084 | data.data[3] = true; 2085 | break; 2086 | } 2087 | } 2088 | } 2089 | }else 2090 | { 2091 | if(isField) 2092 | { 2093 | boolean accessible = false; 2094 | int modifier = 0; 2095 | accessible = ((Field)data.data[1]).isAccessible(); 2096 | modifier = ((Field)data.data[1]).getModifiers(); 2097 | ((Field)data.data[1]).setAccessible(true); 2098 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 2099 | modifiersField.setAccessible(true); 2100 | modifiersField.setInt(((Field)data.data[1]), 2101 | ((Field)data.data[1]).getModifiers() & ~Modifier.FINAL); 2102 | try 2103 | { 2104 | if(type == byte.class) 2105 | { 2106 | byte prim = Byte.parseByte(textField.getText()); 2107 | ((Field)data.data[1]).setByte(data.data[2], prim); 2108 | }else if(type == short.class) 2109 | { 2110 | short prim = Short.parseShort(textField.getText()); 2111 | ((Field)data.data[1]).setShort(data.data[2], prim); 2112 | }else if(type == int.class) 2113 | { 2114 | int prim = Integer.parseInt(textField.getText()); 2115 | ((Field)data.data[1]).setInt(data.data[2], prim); 2116 | }else if(type == long.class) 2117 | { 2118 | long prim = Long.parseLong(textField.getText()); 2119 | ((Field)data.data[1]).setLong(data.data[2], prim); 2120 | }else if(type == char.class) 2121 | { 2122 | if(textField.getText().length() == 1) 2123 | throw new IllegalArgumentException("Length of char must be 1"); 2124 | ((Field)data.data[1]).setChar(data.data[2], textField.getText().charAt(0)); 2125 | }else if(type == float.class) 2126 | { 2127 | float prim = Float.parseFloat(textField.getText()); 2128 | ((Field)data.data[1]).setFloat(data.data[2], prim); 2129 | }else if(type == double.class) 2130 | { 2131 | double prim = Double.parseDouble(textField.getText()); 2132 | ((Field)data.data[1]).setDouble(data.data[2], prim); 2133 | }else if(String.class.isAssignableFrom(type)) 2134 | ((Field)data.data[1]).set(data.data[2], textField.getText()); 2135 | else 2136 | throw new IllegalStateException(type.getName()); 2137 | }finally 2138 | { 2139 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 2140 | { 2141 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 2142 | if(data1 == data) 2143 | { 2144 | fieldsTable.getModel().setValueAt(((Field)data.data[1]).get( 2145 | data.data[2]), i, 3); 2146 | data.data[3] = ((Field)data.data[1]).get(data.data[2]) == null; 2147 | break; 2148 | } 2149 | } 2150 | ((Field)data.data[1]).setAccessible(accessible); 2151 | modifiersField.setInt(((Field)data.data[1]), modifier); 2152 | modifiersField.setAccessible(false); 2153 | } 2154 | }else 2155 | { 2156 | if(type == byte.class) 2157 | { 2158 | byte prim = Byte.parseByte(textField.getText()); 2159 | Array.setByte(data.data[1], (int)data.data[2], prim); 2160 | }else if(type == short.class) 2161 | { 2162 | short prim = Short.parseShort(textField.getText()); 2163 | Array.setShort(data.data[1], (int)data.data[2], prim); 2164 | }else if(type == int.class) 2165 | { 2166 | int prim = Integer.parseInt(textField.getText()); 2167 | Array.setInt(data.data[1], (int)data.data[2], prim); 2168 | }else if(type == long.class) 2169 | { 2170 | long prim = Long.parseLong(textField.getText()); 2171 | Array.setLong(data.data[1], (int)data.data[2], prim); 2172 | }else if(type == char.class) 2173 | { 2174 | if(textField.getText().length() == 1) 2175 | throw new IllegalArgumentException("Length of char must be 1"); 2176 | Array.setChar(data.data[1], (int)data.data[2], textField.getText().charAt(0)); 2177 | }else if(type == float.class) 2178 | { 2179 | float prim = Float.parseFloat(textField.getText()); 2180 | Array.setFloat(data.data[1], (int)data.data[2], prim); 2181 | }else if(type == double.class) 2182 | { 2183 | double prim = Double.parseDouble(textField.getText()); 2184 | Array.setDouble(data.data[1], (int)data.data[2], prim); 2185 | }else if(String.class.isAssignableFrom(type)) 2186 | Array.set(data.data[1], (int)data.data[2], textField.getText()); 2187 | else 2188 | throw new IllegalStateException(type.getName()); 2189 | for(int i = 0; i < fieldsTable.getRowCount(); i++) 2190 | { 2191 | Data data1 = (Data)fieldsTable.getModel().getValueAt(i, 2); 2192 | if(data1 == data) 2193 | { 2194 | fieldsTable.getModel().setValueAt(Array.get(data.data[1], 2195 | (int)data.data[2]), i, 3); 2196 | data.data[3] = Array.get(data.data[1], (int)data.data[2]) == null; 2197 | break; 2198 | } 2199 | } 2200 | } 2201 | } 2202 | }catch(Exception e) 2203 | { 2204 | showErrorDialog("Error setting field.", e); 2205 | } 2206 | newFrame.dispose(); 2207 | }); 2208 | } 2209 | GridBagConstraints nullBoxC = new GridBagConstraints(); 2210 | nullBoxC.insets = new Insets(0, 10, 0, 0); 2211 | nullBoxC.anchor = GridBagConstraints.NORTHWEST; 2212 | nullBoxC.gridy = 3; 2213 | newFrame.add(nullBox, nullBoxC); 2214 | 2215 | GridBagConstraints setValueC = new GridBagConstraints(); 2216 | setValueC.insets = new Insets(0, 0, 20, 0); 2217 | setValueC.anchor = GridBagConstraints.SOUTH; 2218 | setValueC.weighty = 1; 2219 | setValueC.gridy = 4; 2220 | newFrame.add(setValue, setValueC); 2221 | newFrame.setAlwaysOnTop(isOnTop); 2222 | newFrame.setVisible(true); 2223 | } 2224 | } 2225 | }); 2226 | TableColumnModel colMod = fieldsTable.getTableHeader().getColumnModel(); 2227 | TableColumn tabCol0 = colMod.getColumn(0); 2228 | tabCol0.setCellRenderer(new DefaultTableCellRenderer() 2229 | { 2230 | JLabel lbl = new JLabel(); 2231 | @Override 2232 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 2233 | { 2234 | if(isSelected) 2235 | lbl.setBackground(table.getSelectionBackground()); 2236 | else 2237 | lbl.setBackground(table.getBackground()); 2238 | lbl.setIcon((ImageIcon)value); 2239 | lbl.setOpaque(true); 2240 | return lbl; 2241 | } 2242 | }); 2243 | tabCol0.setHeaderValue(""); 2244 | tabCol0.setMinWidth(25); 2245 | tabCol0.setMaxWidth(25); 2246 | TableColumn tabCol1 = colMod.getColumn(1); 2247 | tabCol1.setCellRenderer(new DefaultTableCellRenderer() 2248 | { 2249 | JLabel lbl = new JLabel(); 2250 | @Override 2251 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 2252 | { 2253 | if(isSelected) 2254 | lbl.setBackground(table.getSelectionBackground()); 2255 | else 2256 | lbl.setBackground(table.getBackground()); 2257 | lbl.setIcon((ImageIcon)value); 2258 | lbl.setOpaque(true); 2259 | return lbl; 2260 | } 2261 | }); 2262 | tabCol1.setHeaderValue(""); 2263 | tabCol1.setMinWidth(25); 2264 | tabCol1.setMaxWidth(25); 2265 | TableColumn tabCol2 = colMod.getColumn(2); 2266 | tabCol2.setHeaderValue("name"); 2267 | tabCol2.setMinWidth(35); 2268 | TableColumn tabCol3 = colMod.getColumn(3); 2269 | tabCol3.setHeaderValue("value"); 2270 | tabCol3.setMinWidth(35); 2271 | fieldsTable.setShowHorizontalLines(false); 2272 | fieldsTable.setGridColor(Color.LIGHT_GRAY); 2273 | fieldsTable.setRowHeight(25); 2274 | jField.add(new JScrollPane(fieldsTable), BorderLayout.CENTER); 2275 | fieldMethodsTab.addTab("Methods", jMethod); 2276 | fieldMethodsTab.addTab("Fields", jField); 2277 | fieldMethodsTab.setFont(new Font("Tahoma", Font.BOLD, 15)); 2278 | fieldMethodsTab.setOpaque(true); 2279 | fieldMethodsTab.setBackground(new Color(105, 105, 105)); 2280 | GridBagConstraints fieldMethodsTabC = new GridBagConstraints(); 2281 | fieldMethodsTabC.fill = GridBagConstraints.BOTH; 2282 | fieldMethodsTabC.anchor = GridBagConstraints.NORTHWEST; 2283 | fieldMethodsTabC.weightx = 1; 2284 | fieldMethodsTabC.weighty = 1; 2285 | propertiesPanel.add(fieldMethodsTab, fieldMethodsTabC); 2286 | propertiesPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); 2287 | propertiesPanel.setMinimumSize(new Dimension(0, 0)); 2288 | 2289 | JSplitPane splitPane1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainPanel, propertiesPanel); 2290 | splitPane1.setDividerLocation(0.65); 2291 | splitPane1.setResizeWeight(0.65); 2292 | splitPane1.setContinuousLayout(true); 2293 | splitPane1.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); 2294 | splitPane1.setUI(new BasicSplitPaneUI() 2295 | { 2296 | @Override 2297 | public BasicSplitPaneDivider createDefaultDivider() 2298 | { 2299 | return new BasicSplitPaneDivider(this) 2300 | { 2301 | @Override 2302 | public void setBorder(Border b) 2303 | {} 2304 | }; 2305 | } 2306 | }); 2307 | splitPane1.setBorder(null); 2308 | splitPane1.addPropertyChangeListener(new PropertyChangeListener() 2309 | { 2310 | @Override 2311 | public void propertyChange(PropertyChangeEvent changeEvent) 2312 | { 2313 | String propertyName = changeEvent.getPropertyName(); 2314 | if(propertyName.equals(JSplitPane.DIVIDER_LOCATION_PROPERTY)) 2315 | splitPane1.setResizeWeight(((int)changeEvent.getNewValue()) / 2316 | (double)(splitPane1.getWidth() - splitPane1.getDividerSize())); 2317 | } 2318 | }); 2319 | 2320 | breakpointPanel = new JPanel(new BorderLayout()); 2321 | breakpointPanel.setPreferredSize(breakpointPanel.getPreferredSize()); 2322 | JLabel breakpointsLabel = new JLabel(" Breakpoints"); 2323 | breakpointsLabel.setPreferredSize(new Dimension(breakpointsLabel.getPreferredSize().width, breakpointsLabel.getPreferredSize().height + 6)); 2324 | breakpointsLabel.setFont(new Font("Tahoma", Font.BOLD, 15)); 2325 | breakpointsLabel.setOpaque(true); 2326 | breakpointsLabel.setBackground(new Color(105, 105, 105)); 2327 | breakpointsLabel.setForeground(Color.WHITE); 2328 | breakpointPanel.add(breakpointsLabel, BorderLayout.NORTH); 2329 | breakpointsTable = new MyTable(0, 6, 2); 2330 | breakpointsTable.setShowHorizontalLines(false); 2331 | breakpointsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 2332 | breakpointsTable.addMouseListener(new MouseAdapter() 2333 | { 2334 | @Override 2335 | public void mousePressed(MouseEvent mouseEvent) 2336 | { 2337 | JTable table = (JTable)mouseEvent.getSource(); 2338 | if(mouseEvent.getClickCount() == 2 && table.getSelectedRow() != -1 && table.getSelectedColumn() == 5) 2339 | { 2340 | Object[] values = (Object[])((Data)table.getValueAt(table.getSelectedRow(), 5)).data[0]; 2341 | if(values == null) 2342 | values = new Object[0]; 2343 | AtomicBoolean bool = (AtomicBoolean)table.getValueAt(table.getSelectedRow(), 4); 2344 | JPanel panel = new JPanel(); 2345 | panel.setBounds(100, 100, 300, 400); 2346 | panel.setLayout(new BorderLayout()); 2347 | 2348 | JTable jtable = new JTable() 2349 | { 2350 | @Override 2351 | public boolean isCellEditable(int row, int column) 2352 | { 2353 | return false; 2354 | } 2355 | }; 2356 | jtable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 2357 | jtable.getTableHeader().setReorderingAllowed(false); 2358 | DefaultTableModel lm = new DefaultTableModel(); 2359 | lm.addColumn("#"); 2360 | lm.addColumn("Type"); 2361 | lm.addColumn("Value"); 2362 | int i = 0; 2363 | for(Object o : values) 2364 | { 2365 | String type = o != null ? getArrayName(o.getClass()) : ""; 2366 | lm.addRow(new Object[]{i, type, o}); 2367 | i++; 2368 | } 2369 | jtable.setModel(lm); 2370 | jtable.getColumn("Value").setCellRenderer(new DefaultTableCellRenderer() 2371 | { 2372 | @Override 2373 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 2374 | boolean hasFocus, int row, int column) 2375 | { 2376 | if(value != null && value.getClass().isArray()) 2377 | value = getArrayName(value.getClass()); 2378 | Component cell = super.getTableCellRendererComponent(table, value, isSelected, 2379 | hasFocus, row, column); 2380 | if(!cell.getBackground().equals(table.getSelectionBackground())) 2381 | cell.setBackground(Color.WHITE); 2382 | if(column == 2 && value == null && !isSelected) 2383 | cell.setBackground(Color.RED); 2384 | return cell; 2385 | } 2386 | }); 2387 | 2388 | panel.add(new JScrollPane(jtable), BorderLayout.CENTER); 2389 | if(JOptionPane.showOptionDialog(null, panel, "View Array", 2390 | JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[] {"Ok", "Pass"}, null) == 1) 2391 | { 2392 | bool.set(true); 2393 | int newRow = -1; 2394 | for(int r = 0; r < table.getRowCount(); r++) 2395 | if(table.getValueAt(r, 4) == bool) 2396 | { 2397 | newRow = r; 2398 | break; 2399 | } 2400 | ((DefaultTableModel)table.getModel()).fireTableCellUpdated(newRow, 4); 2401 | } 2402 | } 2403 | } 2404 | }); 2405 | TableColumnModel colModB = breakpointsTable.getTableHeader().getColumnModel(); 2406 | TableColumn tabColB0 = colModB.getColumn(0); 2407 | tabColB0.setHeaderValue("ID"); 2408 | TableColumn tabColB1 = colModB.getColumn(1); 2409 | tabColB1.setHeaderValue("Time"); 2410 | tabColB1.setCellRenderer(new DefaultTableCellRenderer() 2411 | { 2412 | private SimpleDateFormat format = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); 2413 | 2414 | @Override 2415 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 2416 | { 2417 | Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 2418 | ((JLabel)c).setText(format.format(new Date((long)value))); 2419 | return c; 2420 | } 2421 | }); 2422 | TableColumn tabColB2 = colModB.getColumn(2); 2423 | tabColB2.setHeaderValue("Time Difference"); 2424 | tabColB2.setCellRenderer(new DefaultTableCellRenderer() 2425 | { 2426 | @Override 2427 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 2428 | { 2429 | Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 2430 | long diff = (long)value; 2431 | String diffMS = String.valueOf(diff % 1000); 2432 | String diffSeconds = String.valueOf(diff / 1000 % 60); 2433 | String diffMinutes = String.valueOf(diff / 60000 % 60); 2434 | String diffHours = String.valueOf(diff / 3600000); 2435 | if(diffSeconds.length() == 1) 2436 | diffSeconds = "0" + diffSeconds; 2437 | if(diffMinutes.length() == 1) 2438 | diffMinutes = "0" + diffMinutes; 2439 | if(diffHours.length() == 1) 2440 | diffHours = "0" + diffHours; 2441 | while(diffMS.length() != 4) 2442 | diffMS = "0" + diffMS; 2443 | ((JLabel)c).setText(diffHours + ":" + diffMinutes + ":" + diffSeconds + " " + diffMS); 2444 | return c; 2445 | } 2446 | }); 2447 | TableColumn tabColB3 = colModB.getColumn(3); 2448 | tabColB3.setHeaderValue("Mode"); 2449 | TableColumn tabColB4 = colModB.getColumn(4); 2450 | tabColB4.setHeaderValue("Pass"); 2451 | TableColumn tabColB5 = colModB.getColumn(5); 2452 | tabColB5.setHeaderValue("View"); 2453 | tabColB5.setCellRenderer(new TableButtonRenderer()); 2454 | breakpointsTable.setGridColor(Color.LIGHT_GRAY); 2455 | breakpointsTable.setRowHeight(25); 2456 | breakpointPanel.add(new JScrollPane(breakpointsTable), BorderLayout.CENTER); 2457 | JPanel bottomBreakpointPanel = new JPanel(new GridBagLayout()); 2458 | passBox = new JCheckBox("Pass", true); 2459 | GridBagConstraints passBoxC = new GridBagConstraints(); 2460 | passBoxC.anchor = GridBagConstraints.EAST; 2461 | passBoxC.weightx = 1; 2462 | passBoxC.insets = new Insets(0, 0, 0, 10); 2463 | bottomBreakpointPanel.add(passBox, passBoxC); 2464 | JButton clearButton = new JButton("Pass and Delete Selected Breakpoints"); 2465 | clearButton.addActionListener(new ActionListener() 2466 | { 2467 | @Override 2468 | public void actionPerformed(ActionEvent e) 2469 | { 2470 | for(int index : breakpointsTable.getSelectedRows()) 2471 | ((AtomicBoolean)breakpointsTable.getValueAt(index, 4)).set(true); 2472 | int[] indices = Arrays.copyOf(breakpointsTable.getSelectedRows(), breakpointsTable.getSelectedRows().length); 2473 | Arrays.sort(indices); 2474 | int left = 0; 2475 | int right = indices.length - 1; 2476 | while(left < right) 2477 | { 2478 | int temp = indices[left]; 2479 | indices[left] = indices[right]; 2480 | indices[right] = temp; 2481 | left++; 2482 | right--; 2483 | } 2484 | for(int i : indices) 2485 | ((DefaultTableModel)breakpointsTable.getModel()).removeRow(i); 2486 | } 2487 | }); 2488 | GridBagConstraints clearButtonC = new GridBagConstraints(); 2489 | clearButtonC.anchor = GridBagConstraints.EAST; 2490 | clearButtonC.gridx = 1; 2491 | clearButtonC.insets = new Insets(0, 0, 0, 10); 2492 | bottomBreakpointPanel.add(clearButton, clearButtonC); 2493 | bottomBreakpointPanel.setMinimumSize(new Dimension(0, 0)); 2494 | breakpointPanel.add(bottomBreakpointPanel, BorderLayout.SOUTH); 2495 | breakpointPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); 2496 | breakpointPanel.setMinimumSize(new Dimension(0, 0)); 2497 | panel.add(breakpointPanel); 2498 | 2499 | JSplitPane splitPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, splitPane1, breakpointPanel); 2500 | splitPane2.setDividerLocation(0.6); 2501 | splitPane2.setResizeWeight(0.6); 2502 | splitPane2.setContinuousLayout(true); 2503 | splitPane2.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); 2504 | splitPane2.setUI(new BasicSplitPaneUI() 2505 | { 2506 | @Override 2507 | public BasicSplitPaneDivider createDefaultDivider() 2508 | { 2509 | return new BasicSplitPaneDivider(this) 2510 | { 2511 | @Override 2512 | public void setBorder(Border b) 2513 | {} 2514 | }; 2515 | } 2516 | }); 2517 | splitPane2.setBorder(null); 2518 | splitPane2.addPropertyChangeListener(new PropertyChangeListener() 2519 | { 2520 | @Override 2521 | public void propertyChange(PropertyChangeEvent changeEvent) 2522 | { 2523 | String propertyName = changeEvent.getPropertyName(); 2524 | if(propertyName.equals(JSplitPane.DIVIDER_LOCATION_PROPERTY)) 2525 | splitPane2.setResizeWeight(((int)changeEvent.getNewValue()) / 2526 | (double)(splitPane2.getHeight() - splitPane2.getDividerSize())); 2527 | } 2528 | }); 2529 | GridBagConstraints splitPane2C = new GridBagConstraints(); 2530 | splitPane2C.anchor = GridBagConstraints.NORTHWEST; 2531 | splitPane2C.fill = GridBagConstraints.BOTH; 2532 | splitPane2C.weightx = 1; 2533 | splitPane2C.weighty = 1; 2534 | splitPane2C.insets = new Insets(3, 3, 3, 3); 2535 | panel.add(splitPane2, splitPane2C); 2536 | refreshTree(textField.getText()); 2537 | init = true; 2538 | return panel; 2539 | } 2540 | 2541 | private void updateFilter(HideableTreeNode node, String filterText, boolean clear) 2542 | { 2543 | if(clear && node != tree.getModel().getRoot()) 2544 | { 2545 | for(int i = 0; i < ((HideableTreeNode)tree.getModel().getRoot()).getChildCountFilterless(); i++) 2546 | { 2547 | HideableTreeNode child = (HideableTreeNode)((HideableTreeNode)tree.getModel().getRoot()).getChildAtFilterless(i); 2548 | child.filtered = false; 2549 | updateFilter(child, filterText, false); 2550 | } 2551 | } 2552 | for(int i = 0; i < node.getChildCountFilterless(); i++) 2553 | { 2554 | HideableTreeNode child = (HideableTreeNode)node.getChildAtFilterless(i); 2555 | String name = (String)child.getUserObject(); 2556 | if(name.contains(filterText)) 2557 | child.filtered = false; 2558 | else 2559 | child.filtered = true; 2560 | updateFilter(child, filterText, false); 2561 | } 2562 | ((DefaultTreeModel)tree.getModel()).reload(); 2563 | } 2564 | 2565 | private void refreshTree(String filter) 2566 | { 2567 | expanded.clear(); 2568 | specificSearch = null; 2569 | deleteChildren((HideableTreeNode)tree.getModel().getRoot()); 2570 | for(Field f : clazz.getDeclaredFields()) 2571 | { 2572 | String name = f.getName() + " (" + getArrayName(f.getType()) + ")"; 2573 | Object inst = null; 2574 | if(Modifier.isStatic(f.getModifiers()) || instance != null) 2575 | try 2576 | { 2577 | boolean old = f.isAccessible(); 2578 | f.setAccessible(true); 2579 | if((f.getType().isPrimitive() || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType())) 2580 | && f.get(instance) != null) 2581 | name += " = " + f.get(instance); 2582 | inst = f.get(instance); 2583 | f.setAccessible(old); 2584 | }catch(Exception e) 2585 | { 2586 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz.getName() + ")"); 2587 | } 2588 | FieldTreeNode node = new FieldTreeNode(name, f, inst, !f.getType().isPrimitive()); 2589 | top.add(node); 2590 | if(!((String)node.getUserObject()).contains(filter)) 2591 | node.filtered = true; 2592 | } 2593 | if(showAllFields) 2594 | { 2595 | Class clazz1 = clazz.getSuperclass(); 2596 | while(clazz1 != null) 2597 | { 2598 | for(Field f : clazz1.getDeclaredFields()) 2599 | { 2600 | String name = f.getName() + " (" + getArrayName(f.getType()) + ")"; 2601 | Object inst = null; 2602 | if(!Modifier.isStatic(f.getModifiers()) || instance != null) 2603 | try 2604 | { 2605 | boolean old = f.isAccessible(); 2606 | f.setAccessible(true); 2607 | if((f.getType().isPrimitive() || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType())) 2608 | && f.get(instance) != null) 2609 | name += " = " + f.get(instance); 2610 | inst = f.get(instance); 2611 | f.setAccessible(old); 2612 | }catch(Exception e) 2613 | { 2614 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz1.getName() + ")"); 2615 | } 2616 | FieldTreeNode node = new FieldTreeNode(name, f, inst, !f.getType().isPrimitive()); 2617 | top.add(node); 2618 | if(!((String)node.getUserObject()).contains(filter)) 2619 | node.filtered = true; 2620 | } 2621 | clazz1 = clazz1.getSuperclass(); 2622 | } 2623 | } 2624 | ((DefaultTreeModel)tree.getModel()).reload(); 2625 | tree.collapsePath(tree.getPathForRow(0)); 2626 | tableClazz = clazz; 2627 | tableValue = instance; 2628 | reloadFields(tableClazz, tableClazz); 2629 | reloadMethods(tableClazz, tableClazz); 2630 | } 2631 | 2632 | private void reloadFields(Class clazz, Class owner) 2633 | { 2634 | DefaultTableModel model = (DefaultTableModel)fieldsTable.getModel(); 2635 | for(int i = model.getRowCount() - 1; i >= 0; i--) 2636 | model.removeRow(i); 2637 | fieldsTable.setAutoCreateRowSorter(false); 2638 | fieldsTable.setRowSorter(null); 2639 | if(clazz.isArray()) 2640 | { 2641 | if(tableValue != null) 2642 | for(int i = 0; i < Array.getLength(tableValue); i++) 2643 | { 2644 | Object o = Array.get(tableValue, i); 2645 | if(clazz.getComponentType().isPrimitive() || String.class.isAssignableFrom(clazz.getComponentType()) 2646 | || Enum.class.isAssignableFrom(clazz.getComponentType())) 2647 | model.addRow(new Object[] {editable, publicField, new Data(new Object[] {owner, tableValue, i, o == null, clazz}), o}); 2648 | else if(getRealComponentType(clazz.getComponentType()).isPrimitive() 2649 | || String.class.isAssignableFrom(getRealComponentType(clazz.getComponentType())) 2650 | || Enum.class.isAssignableFrom(getRealComponentType(clazz.getComponentType()))) 2651 | model.addRow(new Object[] {editable, publicField, new Data(new Object[] {owner, tableValue, i, o == null, clazz}), null}); 2652 | else 2653 | model.addRow(new Object[] {null, publicField, new Data(new Object[] {owner, tableValue, i, o == null, clazz}), null}); 2654 | } 2655 | return; 2656 | } 2657 | for(Field f : clazz.getDeclaredFields()) 2658 | { 2659 | String inst = null; 2660 | ImageIcon icon = null; 2661 | boolean nullValue = false; 2662 | if(Modifier.isStatic(f.getModifiers()) || tableValue != null) 2663 | try 2664 | { 2665 | boolean old = f.isAccessible(); 2666 | f.setAccessible(true); 2667 | Object value = f.get(tableValue); 2668 | if(value == null) 2669 | nullValue = true; 2670 | if(getRealComponentType(f.getType()).isPrimitive() || String.class.isAssignableFrom(getRealComponentType(f.getType())) 2671 | || Enum.class.isAssignableFrom(getRealComponentType(f.getType()))) 2672 | { 2673 | icon = editable; 2674 | if(value != null && (f.getType().isPrimitive() 2675 | || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType()))) 2676 | inst = String.valueOf(value); 2677 | else if(value != null) 2678 | inst = getArrayName(value.getClass()); 2679 | } 2680 | f.setAccessible(old); 2681 | }catch(Exception e) 2682 | { 2683 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz.getName() + ")"); 2684 | } 2685 | ImageIcon fieldIcon = null; 2686 | if(Modifier.isPublic(f.getModifiers())) 2687 | fieldIcon = publicField; 2688 | else if (Modifier.isPrivate(f.getModifiers())) 2689 | fieldIcon = privateField; 2690 | else if (Modifier.isProtected(f.getModifiers())) 2691 | fieldIcon = protectedField; 2692 | else 2693 | fieldIcon = defaultField; 2694 | if(Modifier.isTransient(f.getModifiers())) 2695 | fieldIcon = combineAccess(fieldIcon, transientCo, 2); 2696 | boolean placedFinal = false; 2697 | boolean placedVolatile = false; 2698 | boolean placedStatic = false; 2699 | if(Modifier.isFinal(f.getModifiers())) 2700 | { 2701 | fieldIcon = combineAccess(fieldIcon, finalCo, 0); 2702 | placedFinal = true; 2703 | }else if(Modifier.isVolatile(f.getModifiers())) 2704 | { 2705 | fieldIcon = combineAccess(fieldIcon, volatileCo, 0); 2706 | placedVolatile = true; 2707 | }else if(Modifier.isStatic(f.getModifiers())) 2708 | { 2709 | fieldIcon = combineAccess(fieldIcon, staticCo, 0); 2710 | placedStatic = true; 2711 | } 2712 | if(Modifier.isFinal(f.getModifiers()) && !placedFinal) 2713 | fieldIcon = combineAccess(fieldIcon, finalCo, 1); 2714 | else if(Modifier.isVolatile(f.getModifiers()) && !placedVolatile) 2715 | fieldIcon = combineAccess(fieldIcon, volatileCo, 1); 2716 | else if(Modifier.isStatic(f.getModifiers()) && !placedStatic) 2717 | fieldIcon = combineAccess(fieldIcon, staticCo, 1); 2718 | model.addRow(new Object[] {icon, fieldIcon, new Data(new Object[] {owner, f, tableValue, nullValue}), inst}); 2719 | } 2720 | if(showAllFields) 2721 | { 2722 | clazz = clazz.getSuperclass(); 2723 | while(clazz != null) 2724 | { 2725 | for(Field f : clazz.getDeclaredFields()) 2726 | { 2727 | String inst = null; 2728 | ImageIcon icon = null; 2729 | boolean nullValue = false; 2730 | if(Modifier.isStatic(f.getModifiers()) || tableValue != null) 2731 | try 2732 | { 2733 | boolean old = f.isAccessible(); 2734 | f.setAccessible(true); 2735 | Object value = f.get(tableValue); 2736 | if(value == null) 2737 | nullValue = true; 2738 | if(getRealComponentType(f.getType()).isPrimitive() || String.class.isAssignableFrom(getRealComponentType(f.getType())) 2739 | || Enum.class.isAssignableFrom(getRealComponentType(f.getType()))) 2740 | { 2741 | icon = editable; 2742 | if(value != null && (f.getType().isPrimitive() 2743 | || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType()))) 2744 | inst = String.valueOf(value); 2745 | else if(value != null) 2746 | inst = getArrayName(value.getClass()); 2747 | } 2748 | f.setAccessible(old); 2749 | }catch(Exception e) 2750 | { 2751 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz.getName() + ")"); 2752 | } 2753 | ImageIcon fieldIcon = null; 2754 | if(Modifier.isPublic(f.getModifiers())) 2755 | fieldIcon = publicField; 2756 | else if (Modifier.isPrivate(f.getModifiers())) 2757 | fieldIcon = privateField; 2758 | else if (Modifier.isProtected(f.getModifiers())) 2759 | fieldIcon = protectedField; 2760 | else 2761 | fieldIcon = defaultField; 2762 | if(Modifier.isTransient(f.getModifiers())) 2763 | fieldIcon = combineAccess(fieldIcon, transientCo, 2); 2764 | boolean placedFinal = false; 2765 | boolean placedVolatile = false; 2766 | boolean placedStatic = false; 2767 | if(Modifier.isFinal(f.getModifiers())) 2768 | { 2769 | fieldIcon = combineAccess(fieldIcon, finalCo, 0); 2770 | placedFinal = true; 2771 | }else if(Modifier.isVolatile(f.getModifiers())) 2772 | { 2773 | fieldIcon = combineAccess(fieldIcon, volatileCo, 0); 2774 | placedVolatile = true; 2775 | }else if(Modifier.isStatic(f.getModifiers())) 2776 | { 2777 | fieldIcon = combineAccess(fieldIcon, staticCo, 0); 2778 | placedStatic = true; 2779 | } 2780 | if(Modifier.isFinal(f.getModifiers()) && !placedFinal) 2781 | fieldIcon = combineAccess(fieldIcon, finalCo, 1); 2782 | else if(Modifier.isVolatile(f.getModifiers()) && !placedVolatile) 2783 | fieldIcon = combineAccess(fieldIcon, volatileCo, 1); 2784 | else if(Modifier.isStatic(f.getModifiers()) && !placedStatic) 2785 | fieldIcon = combineAccess(fieldIcon, staticCo, 1); 2786 | model.addRow(new Object[] {fieldIcon, icon, new Data(new Object[] {owner, f, tableValue, nullValue}), inst}); 2787 | } 2788 | clazz = clazz.getSuperclass(); 2789 | } 2790 | } 2791 | fieldsTable.setAutoCreateRowSorter(true); 2792 | } 2793 | 2794 | private void reloadMethods(Class clazz, Class owner) 2795 | { 2796 | DefaultTableModel model = (DefaultTableModel)methodsTable.getModel(); 2797 | for(int i = model.getRowCount() - 1; i >= 0; i--) 2798 | model.removeRow(i); 2799 | methodsTable.setAutoCreateRowSorter(false); 2800 | methodsTable.setRowSorter(null); 2801 | for(Method m : clazz.getDeclaredMethods()) 2802 | { 2803 | boolean cannotRun = false; 2804 | if(!Modifier.isStatic(m.getModifiers()) && tableValue == null) 2805 | cannotRun = true; 2806 | if(!cannotRun) 2807 | for(Class arg : m.getParameterTypes()) 2808 | if(!getRealComponentType(arg).isPrimitive() && !String.class.isAssignableFrom(getRealComponentType(arg)) 2809 | && !Enum.class.isAssignableFrom(getRealComponentType(arg))) 2810 | { 2811 | cannotRun = true; 2812 | break; 2813 | } 2814 | ImageIcon methodIcon = null; 2815 | if(Modifier.isPublic(m.getModifiers())) 2816 | methodIcon = publicMethod; 2817 | else if (Modifier.isPrivate(m.getModifiers())) 2818 | methodIcon = privateMethod; 2819 | else if (Modifier.isProtected(m.getModifiers())) 2820 | methodIcon = protectedMethod; 2821 | else 2822 | methodIcon = defaultMethod; 2823 | if(Modifier.isSynchronized(m.getModifiers())) 2824 | methodIcon = combineAccess(methodIcon, synchronizedCo, 2); 2825 | boolean placedAbstract = false; 2826 | boolean placedFinal = false; 2827 | boolean placedStatic = false; 2828 | boolean placedNative = false; 2829 | boolean placedDefault = false; 2830 | if(Modifier.isAbstract(m.getModifiers())) 2831 | { 2832 | methodIcon = combineAccess(methodIcon, abstractCo, 0); 2833 | placedAbstract = true; 2834 | }else if(Modifier.isFinal(m.getModifiers())) 2835 | { 2836 | methodIcon = combineAccess(methodIcon, finalCo, 0); 2837 | placedFinal = true; 2838 | }else if(Modifier.isStatic(m.getModifiers())) 2839 | { 2840 | methodIcon = combineAccess(methodIcon, staticCo, 0); 2841 | placedStatic = true; 2842 | }else if(Modifier.isNative(m.getModifiers())) 2843 | { 2844 | methodIcon = combineAccess(methodIcon, nativeCo, 0); 2845 | placedNative = true; 2846 | }else if(m.isDefault()) 2847 | { 2848 | methodIcon = combineAccess(methodIcon, defaultCo, 0); 2849 | placedDefault = true; 2850 | } 2851 | if(Modifier.isAbstract(m.getModifiers()) && !placedAbstract) 2852 | methodIcon = combineAccess(methodIcon, abstractCo, 1); 2853 | else if(Modifier.isFinal(m.getModifiers()) && !placedFinal) 2854 | methodIcon = combineAccess(methodIcon, finalCo, 1); 2855 | else if(Modifier.isStatic(m.getModifiers()) && !placedStatic) 2856 | methodIcon = combineAccess(methodIcon, staticCo, 1); 2857 | else if(Modifier.isNative(m.getModifiers()) && !placedNative) 2858 | methodIcon = combineAccess(methodIcon, nativeCo, 1); 2859 | else if(m.isDefault() && !placedDefault) 2860 | methodIcon = combineAccess(methodIcon, defaultCo, 1); 2861 | model.addRow(new Object[] {cannotRun ? null : runnable, methodIcon, new Data(new Object[] {owner, m, tableValue})}); 2862 | } 2863 | if(showAllMethods) 2864 | { 2865 | clazz = clazz.getSuperclass(); 2866 | while(clazz != null) 2867 | { 2868 | for(Method m : clazz.getDeclaredMethods()) 2869 | { 2870 | boolean cannotRun = false; 2871 | if(!Modifier.isStatic(m.getModifiers()) && tableValue == null) 2872 | cannotRun = true; 2873 | if(!cannotRun) 2874 | for(Class arg : m.getParameterTypes()) 2875 | if(!getRealComponentType(arg).isPrimitive() && !String.class.isAssignableFrom(getRealComponentType(arg)) 2876 | && !Enum.class.isAssignableFrom(getRealComponentType(arg))) 2877 | { 2878 | cannotRun = true; 2879 | break; 2880 | } 2881 | ImageIcon methodIcon = null; 2882 | if(Modifier.isPublic(m.getModifiers())) 2883 | methodIcon = publicMethod; 2884 | else if (Modifier.isPrivate(m.getModifiers())) 2885 | methodIcon = privateMethod; 2886 | else if (Modifier.isProtected(m.getModifiers())) 2887 | methodIcon = protectedMethod; 2888 | else 2889 | methodIcon = defaultMethod; 2890 | if(Modifier.isSynchronized(m.getModifiers())) 2891 | methodIcon = combineAccess(methodIcon, synchronizedCo, 2); 2892 | boolean placedAbstract = false; 2893 | boolean placedFinal = false; 2894 | boolean placedStatic = false; 2895 | boolean placedNative = false; 2896 | boolean placedDefault = false; 2897 | if(Modifier.isAbstract(m.getModifiers())) 2898 | { 2899 | methodIcon = combineAccess(methodIcon, abstractCo, 0); 2900 | placedAbstract = true; 2901 | }else if(Modifier.isFinal(m.getModifiers())) 2902 | { 2903 | methodIcon = combineAccess(methodIcon, finalCo, 0); 2904 | placedFinal = true; 2905 | }else if(Modifier.isStatic(m.getModifiers())) 2906 | { 2907 | methodIcon = combineAccess(methodIcon, staticCo, 0); 2908 | placedStatic = true; 2909 | }else if(Modifier.isNative(m.getModifiers())) 2910 | { 2911 | methodIcon = combineAccess(methodIcon, nativeCo, 0); 2912 | placedNative = true; 2913 | }else if(m.isDefault()) 2914 | { 2915 | methodIcon = combineAccess(methodIcon, defaultCo, 0); 2916 | placedDefault = true; 2917 | } 2918 | if(Modifier.isAbstract(m.getModifiers()) && !placedAbstract) 2919 | methodIcon = combineAccess(methodIcon, abstractCo, 1); 2920 | else if(Modifier.isFinal(m.getModifiers()) && !placedFinal) 2921 | methodIcon = combineAccess(methodIcon, finalCo, 1); 2922 | else if(Modifier.isStatic(m.getModifiers()) && !placedStatic) 2923 | methodIcon = combineAccess(methodIcon, staticCo, 1); 2924 | else if(Modifier.isNative(m.getModifiers()) && !placedNative) 2925 | methodIcon = combineAccess(methodIcon, nativeCo, 1); 2926 | else if(m.isDefault() && !placedDefault) 2927 | methodIcon = combineAccess(methodIcon, defaultCo, 1); 2928 | model.addRow(new Object[] {cannotRun ? null : runnable, methodIcon, new Data(new Object[] {owner, m, tableValue})}); 2929 | } 2930 | clazz = clazz.getSuperclass(); 2931 | } 2932 | } 2933 | methodsTable.setAutoCreateRowSorter(true); 2934 | } 2935 | 2936 | public void deleteChildren(HideableTreeNode node) 2937 | { 2938 | for(int i = 0; i < node.getChildCountFilterless(); i++) 2939 | deleteChildren((HideableTreeNode)node.getChildAtFilterless(i)); 2940 | node.removeAllChildren(); 2941 | } 2942 | 2943 | private ImageIcon combineAccess(ImageIcon icon1, ImageIcon icon2, int mode) 2944 | { 2945 | Image img1 = icon1.getImage(); 2946 | Image img2 = icon2.getImage(); 2947 | 2948 | int w = icon1.getIconWidth(); 2949 | int h = icon1.getIconHeight(); 2950 | BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 2951 | Graphics2D g2 = image.createGraphics(); 2952 | g2.drawImage(img1, 0, 0, null); 2953 | switch(mode) 2954 | { 2955 | case 0: 2956 | g2.drawImage(img2, w / 4, h / -4, null); 2957 | break; 2958 | case 1: 2959 | g2.drawImage(img2, w / -4, h / -4, null); 2960 | break; 2961 | case 2: 2962 | g2.drawImage(img2, w / 4, h / 4, null); 2963 | break; 2964 | } 2965 | g2.dispose(); 2966 | 2967 | return new ImageIcon(image); 2968 | } 2969 | 2970 | private class MyTable extends JTable 2971 | { 2972 | private int tablemode; 2973 | 2974 | public MyTable(int numRows, int numColumns, int tablemode) 2975 | { 2976 | super(numRows, numColumns); 2977 | this.tablemode = tablemode; 2978 | } 2979 | 2980 | @Override 2981 | public Component prepareRenderer(TableCellRenderer renderer, int row, int column) 2982 | { 2983 | Component returnComp = super.prepareRenderer(renderer, row, column); 2984 | if(!returnComp.getBackground().equals(getSelectionBackground())) 2985 | returnComp.setBackground(row % 2 == 0 ? UIManager.getColor("Panel.background") : Color.WHITE); 2986 | if(column == 3 && tablemode == 1 && ((Data)getValueAt(row, 2)).data[3].equals(true) && selectionModel.getLeadSelectionIndex() != row) 2987 | returnComp.setBackground(Color.RED); 2988 | if(column == 4 && tablemode == 2 && ((AtomicBoolean)getValueAt(row, 4)).get() == true && selectionModel.getLeadSelectionIndex() != row) 2989 | returnComp.setBackground(Color.GREEN); 2990 | return returnComp; 2991 | } 2992 | 2993 | @Override 2994 | public boolean isCellEditable(int row, int column) 2995 | { 2996 | return false; 2997 | } 2998 | } 2999 | } 3000 | 3001 | private class HideableTreeNode extends DefaultMutableTreeNode 3002 | { 3003 | public boolean filtered; 3004 | 3005 | public HideableTreeNode(String name, boolean primitive) 3006 | { 3007 | super(name, primitive); 3008 | } 3009 | 3010 | public TreeNode getChildAtFilterless(int index) 3011 | { 3012 | return super.getChildAt(index); 3013 | } 3014 | 3015 | @Override 3016 | public TreeNode getChildAt(int index) 3017 | { 3018 | if(children == null) 3019 | throw new ArrayIndexOutOfBoundsException("node has no children"); 3020 | int realIndex = -1; 3021 | int visibleIndex = -1; 3022 | Enumeration e = children.elements(); 3023 | while(e.hasMoreElements()) 3024 | { 3025 | HideableTreeNode node = (HideableTreeNode)e.nextElement(); 3026 | if(!node.filtered) 3027 | visibleIndex++; 3028 | realIndex++; 3029 | if(visibleIndex == index) 3030 | return (TreeNode)children.elementAt(realIndex); 3031 | } 3032 | throw new ArrayIndexOutOfBoundsException("index unmatched"); 3033 | } 3034 | 3035 | public int getChildCountFilterless() 3036 | { 3037 | return super.getChildCount(); 3038 | } 3039 | 3040 | @Override 3041 | public int getChildCount() 3042 | { 3043 | if(children == null) 3044 | return 0; 3045 | int count = 0; 3046 | Enumeration e = children.elements(); 3047 | while(e.hasMoreElements()) 3048 | { 3049 | HideableTreeNode node = (HideableTreeNode)e.nextElement(); 3050 | if(!node.filtered) 3051 | count++; 3052 | } 3053 | return count; 3054 | } 3055 | 3056 | @Override 3057 | public void removeAllChildren() 3058 | { 3059 | for(int i = getChildCountFilterless() - 1; i >= 0; i--) 3060 | { 3061 | HideableTreeNode node = (HideableTreeNode)getChildAtFilterless(i); 3062 | children.removeElementAt(i); 3063 | node.setParent(null); 3064 | } 3065 | } 3066 | 3067 | @Override 3068 | public void add(MutableTreeNode newChild) 3069 | { 3070 | if(newChild != null && newChild.getParent() == this) 3071 | insert(newChild, getChildCountFilterless() - 1); 3072 | else 3073 | insert(newChild, getChildCountFilterless()); 3074 | } 3075 | } 3076 | 3077 | private class FieldTreeNode extends HideableTreeNode 3078 | { 3079 | public Class type; 3080 | public Class owner; 3081 | public Field field; 3082 | public Object value; 3083 | private boolean loaded; 3084 | 3085 | public FieldTreeNode(String name, Field field, Object value, boolean primitive) 3086 | { 3087 | super(name, primitive); 3088 | this.field = field; 3089 | this.value = value; 3090 | if(field.getType().isArray()) 3091 | owner = field.getDeclaringClass(); 3092 | else 3093 | owner = field.getType(); 3094 | } 3095 | 3096 | public FieldTreeNode(String name, Class type, Class owner, Object value, boolean primitive) 3097 | { 3098 | super(name, primitive); 3099 | this.type = type; 3100 | this.value = value; 3101 | this.owner = owner; 3102 | } 3103 | 3104 | public void loadChildren(String filter) 3105 | { 3106 | if(!loaded) 3107 | { 3108 | loaded = true; 3109 | Class clazz; 3110 | if(field != null) 3111 | clazz = field.getType(); 3112 | else 3113 | clazz = type; 3114 | if(clazz.isArray()) 3115 | { 3116 | if(value != null) 3117 | for(int i = 0; i < Array.getLength(value); i++) 3118 | { 3119 | Object o = Array.get(value, i); 3120 | String name = "(" + getArrayName(clazz.getComponentType()) + ")"; 3121 | if((clazz.getComponentType().isPrimitive() 3122 | || String.class.isAssignableFrom(clazz.getComponentType()) || Enum.class.isAssignableFrom(clazz.getComponentType())) 3123 | && o != null) 3124 | name += " = " + o; 3125 | FieldTreeNode node = new FieldTreeNode(name, clazz.getComponentType(), 3126 | owner, o, !clazz.getComponentType().isPrimitive()); 3127 | add(node); 3128 | if(!((String)node.getUserObject()).contains(filter)) 3129 | node.filtered = true; 3130 | } 3131 | return; 3132 | } 3133 | for(Field f : clazz.getDeclaredFields()) 3134 | { 3135 | String name = f.getName() + " (" + getArrayName(f.getType()) + ")"; 3136 | Object inst = null; 3137 | if(Modifier.isStatic(f.getModifiers()) || value != null) 3138 | try 3139 | { 3140 | boolean old = f.isAccessible(); 3141 | f.setAccessible(true); 3142 | if((f.getType().isPrimitive() || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType())) 3143 | && f.get(value) != null) 3144 | name += " = " + f.get(value); 3145 | inst = f.get(value); 3146 | f.setAccessible(old); 3147 | }catch(Exception e) 3148 | { 3149 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz.getName() + ")"); 3150 | } 3151 | FieldTreeNode node = new FieldTreeNode(name, f, inst, !f.getType().isPrimitive()); 3152 | add(node); 3153 | if(!((String)node.getUserObject()).contains(filter)) 3154 | node.filtered = true; 3155 | } 3156 | if(showAllFields) 3157 | { 3158 | clazz = clazz.getSuperclass(); 3159 | while(clazz != null) 3160 | { 3161 | for(Field f : clazz.getDeclaredFields()) 3162 | { 3163 | String name = f.getName() + " (" + getArrayName(f.getType()) + ")"; 3164 | Object inst = null; 3165 | if(Modifier.isStatic(f.getModifiers()) || value != null) 3166 | try 3167 | { 3168 | boolean old = f.isAccessible(); 3169 | f.setAccessible(true); 3170 | if((f.getType().isPrimitive() || String.class.isAssignableFrom(f.getType()) || Enum.class.isAssignableFrom(f.getType())) 3171 | && f.get(value) != null) 3172 | name += " = " + f.get(value); 3173 | inst = f.get(value); 3174 | f.setAccessible(old); 3175 | }catch(Exception e) 3176 | { 3177 | System.out.println("[DEBUG] ERROR GETTING FIELD VALUE (" + f.getName() + " @ " + clazz.getName() + ")"); 3178 | } 3179 | FieldTreeNode node = new FieldTreeNode(name, f, inst, !f.getType().isPrimitive()); 3180 | add(node); 3181 | if(!((String)node.getUserObject()).contains(filter)) 3182 | node.filtered = true; 3183 | } 3184 | clazz = clazz.getSuperclass(); 3185 | } 3186 | } 3187 | } 3188 | } 3189 | } 3190 | 3191 | private class Data 3192 | { 3193 | public Object[] data; 3194 | 3195 | public Data(Object[] data) 3196 | { 3197 | this.data = data; 3198 | } 3199 | 3200 | @Override 3201 | public String toString() 3202 | { 3203 | if(data[1] instanceof Field) 3204 | return ((Field)data[1]).getName(); 3205 | else if(data[1] instanceof Method) 3206 | return ((Method)data[1]).getName(); 3207 | return data[1].toString(); 3208 | } 3209 | } 3210 | 3211 | private class ListButton extends JButton 3212 | { 3213 | public Object array; 3214 | 3215 | public ListButton(String text, Object array, Class type, JPanel parent) 3216 | { 3217 | super(text); 3218 | this.array = array; 3219 | addActionListener(a -> { 3220 | List values = new ArrayList<>(); 3221 | for(int i = 0; i < Array.getLength(this.array); i++) 3222 | { 3223 | Object o = Array.get(this.array, i); 3224 | values.add(o); 3225 | } 3226 | JPanel panel = new JPanel(); 3227 | panel.setBounds(100, 100, 300, 400); 3228 | panel.setLayout(new BorderLayout()); 3229 | 3230 | JTable jtable = new JTable() 3231 | { 3232 | @Override 3233 | public boolean isCellEditable(int row, int column) 3234 | { 3235 | return false; 3236 | } 3237 | }; 3238 | jtable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 3239 | jtable.getTableHeader().setReorderingAllowed(false); 3240 | DefaultTableModel lm = new DefaultTableModel(); 3241 | lm.addColumn("#"); 3242 | lm.addColumn("Value"); 3243 | int i = 0; 3244 | for(Object o : values) 3245 | { 3246 | lm.addRow(new Object[]{i, o}); 3247 | i++; 3248 | } 3249 | jtable.setModel(lm); 3250 | jtable.getColumn("Value").setCellRenderer(new DefaultTableCellRenderer() 3251 | { 3252 | @Override 3253 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 3254 | boolean hasFocus, int row, int column) 3255 | { 3256 | if(value != null && value.getClass().isArray()) 3257 | value = getArrayName(value.getClass()); 3258 | Component cell = super.getTableCellRendererComponent(table, value, isSelected, 3259 | hasFocus, row, column); 3260 | if(!cell.getBackground().equals(table.getSelectionBackground())) 3261 | cell.setBackground(Color.WHITE); 3262 | if(column == 1 && value == null && !isSelected) 3263 | cell.setBackground(Color.RED); 3264 | return cell; 3265 | } 3266 | }); 3267 | 3268 | panel.add(new JScrollPane(jtable), BorderLayout.CENTER); 3269 | JPanel actions = new JPanel(); 3270 | actions.setLayout(new GridLayout(1, 4)); 3271 | JButton add = new JButton("Add"); 3272 | add.addActionListener(a2 -> { 3273 | Object o = null; 3274 | try 3275 | { 3276 | o = editValueWindow(null, type, true); 3277 | }catch(Exception e) 3278 | { 3279 | showErrorDialog("Exception while editing list value.", e); 3280 | } 3281 | int row = jtable.getSelectedRow(); 3282 | if(row != -1) 3283 | { 3284 | lm.insertRow(row, new Object[]{-1, o}); 3285 | values.add(row, o); 3286 | recalcIndex(lm); 3287 | }else 3288 | { 3289 | lm.addRow(new Object[]{lm.getRowCount(), o}); 3290 | values.add(o); 3291 | } 3292 | jtable.repaint(); 3293 | }); 3294 | actions.add(add); 3295 | JButton remove = new JButton("Remove"); 3296 | remove.addActionListener(a2 -> { 3297 | int[] selectedRows = jtable.getSelectedRows(); 3298 | if(selectedRows.length > 0) 3299 | { 3300 | for(int j = selectedRows.length - 1; j >= 0; j--) 3301 | { 3302 | lm.removeRow(selectedRows[j]); 3303 | values.remove(selectedRows[j]); 3304 | } 3305 | recalcIndex(lm); 3306 | jtable.repaint(); 3307 | } 3308 | }); 3309 | actions.add(remove); 3310 | JButton edit = new JButton("Edit"); 3311 | edit.addActionListener(a2 -> { 3312 | int row = jtable.getSelectedRow(); 3313 | if(row == -1) 3314 | return; 3315 | Object o = values.get(row); 3316 | try 3317 | { 3318 | o = editValueWindow(o, type, false); 3319 | }catch(Exception e) 3320 | { 3321 | showErrorDialog("Exception while editing list value.", e); 3322 | } 3323 | values.add(row, o); 3324 | values.remove(row + 1); 3325 | lm.insertRow(row, new Object[]{row, o}); 3326 | lm.removeRow(row + 1); 3327 | jtable.repaint(); 3328 | }); 3329 | actions.add(edit); 3330 | 3331 | panel.add(actions, BorderLayout.PAGE_END); 3332 | if(JOptionPane.showConfirmDialog(parent, panel, "Edit Array", 3333 | JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) 3334 | { 3335 | this.array = Array.newInstance(type, values.size()); 3336 | for(int i1 = 0; i1 < values.size(); i1++) 3337 | { 3338 | Object o = values.get(i1); 3339 | Array.set(this.array, i1, o); 3340 | } 3341 | } 3342 | }); 3343 | } 3344 | 3345 | private void recalcIndex(DefaultTableModel lm) 3346 | { 3347 | for(int i = 0; i < lm.getRowCount(); i++) 3348 | lm.setValueAt(i, i, 0); 3349 | } 3350 | 3351 | private Object editValueWindow(Object o, Class type, boolean isAdd) 3352 | { 3353 | JPanel panel = new JPanel(new GridBagLayout()); 3354 | GridBagConstraints panelC = new GridBagConstraints(); 3355 | panelC.insets = new Insets(10, 10, 0, 0); 3356 | panelC.anchor = GridBagConstraints.NORTHWEST; 3357 | panelC.fill = GridBagConstraints.BOTH; 3358 | panelC.gridy = 2; 3359 | panelC.weightx = 1; 3360 | JCheckBox nullBox = new JCheckBox("Null"); 3361 | JButton setValue = new JButton("Set Value"); 3362 | if(type == boolean.class || Enum.class.isAssignableFrom(type)) 3363 | { 3364 | GridBagConstraints textC = new GridBagConstraints(); 3365 | textC.anchor = GridBagConstraints.NORTHWEST; 3366 | textC.insets = new Insets(3, 0, 10, 0); 3367 | panel.add(new JLabel(type == boolean.class ? "Boolean: " : "Enum: "), textC); 3368 | JComboBox comboBox = new JComboBox<>(); 3369 | List enumFields = new ArrayList<>(); 3370 | if(type == boolean.class) 3371 | { 3372 | comboBox.addItem("true"); 3373 | comboBox.addItem("false"); 3374 | if(o != null && o.equals(true)) 3375 | comboBox.setSelectedIndex(0); 3376 | else 3377 | comboBox.setSelectedIndex(1); 3378 | nullBox.setEnabled(false); 3379 | }else 3380 | { 3381 | for(Field f : type.getDeclaredFields()) 3382 | if(f.getType() == type && Modifier.isStatic(f.getModifiers())) 3383 | enumFields.add(f); 3384 | for(Field f : enumFields) 3385 | comboBox.addItem(f.getName()); 3386 | if(o == null) 3387 | { 3388 | nullBox.setSelected(true); 3389 | comboBox.setEnabled(false); 3390 | }else 3391 | { 3392 | comboBox.setSelectedItem(((Enum)o).name()); 3393 | if(comboBox.getItemCount() == 0) 3394 | comboBox.addItem(((Enum)o).name()); 3395 | } 3396 | } 3397 | GridBagConstraints valueC = new GridBagConstraints(); 3398 | valueC.anchor = GridBagConstraints.NORTHWEST; 3399 | valueC.gridx = 1; 3400 | valueC.weightx = 1; 3401 | panel.add(comboBox, valueC); 3402 | nullBox.addActionListener(a -> { 3403 | if(nullBox.isSelected()) 3404 | comboBox.setEnabled(false); 3405 | else 3406 | comboBox.setEnabled(true); 3407 | }); 3408 | }else if(type.isArray()) 3409 | { 3410 | JLabel text = new JLabel("Value: "); 3411 | GridBagConstraints textC = new GridBagConstraints(); 3412 | textC.anchor = GridBagConstraints.NORTHWEST; 3413 | textC.insets = new Insets(3, 0, 10, 0); 3414 | panel.add(text, textC); 3415 | ListButton arrButton = new ListButton("Edit Array", o == null ? Array.newInstance(type.getComponentType(), 3416 | 0) : o, type.getComponentType(), panel); 3417 | GridBagConstraints arrButtonC = new GridBagConstraints(); 3418 | arrButtonC.anchor = GridBagConstraints.NORTHWEST; 3419 | arrButtonC.gridx = 1; 3420 | arrButtonC.weightx = 1; 3421 | panel.add(arrButton, arrButtonC); 3422 | 3423 | if(o == null) 3424 | { 3425 | nullBox.setSelected(true); 3426 | arrButton.setEnabled(false); 3427 | } 3428 | Class compType = getRealComponentType(type); 3429 | if(!String.class.isAssignableFrom(compType) && !compType.isPrimitive() 3430 | && !Enum.class.isAssignableFrom(compType)) 3431 | { 3432 | nullBox.setEnabled(false); 3433 | arrButton.setEnabled(false); 3434 | setValue.setEnabled(false); 3435 | } 3436 | nullBox.addActionListener(a -> { 3437 | if(nullBox.isSelected()) 3438 | arrButton.setEnabled(false); 3439 | else 3440 | arrButton.setEnabled(true); 3441 | }); 3442 | }else 3443 | { 3444 | JLabel text = new JLabel("Value: "); 3445 | GridBagConstraints textC = new GridBagConstraints(); 3446 | textC.anchor = GridBagConstraints.NORTHWEST; 3447 | textC.insets = new Insets(3, 0, 10, 0); 3448 | panel.add(text, textC); 3449 | JTextField textField = new JTextField(20); 3450 | GridBagConstraints valueC = new GridBagConstraints(); 3451 | valueC.anchor = GridBagConstraints.NORTHWEST; 3452 | valueC.gridx = 1; 3453 | valueC.weightx = 1; 3454 | panel.add(textField, valueC); 3455 | 3456 | if(o == null) 3457 | { 3458 | nullBox.setSelected(true); 3459 | textField.setEnabled(false); 3460 | if(!String.class.isAssignableFrom(type) && !type.isPrimitive()) 3461 | { 3462 | setValue.setEnabled(false); 3463 | nullBox.setEnabled(false); 3464 | } 3465 | }else if(String.class.isAssignableFrom(type)) 3466 | textField.setText(o.toString()); 3467 | else if(type.isPrimitive()) 3468 | { 3469 | textField.setText(o.toString()); 3470 | nullBox.setEnabled(false); 3471 | }else 3472 | { 3473 | nullBox.setEnabled(false); 3474 | textField.setEnabled(false); 3475 | setValue.setEnabled(false); 3476 | text.setEnabled(false); 3477 | } 3478 | nullBox.addActionListener(a -> { 3479 | if(nullBox.isSelected()) 3480 | textField.setEnabled(false); 3481 | else 3482 | textField.setEnabled(true); 3483 | }); 3484 | } 3485 | 3486 | GridBagConstraints nullBoxC = new GridBagConstraints(); 3487 | nullBoxC.insets = new Insets(0, 10, 0, 0); 3488 | nullBoxC.anchor = GridBagConstraints.NORTHWEST; 3489 | nullBoxC.gridy = 2; 3490 | panel.add(nullBox, nullBoxC); 3491 | 3492 | if(JOptionPane.showConfirmDialog(null, panel, isAdd ? "Add " + getArrayName(type) : 3493 | "Edit " + getArrayName(type), 3494 | JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) 3495 | { 3496 | JCheckBox box = (JCheckBox)panel.getComponent(2); 3497 | if(box.isSelected()) 3498 | return null; 3499 | else if(panel.getComponent(1) instanceof JTextField) 3500 | { 3501 | JTextField field = (JTextField)panel.getComponent(1); 3502 | if(type == byte.class) 3503 | return Byte.parseByte(field.getText()); 3504 | if(type == short.class) 3505 | return Short.parseShort(field.getText()); 3506 | if(type == int.class) 3507 | return Integer.parseInt(field.getText()); 3508 | if(type == long.class) 3509 | return Long.parseLong(field.getText()); 3510 | if(type == char.class) 3511 | { 3512 | if(field.getText().length() == 1) 3513 | throw new IllegalArgumentException("Length of char must be 1"); 3514 | return field.getText().charAt(0); 3515 | } 3516 | if(type == float.class) 3517 | return Float.parseFloat(field.getText()); 3518 | if(type == double.class) 3519 | return Double.parseDouble(field.getText()); 3520 | if(String.class.isAssignableFrom(type)) 3521 | return field.getText(); 3522 | throw new IllegalStateException(type.getName()); 3523 | }else if(panel.getComponent(1) instanceof JComboBox) 3524 | { 3525 | JComboBox comboBox = (JComboBox)panel.getComponent(1); 3526 | if(type == boolean.class) 3527 | return comboBox.getSelectedIndex() == 0; 3528 | if(Enum.class.isAssignableFrom(type)) 3529 | { 3530 | List enumFields = new ArrayList<>(); 3531 | for(Field f : type.getDeclaredFields()) 3532 | if(f.getType() == type && Modifier.isStatic(f.getModifiers())) 3533 | enumFields.add(f); 3534 | if(comboBox.getSelectedIndex() < enumFields.size() && comboBox.getSelectedIndex() != -1) 3535 | { 3536 | try 3537 | { 3538 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 3539 | modifiersField.setAccessible(true); 3540 | boolean accessible = false; 3541 | int modifier = 0; 3542 | accessible = enumFields.get(comboBox.getSelectedIndex()).isAccessible(); 3543 | modifier = enumFields.get(comboBox.getSelectedIndex()).getModifiers(); 3544 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(true); 3545 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), 3546 | enumFields.get(comboBox.getSelectedIndex()).getModifiers() & ~Modifier.FINAL); 3547 | Object toReturn = enumFields.get(comboBox.getSelectedIndex()).get(null); 3548 | enumFields.get(comboBox.getSelectedIndex()).setAccessible(accessible); 3549 | modifiersField.setInt(enumFields.get(comboBox.getSelectedIndex()), modifier); 3550 | modifiersField.setAccessible(false); 3551 | return toReturn; 3552 | }catch(Exception ex) 3553 | { 3554 | showErrorDialog("Exception occurred while choosing Enum, using null instead", ex); 3555 | return null; 3556 | } 3557 | }else 3558 | return null; 3559 | }else 3560 | throw new IllegalStateException(type.getName()); 3561 | }else if(panel.getComponent(1) instanceof ListButton) 3562 | return ((ListButton)panel.getComponent(1)).array; 3563 | return o; 3564 | }else 3565 | return o; 3566 | } 3567 | } 3568 | 3569 | public class TableButtonRenderer extends JButton implements TableCellRenderer 3570 | { 3571 | public TableButtonRenderer() 3572 | { 3573 | setOpaque(true); 3574 | } 3575 | 3576 | @Override 3577 | public Component getTableCellRendererComponent(JTable table, Object value, 3578 | boolean isSelected, boolean hasFocus, int row, int column) 3579 | { 3580 | if(isSelected) 3581 | { 3582 | setForeground(table.getSelectionForeground()); 3583 | setBackground(table.getSelectionBackground()); 3584 | }else 3585 | { 3586 | setForeground(table.getForeground()); 3587 | setBackground(UIManager.getColor("Button.background")); 3588 | } 3589 | setText(((Data)value).data[1].toString()); 3590 | return this; 3591 | } 3592 | } 3593 | } 3594 | -------------------------------------------------------------------------------- /src/main/com/thistestuser/debugger/DebuggerHook.java: -------------------------------------------------------------------------------- 1 | package com.thistestuser.debugger; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | import javax.swing.*; 9 | 10 | public class DebuggerHook 11 | { 12 | /** 13 | * The singleton instance of Debugger. 14 | */ 15 | public static Debugger debugger; 16 | public static boolean enableBreakpoints = true; 17 | private static ExecutorService executor = Executors.newSingleThreadExecutor(); 18 | 19 | /** 20 | * Add a class for analysis in Debugger. The class loaded is the previous method's owner. 21 | * @param instance The instance of the class (can be null) 22 | * @param loader The loader to load the class through (if null, uses current loader) 23 | */ 24 | public static void injectDebugger(Object instance, ClassLoader loader) 25 | { 26 | StackTraceElement[] stack = new Throwable().getStackTrace(); 27 | Thread thread = new Thread() 28 | { 29 | @Override 30 | public void run() 31 | { 32 | try 33 | { 34 | if(debugger == null) 35 | { 36 | try 37 | { 38 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 39 | }catch(ClassNotFoundException | InstantiationException 40 | | IllegalAccessException | UnsupportedLookAndFeelException e) 41 | { 42 | e.printStackTrace(); 43 | } 44 | debugger = new Debugger(); 45 | } 46 | debugger.addClass(stack[1].getClassName(), instance, loader); 47 | }catch(Exception e) 48 | { 49 | Debugger.showErrorDialog("Exception while loading Debugger.", e); 50 | } 51 | } 52 | }; 53 | executor.execute(thread); 54 | } 55 | 56 | /** 57 | * Add a class for analysis in Debugger. 58 | * @param instance The instance of the class (can be null) 59 | * @param loader The loader to load the class through (if null, uses current loader) 60 | */ 61 | public static void injectDebugger(String clazzName, Object instance, ClassLoader loader) 62 | { 63 | Thread thread = new Thread() 64 | { 65 | @Override 66 | public void run() 67 | { 68 | try 69 | { 70 | if(debugger == null) 71 | { 72 | try 73 | { 74 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 75 | }catch(ClassNotFoundException | InstantiationException 76 | | IllegalAccessException | UnsupportedLookAndFeelException e) 77 | { 78 | e.printStackTrace(); 79 | } 80 | debugger = new Debugger(); 81 | } 82 | debugger.addClass(clazzName, instance, loader); 83 | }catch(Exception e) 84 | { 85 | Debugger.showErrorDialog("Exception while loading Debugger.", e); 86 | } 87 | } 88 | }; 89 | executor.execute(thread); 90 | } 91 | 92 | /** 93 | * Adds a breakpoint to the debugger. Breakpoints record information about the variables you choose, and 94 | * also stop the execution if necessary. You can choose when to continue if the execution is stopped. 95 | * @param clazzName The class name of the tab that the breakpoint will be associated with. 96 | * @param instance The instance of the tab that the breakpoint will be associated with. If the tab doesn't exist, it will be created. 97 | * @param loader The loader to load the class. Used only if the class isn't already loaded. 98 | * @param id The unique ID of the breakpoint. Only 1 ID is allowed per class instance. 99 | * @param input The variables to analyze. The results can be printed out with the "View" button. 100 | * @param mode If the breakpoint should pause the execution of the program. 0 will depend on the pass checkbox, 101 | * 1 will always pass, and 2 will always pause. 102 | * @param override If this is true and there is already a breakpoint with the same ID, 103 | * the breakpoint will automatically pass and be replaced with this one. 104 | */ 105 | public static void injectBreakpoint(String clazzName, Object instance, ClassLoader loader, 106 | int id, Object[] input, int mode, boolean override) 107 | { 108 | AtomicBoolean isFinished = new AtomicBoolean(); 109 | Thread thread = new Thread() 110 | { 111 | @Override 112 | public void run() 113 | { 114 | try 115 | { 116 | if(debugger == null) 117 | { 118 | try 119 | { 120 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 121 | }catch(ClassNotFoundException | InstantiationException 122 | | IllegalAccessException | UnsupportedLookAndFeelException e) 123 | { 124 | e.printStackTrace(); 125 | } 126 | debugger = new Debugger(); 127 | } 128 | debugger.addClass(clazzName, instance, loader); 129 | }catch(Exception e) 130 | { 131 | Debugger.showErrorDialog("Exception while loading Debugger.", e); 132 | } 133 | isFinished.set(true); 134 | } 135 | }; 136 | Future future = executor.submit(thread); 137 | try 138 | { 139 | while(true) 140 | { 141 | if((isFinished.get() || future.isDone()) && debugger == null) 142 | throw new IllegalStateException("Debugger class could not load"); 143 | if(debugger != null && debugger.isInstInit(clazzName, instance, loader)) 144 | break; 145 | } 146 | debugger.injectBreakpoint(clazzName, instance, loader, id, input, mode, override); 147 | }catch(Exception e) 148 | { 149 | Debugger.showErrorDialog("Exception while adding breakpoint.", e); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /wiki/attach_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/attach_1.PNG -------------------------------------------------------------------------------- /wiki/attach_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/attach_2.PNG -------------------------------------------------------------------------------- /wiki/breakpoints_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/breakpoints_1.PNG -------------------------------------------------------------------------------- /wiki/breakpoints_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/breakpoints_2.PNG -------------------------------------------------------------------------------- /wiki/fields_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/fields_1.PNG -------------------------------------------------------------------------------- /wiki/fields_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/fields_2.PNG -------------------------------------------------------------------------------- /wiki/fields_3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/fields_3.PNG -------------------------------------------------------------------------------- /wiki/methods_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/methods_1.PNG -------------------------------------------------------------------------------- /wiki/methods_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/methods_2.PNG -------------------------------------------------------------------------------- /wiki/search_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/search_1.PNG -------------------------------------------------------------------------------- /wiki/search_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThisTestUser/Java-Debugger/78a15a0b6a49ecd31e22ad1e6484beadcdfa27d5/wiki/search_2.PNG --------------------------------------------------------------------------------