1 | | - | package jadx.gui; |
| 1 | + | package jadx.gui.ui; |
2 | 2 | | |
| 3 | + | import jadx.gui.JadxWrapper; |
3 | 4 | | import jadx.gui.treemodel.JClass; |
4 | 5 | | import jadx.gui.treemodel.JNode; |
5 | 6 | | import jadx.gui.treemodel.JRoot; |
6 | 7 | | import jadx.gui.utils.NLS; |
7 | 8 | | import jadx.gui.utils.Utils; |
8 | 9 | | |
9 | | - | import javax.swing.AbstractAction; |
10 | | - | import javax.swing.BorderFactory; |
11 | 10 | | import javax.swing.ImageIcon; |
12 | 11 | | import javax.swing.JButton; |
13 | 12 | | import javax.swing.JFileChooser; |
14 | 13 | | import javax.swing.JFrame; |
15 | | - | import javax.swing.JLabel; |
16 | 14 | | import javax.swing.JMenu; |
17 | 15 | | import javax.swing.JMenuBar; |
18 | 16 | | import javax.swing.JMenuItem; |
19 | 17 | | import javax.swing.JPanel; |
20 | 18 | | import javax.swing.JScrollPane; |
21 | 19 | | import javax.swing.JSplitPane; |
22 | | - | import javax.swing.JTabbedPane; |
23 | | - | import javax.swing.JTextArea; |
24 | 20 | | import javax.swing.JToggleButton; |
25 | 21 | | import javax.swing.JToolBar; |
26 | 22 | | import javax.swing.JTree; |
27 | | - | import javax.swing.KeyStroke; |
28 | 23 | | import javax.swing.ProgressMonitor; |
29 | 24 | | import javax.swing.event.TreeExpansionEvent; |
30 | 25 | | import javax.swing.event.TreeWillExpandListener; |
31 | 26 | | import javax.swing.filechooser.FileNameExtensionFilter; |
32 | | - | import javax.swing.plaf.basic.BasicButtonUI; |
33 | | - | import javax.swing.text.BadLocationException; |
34 | 27 | | import javax.swing.tree.DefaultMutableTreeNode; |
35 | 28 | | import javax.swing.tree.DefaultTreeCellRenderer; |
36 | 29 | | import javax.swing.tree.DefaultTreeModel; |
| skipped 3 lines |
40 | 33 | | import java.awt.BorderLayout; |
41 | 34 | | import java.awt.Component; |
42 | 35 | | import java.awt.DisplayMode; |
43 | | - | import java.awt.FlowLayout; |
44 | 36 | | import java.awt.GraphicsDevice; |
45 | 37 | | import java.awt.GraphicsEnvironment; |
46 | 38 | | import java.awt.event.ActionEvent; |
47 | 39 | | import java.awt.event.ActionListener; |
48 | | - | import java.awt.event.InputEvent; |
49 | 40 | | import java.awt.event.KeyAdapter; |
50 | 41 | | import java.awt.event.KeyEvent; |
51 | 42 | | import java.awt.event.MouseAdapter; |
52 | 43 | | import java.awt.event.MouseEvent; |
53 | 44 | | import java.io.File; |
54 | | - | import java.util.HashMap; |
55 | | - | import java.util.Map; |
56 | 45 | | |
57 | | - | import org.fife.ui.rtextarea.RTextScrollPane; |
58 | 46 | | import org.slf4j.Logger; |
59 | 47 | | import org.slf4j.LoggerFactory; |
60 | 48 | | |
| skipped 9 lines |
70 | 58 | | private static final ImageIcon ICON_OPEN = Utils.openIcon("folder"); |
71 | 59 | | private static final ImageIcon ICON_SAVE_ALL = Utils.openIcon("disk_multiple"); |
72 | 60 | | private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross"); |
73 | | - | private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed"); |
74 | 61 | | private static final ImageIcon ICON_FLAT_PKG = Utils.openIcon("empty_logical_package_obj"); |
75 | 62 | | private static final ImageIcon ICON_SEARCH = Utils.openIcon("magnifier"); |
76 | 63 | | |
| skipped 3 lines |
80 | 67 | | |
81 | 68 | | private JTree tree; |
82 | 69 | | private DefaultTreeModel treeModel; |
83 | | - | |
84 | | - | private final JTabbedPane tabbedPane = new JTabbedPane(); |
85 | | - | private final Map<JClass, Component> openTabs = new HashMap<JClass, Component>(); |
| 70 | + | private TabbedPane tabbedPane; |
86 | 71 | | |
87 | 72 | | public MainWindow(JadxWrapper wrapper) { |
88 | 73 | | this.wrapper = wrapper; |
| skipped 49 lines |
138 | 123 | | } |
139 | 124 | | } |
140 | 125 | | |
141 | | - | private void toggleSearch() { |
142 | | - | SearchBar searchBar = getSearchBar((JPanel) tabbedPane.getSelectedComponent()); |
143 | | - | searchBar.toggle(); |
144 | | - | } |
145 | | - | |
146 | 126 | | private void treeClickAction() { |
147 | 127 | | Object obj = tree.getLastSelectedPathComponent(); |
148 | 128 | | if (obj instanceof JNode) { |
149 | 129 | | JNode node = (JNode) obj; |
150 | 130 | | JClass cls = node.getRootClass(); |
151 | 131 | | if (cls != null) { |
152 | | - | showCode(cls, node.getLine()); |
| 132 | + | tabbedPane.showCode(cls, node.getLine()); |
153 | 133 | | } |
154 | 134 | | } |
155 | 135 | | } |
156 | 136 | | |
157 | | - | private JPanel newCodePane(final JClass cls) { |
158 | | - | JadxTextArea textArea = new JadxTextArea(this, cls); |
159 | | - | RTextScrollPane scrollPane = new RTextScrollPane(textArea); |
160 | | - | scrollPane.setFoldIndicatorEnabled(true); |
161 | | - | |
162 | | - | JPanel textPanel = new JPanel(new BorderLayout()); |
163 | | - | SearchBar searchBar = new SearchBar(textArea); |
164 | | - | textPanel.add(searchBar, BorderLayout.NORTH); |
165 | | - | textPanel.add(scrollPane); |
166 | | - | |
167 | | - | KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK); |
168 | | - | Utils.addKeyBinding(textArea, key, "SearchAction", new AbstractAction() { |
169 | | - | @Override |
170 | | - | public void actionPerformed(ActionEvent e) { |
171 | | - | toggleSearch(); |
172 | | - | } |
173 | | - | }); |
174 | | - | return textPanel; |
175 | | - | } |
176 | | - | |
177 | | - | private SearchBar getSearchBar(JPanel panel) { |
178 | | - | return (SearchBar) panel.getComponent(0); |
179 | | - | } |
180 | | - | |
181 | | - | private JadxTextArea getTextArea(JPanel panel) { |
182 | | - | RTextScrollPane scrollPane = (RTextScrollPane) panel.getComponent(1); |
183 | | - | return (JadxTextArea) scrollPane.getTextArea(); |
184 | | - | } |
185 | | - | |
186 | | - | void showCode(JClass cls, int line) { |
187 | | - | JPanel panel = (JPanel) openTabs.get(cls); |
188 | | - | if (panel != null) { |
189 | | - | panel = (JPanel) openTabs.get(cls); |
190 | | - | tabbedPane.setSelectedComponent(panel); |
191 | | - | } else { |
192 | | - | panel = newCodePane(cls); |
193 | | - | tabbedPane.add(panel); |
194 | | - | openTabs.put(cls, panel); |
195 | | - | int id = tabbedPane.indexOfComponent(panel); |
196 | | - | tabbedPane.setTabComponentAt(id, makeTabComponent(cls, panel)); |
197 | | - | tabbedPane.setSelectedIndex(id); |
198 | | - | } |
199 | | - | JadxTextArea textArea = getTextArea(panel); |
200 | | - | scrollToLine(textArea, line); |
201 | | - | } |
202 | | - | |
203 | | - | private Component makeTabComponent(final JClass cls, final Component comp) { |
204 | | - | String name = cls.getCls().getFullName(); |
205 | | - | JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0)); |
206 | | - | panel.setOpaque(false); |
207 | | - | |
208 | | - | final JLabel label = new JLabel(name); |
209 | | - | label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10)); |
210 | | - | label.setIcon(cls.getIcon()); |
211 | | - | |
212 | | - | final JButton button = new JButton(); |
213 | | - | button.setIcon(ICON_CLOSE_INACTIVE); |
214 | | - | button.setRolloverIcon(ICON_CLOSE); |
215 | | - | button.setRolloverEnabled(true); |
216 | | - | button.setOpaque(false); |
217 | | - | button.setUI(new BasicButtonUI()); |
218 | | - | button.setContentAreaFilled(false); |
219 | | - | button.setFocusable(false); |
220 | | - | button.setBorder(null); |
221 | | - | button.setBorderPainted(false); |
222 | | - | button.addActionListener(new ActionListener() { |
223 | | - | @Override |
224 | | - | public void actionPerformed(ActionEvent e) { |
225 | | - | closeCodeTab(cls, comp); |
226 | | - | } |
227 | | - | }); |
228 | | - | |
229 | | - | panel.addMouseListener(new MouseAdapter() { |
230 | | - | @Override |
231 | | - | public void mouseClicked(MouseEvent e) { |
232 | | - | if (e.getButton() == MouseEvent.BUTTON2) { |
233 | | - | closeCodeTab(cls, comp); |
234 | | - | } else { |
235 | | - | // TODO: make correct event delegation to tabbed pane |
236 | | - | tabbedPane.setSelectedComponent(comp); |
237 | | - | } |
238 | | - | } |
239 | | - | }); |
240 | | - | |
241 | | - | panel.add(label); |
242 | | - | panel.add(button); |
243 | | - | panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); |
244 | | - | return panel; |
245 | | - | } |
246 | | - | |
247 | | - | private void closeCodeTab(JClass cls, Component comp) { |
248 | | - | tabbedPane.remove(comp); |
249 | | - | openTabs.remove(cls); |
250 | | - | } |
251 | | - | |
252 | | - | private void scrollToLine(JTextArea textArea, int line) { |
253 | | - | if (line == 0) { |
254 | | - | line = 1; |
255 | | - | } |
256 | | - | try { |
257 | | - | textArea.setCaretPosition(textArea.getLineStartOffset(line - 1)); |
258 | | - | } catch (BadLocationException e) { |
259 | | - | LOG.error("Can't scroll to " + line, e); |
260 | | - | } |
| 137 | + | private void toggleSearch() { |
| 138 | + | tabbedPane.getSelectedCodePanel().getSearchBar().toggle(); |
261 | 139 | | } |
262 | 140 | | |
263 | 141 | | private void initMenuAndToolbar() { |
| skipped 132 lines |
396 | 274 | | JScrollPane treeScrollPane = new JScrollPane(tree); |
397 | 275 | | splitPane.setLeftComponent(treeScrollPane); |
398 | 276 | | |
399 | | - | tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); |
| 277 | + | tabbedPane = new TabbedPane(this); |
400 | 278 | | splitPane.setRightComponent(tabbedPane); |
401 | 279 | | |
402 | 280 | | setContentPane(mainPanel); |
| skipped 19 lines |