1 | 1 | | package jadx.gui.ui; |
2 | 2 | | |
3 | 3 | | import jadx.gui.treemodel.JClass; |
| 4 | + | import jadx.gui.utils.NLS; |
4 | 5 | | import jadx.gui.utils.Utils; |
5 | 6 | | |
6 | 7 | | import javax.swing.BorderFactory; |
7 | 8 | | import javax.swing.ImageIcon; |
8 | 9 | | import javax.swing.JButton; |
9 | 10 | | import javax.swing.JLabel; |
| 11 | + | import javax.swing.JMenuItem; |
10 | 12 | | import javax.swing.JPanel; |
| 13 | + | import javax.swing.JPopupMenu; |
11 | 14 | | import javax.swing.JTabbedPane; |
| 15 | + | import javax.swing.SwingUtilities; |
12 | 16 | | import javax.swing.plaf.basic.BasicButtonUI; |
13 | 17 | | import java.awt.Component; |
14 | 18 | | import java.awt.FlowLayout; |
| skipped 1 lines |
16 | 20 | | import java.awt.event.ActionListener; |
17 | 21 | | import java.awt.event.MouseAdapter; |
18 | 22 | | import java.awt.event.MouseEvent; |
19 | | - | import java.util.HashMap; |
| 23 | + | import java.awt.event.MouseWheelEvent; |
| 24 | + | import java.awt.event.MouseWheelListener; |
| 25 | + | import java.util.ArrayList; |
| 26 | + | import java.util.LinkedHashMap; |
| 27 | + | import java.util.List; |
20 | 28 | | import java.util.Map; |
21 | 29 | | |
22 | 30 | | class TabbedPane extends JTabbedPane { |
| 31 | + | |
| 32 | + | private static final long serialVersionUID = -8833600618794570904L; |
23 | 33 | | |
24 | 34 | | private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross"); |
25 | 35 | | private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed"); |
26 | 36 | | |
27 | 37 | | private final MainWindow mainWindow; |
28 | | - | private final Map<JClass, CodePanel> openTabs = new HashMap<JClass, CodePanel>(); |
| 38 | + | private final Map<JClass, CodePanel> openTabs = new LinkedHashMap<JClass, CodePanel>(); |
29 | 39 | | |
30 | 40 | | TabbedPane(MainWindow window) { |
31 | 41 | | mainWindow = window; |
32 | 42 | | |
33 | 43 | | setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); |
| 44 | + | |
| 45 | + | addMouseWheelListener(new MouseWheelListener() { |
| 46 | + | public void mouseWheelMoved(MouseWheelEvent e) { |
| 47 | + | int direction = e.getWheelRotation(); |
| 48 | + | int index = getSelectedIndex(); |
| 49 | + | int maxIndex = getTabCount() - 1; |
| 50 | + | if ((index == 0 && direction < 0) |
| 51 | + | || (index == maxIndex && direction > 0)) { |
| 52 | + | index = maxIndex - index; |
| 53 | + | } else { |
| 54 | + | index += direction; |
| 55 | + | } |
| 56 | + | setSelectedIndex(index); |
| 57 | + | } |
| 58 | + | }); |
| 59 | + | } |
| 60 | + | |
| 61 | + | MainWindow getMainWindow() { |
| 62 | + | return mainWindow; |
| 63 | + | } |
| 64 | + | |
| 65 | + | void showCode(final JClass cls, final int line) { |
| 66 | + | final CodePanel codePanel = getCodePanel(cls); |
| 67 | + | SwingUtilities.invokeLater(new Runnable() { |
| 68 | + | @Override |
| 69 | + | public void run() { |
| 70 | + | setSelectedComponent(codePanel); |
| 71 | + | CodeArea codeArea = codePanel.getCodeArea(); |
| 72 | + | codeArea.scrollToLine(line); |
| 73 | + | codeArea.requestFocus(); |
| 74 | + | } |
| 75 | + | }); |
34 | 76 | | } |
35 | 77 | | |
36 | 78 | | private void addCodePanel(CodePanel codePanel) { |
| 79 | + | openTabs.put(codePanel.getCls(), codePanel); |
37 | 80 | | add(codePanel); |
38 | | - | openTabs.put(codePanel.getCls(), codePanel); |
39 | 81 | | } |
40 | 82 | | |
41 | 83 | | private void closeCodePanel(CodePanel codePanel) { |
| 84 | + | openTabs.remove(codePanel.getCls()); |
42 | 85 | | remove(codePanel); |
43 | | - | openTabs.remove(codePanel.getCls()); |
44 | 86 | | } |
45 | 87 | | |
46 | | - | void showCode(JClass cls, int line) { |
| 88 | + | private CodePanel getCodePanel(JClass cls) { |
47 | 89 | | CodePanel panel = openTabs.get(cls); |
48 | 90 | | if (panel == null) { |
49 | 91 | | panel = new CodePanel(this, cls); |
50 | 92 | | addCodePanel(panel); |
51 | 93 | | setTabComponentAt(indexOfComponent(panel), makeTabComponent(panel)); |
52 | 94 | | } |
| 95 | + | return panel; |
| 96 | + | } |
| 97 | + | |
| 98 | + | private CodePanel getCodePanel(int index) { |
| 99 | + | Component component = getComponent(index); |
| 100 | + | if (component instanceof CodePanel) { |
| 101 | + | return (CodePanel) component; |
| 102 | + | } |
| 103 | + | return null; |
| 104 | + | } |
53 | 105 | | |
54 | | - | setSelectedComponent(panel); |
55 | | - | CodeArea codeArea = panel.getCodeArea(); |
56 | | - | codeArea.scrollToLine(line); |
57 | | - | codeArea.requestFocus(); |
| 106 | + | CodePanel getSelectedCodePanel() { |
| 107 | + | return (CodePanel) getSelectedComponent(); |
58 | 108 | | } |
59 | 109 | | |
60 | 110 | | private Component makeTabComponent(final CodePanel codePanel) { |
61 | 111 | | JClass cls = codePanel.getCls(); |
62 | 112 | | String name = cls.getCls().getFullName(); |
63 | | - | JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0)); |
| 113 | + | |
| 114 | + | final JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0)); |
64 | 115 | | panel.setOpaque(false); |
65 | 116 | | |
66 | 117 | | final JLabel label = new JLabel(name); |
| skipped 20 lines |
87 | 138 | | panel.addMouseListener(new MouseAdapter() { |
88 | 139 | | @Override |
89 | 140 | | public void mouseClicked(MouseEvent e) { |
90 | | - | if (e.getButton() == MouseEvent.BUTTON2) { |
| 141 | + | if (SwingUtilities.isMiddleMouseButton(e)) { |
91 | 142 | | closeCodePanel(codePanel); |
| 143 | + | } else if (SwingUtilities.isRightMouseButton(e)) { |
| 144 | + | JPopupMenu menu = createTabPopupMenu(codePanel); |
| 145 | + | menu.show(panel, e.getX(), e.getY()); |
92 | 146 | | } else { |
93 | 147 | | // TODO: make correct event delegation to tabbed pane |
94 | 148 | | setSelectedComponent(codePanel); |
| skipped 7 lines |
102 | 156 | | return panel; |
103 | 157 | | } |
104 | 158 | | |
105 | | - | CodePanel getSelectedCodePanel() { |
106 | | - | return (CodePanel) getSelectedComponent(); |
107 | | - | } |
| 159 | + | private JPopupMenu createTabPopupMenu(final CodePanel codePanel) { |
| 160 | + | JPopupMenu menu = new JPopupMenu(); |
| 161 | + | |
| 162 | + | JMenuItem closeTab = new JMenuItem(NLS.str("tabs.close")); |
| 163 | + | closeTab.addActionListener(new ActionListener() { |
| 164 | + | @Override |
| 165 | + | public void actionPerformed(ActionEvent e) { |
| 166 | + | closeCodePanel(codePanel); |
| 167 | + | } |
| 168 | + | }); |
| 169 | + | menu.add(closeTab); |
108 | 170 | | |
109 | | - | MainWindow getMainWindow() { |
110 | | - | return mainWindow; |
| 171 | + | if (openTabs.size() > 1) { |
| 172 | + | JMenuItem closeOther = new JMenuItem(NLS.str("tabs.closeOthers")); |
| 173 | + | closeOther.addActionListener(new ActionListener() { |
| 174 | + | @Override |
| 175 | + | public void actionPerformed(ActionEvent e) { |
| 176 | + | List<CodePanel> codePanels = new ArrayList<CodePanel>(openTabs.values()); |
| 177 | + | for (CodePanel panel : codePanels) { |
| 178 | + | if (panel != codePanel) { |
| 179 | + | closeCodePanel(panel); |
| 180 | + | } |
| 181 | + | } |
| 182 | + | } |
| 183 | + | }); |
| 184 | + | menu.add(closeOther); |
| 185 | + | |
| 186 | + | JMenuItem closeAll = new JMenuItem(NLS.str("tabs.closeAll")); |
| 187 | + | closeAll.addActionListener(new ActionListener() { |
| 188 | + | @Override |
| 189 | + | public void actionPerformed(ActionEvent e) { |
| 190 | + | List<CodePanel> codePanels = new ArrayList<CodePanel>(openTabs.values()); |
| 191 | + | for (CodePanel panel : codePanels) { |
| 192 | + | closeCodePanel(panel); |
| 193 | + | } |
| 194 | + | } |
| 195 | + | }); |
| 196 | + | menu.add(closeAll); |
| 197 | + | menu.addSeparator(); |
| 198 | + | |
| 199 | + | CodePanel selectedCodePanel = getSelectedCodePanel(); |
| 200 | + | for (final Map.Entry<JClass, CodePanel> entry : openTabs.entrySet()) { |
| 201 | + | final CodePanel cp = entry.getValue(); |
| 202 | + | if (cp == selectedCodePanel) { |
| 203 | + | continue; |
| 204 | + | } |
| 205 | + | JClass jClass = entry.getKey(); |
| 206 | + | final String clsName = jClass.getCls().getFullName(); |
| 207 | + | JMenuItem item = new JMenuItem(clsName); |
| 208 | + | item.addActionListener(new ActionListener() { |
| 209 | + | @Override |
| 210 | + | public void actionPerformed(ActionEvent e) { |
| 211 | + | setSelectedComponent(cp); |
| 212 | + | } |
| 213 | + | }); |
| 214 | + | item.setIcon(jClass.getIcon()); |
| 215 | + | menu.add(item); |
| 216 | + | } |
| 217 | + | } |
| 218 | + | return menu; |
111 | 219 | | } |
112 | 220 | | } |
113 | 221 | | |