bcv-vf/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java

254 lines
11 KiB
Java
Raw Normal View History

package the.bytecode.club.bytecodeviewer.gui;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
2021-04-12 20:19:12 +00:00
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.InputEvent;
2021-04-12 22:31:22 +00:00
import java.util.Objects;
2021-04-12 20:19:12 +00:00
import java.util.regex.Matcher;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JViewport;
import javax.swing.ListCellRenderer;
2019-04-17 06:45:15 +00:00
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
2021-04-12 20:19:12 +00:00
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.RTextScrollPane;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.util.MethodParser;
2019-04-17 06:45:15 +00:00
import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK;
/**
* Allows us to run a background thread
2018-01-31 15:41:24 +00:00
*
* @author Konloch
2019-04-17 06:45:15 +00:00
* @author DreamSworK
*/
2021-04-12 20:19:12 +00:00
public abstract class PaneUpdaterThread extends Thread {
2019-04-17 06:45:15 +00:00
public ClassViewer viewer;
public RSyntaxTextArea panelArea;
public RTextScrollPane scrollPane;
public JComboBox<Integer> methodsList;
public int decompiler;
public int paneId;
2018-01-31 15:41:24 +00:00
public abstract void doShit();
2018-01-31 15:41:24 +00:00
@Override
public void run() {
doShit();
2019-04-17 06:45:15 +00:00
synchronizePane();
2021-06-22 00:46:57 +00:00
attachCtrlMouseWheelZoom(scrollPane, panelArea); //freezes the UI for some reason
//probably cause BCV is doing dumb shit with the swing thread
2019-04-25 21:27:35 +00:00
}
2021-04-12 20:19:12 +00:00
public void attachCtrlMouseWheelZoom(RTextScrollPane scrollPane, RSyntaxTextArea panelArea) {
if (scrollPane == null)
2019-04-25 21:27:35 +00:00
return;
2021-04-12 22:31:22 +00:00
scrollPane.addMouseWheelListener(e -> {
if (panelArea == null || panelArea.getText().isEmpty())
return;
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
Font font = panelArea.getFont();
int size = font.getSize();
if (e.getWheelRotation() > 0) { //Up
panelArea.setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));
} else { //Down
panelArea.setFont(new Font(font.getName(), font.getStyle(), ++size));
2019-04-25 21:27:35 +00:00
}
}
2021-04-12 22:31:22 +00:00
e.consume();
2019-04-25 21:27:35 +00:00
});
2019-04-17 06:45:15 +00:00
}
2021-04-12 20:19:12 +00:00
public final CaretListener caretListener = new CaretListener() {
2019-04-17 06:45:15 +00:00
@Override
2021-04-12 20:19:12 +00:00
public void caretUpdate(CaretEvent e) {
2019-04-17 06:45:15 +00:00
MethodParser methods = viewer.methods.get(paneId);
2021-04-12 20:19:12 +00:00
if (methods != null) {
2019-04-17 06:45:15 +00:00
int methodLine = methods.findActiveMethod(panelArea.getCaretLineNumber());
2021-04-12 20:19:12 +00:00
if (methodLine != -1) {
if (BytecodeViewer.viewer.showClassMethods.isSelected()) {
if (methodsList != null) {
2021-04-12 22:31:22 +00:00
if (methodLine != (int) Objects.requireNonNull(methodsList.getSelectedItem())) {
2019-04-17 06:45:15 +00:00
methodsList.setSelectedItem(methodLine);
}
}
}
2021-04-12 20:19:12 +00:00
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
2019-04-17 06:45:15 +00:00
int panes = 2;
2021-04-12 20:19:12 +00:00
if (viewer.panel3 != null)
2019-04-17 06:45:15 +00:00
panes = 3;
2021-04-12 20:19:12 +00:00
for (int i = 0; i < panes; i++) {
if (i != paneId) {
2019-04-17 06:45:15 +00:00
ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine));
}
}
}
}
}
}
};
public final ChangeListener viewportListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int panes = 2;
2021-04-12 20:19:12 +00:00
if (viewer.panel3 != null)
2019-04-17 06:45:15 +00:00
panes = 3;
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
if (panelArea.isShowing() && (panelArea.hasFocus() || panelArea.getMousePosition() != null)) {
int caretLine = panelArea.getCaretLineNumber();
int maxViewLine = ClassViewer.getMaxViewLine(panelArea);
int activeViewLine = ClassViewer.getViewLine(panelArea);
2021-04-12 20:19:12 +00:00
int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine :
activeViewLine;
2019-04-17 06:45:15 +00:00
int activeLineDelta = -1;
MethodParser.Method activeMethod = null;
MethodParser activeMethods = viewer.methods.get(paneId);
if (activeMethods != null) {
int activeMethodLine = activeMethods.findActiveMethod(activeLine);
if (activeMethodLine != -1) {
activeLineDelta = activeLine - activeMethodLine;
activeMethod = activeMethods.getMethod(activeMethodLine);
ClassViewer.selectMethod(panelArea, activeMethodLine);
}
}
for (int i = 0; i < panes; i++) {
2021-04-12 20:19:12 +00:00
if (i != paneId) {
2019-04-17 06:45:15 +00:00
int setLine = -1;
RSyntaxTextArea area = null;
2021-04-12 20:19:12 +00:00
switch (i) {
case 0:
area = viewer.t1.panelArea;
break;
case 1:
area = viewer.t2.panelArea;
break;
case 2:
area = viewer.t3.panelArea;
break;
2019-04-17 06:45:15 +00:00
}
if (area != null) {
if (activeMethod != null && activeLineDelta >= 0) {
MethodParser methods = viewer.methods.get(i);
if (methods != null) {
int methodLine = methods.findMethod(activeMethod);
if (methodLine != -1) {
int viewLine = ClassViewer.getViewLine(area);
if (activeLineDelta != viewLine - methodLine) {
setLine = methodLine + activeLineDelta;
}
}
}
2021-04-12 20:19:12 +00:00
} else if (activeLine != ClassViewer.getViewLine(area)) {
2019-04-17 06:45:15 +00:00
setLine = activeLine;
}
if (setLine >= 0) {
ClassViewer.setViewLine(area, setLine);
}
}
}
}
}
}
}
};
2021-04-12 20:19:12 +00:00
class MethodsRenderer extends JLabel implements ListCellRenderer<Object> {
2019-04-17 06:45:15 +00:00
public MethodsRenderer() {
setOpaque(true);
}
2021-04-12 22:31:22 +00:00
@Override
2021-04-12 20:19:12 +00:00
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
2019-04-17 06:45:15 +00:00
MethodParser methods = viewer.methods.get(paneId);
MethodParser.Method method = methods.getMethod((Integer) value);
setText(method.toString());
return this;
}
}
2021-04-12 20:19:12 +00:00
public void synchronizePane() {
2019-04-17 06:45:15 +00:00
JViewport viewport = scrollPane.getViewport();
viewport.addChangeListener(viewportListener);
panelArea.addCaretListener(caretListener);
final MethodParser methods = viewer.methods.get(paneId);
2021-04-12 20:19:12 +00:00
for (int i = 0; i < panelArea.getLineCount(); i++) {
2019-04-17 06:45:15 +00:00
String lineText = ClassViewer.getLineText(panelArea, i);
Matcher regexMatcher = MethodParser.regex.matcher(lineText);
2021-04-12 20:19:12 +00:00
if (regexMatcher.find()) {
2019-04-17 06:45:15 +00:00
String methodName = regexMatcher.group("name");
String methodParams = regexMatcher.group("params");
methods.addMethod(i, methodName, methodParams);
}
}
2021-04-12 20:19:12 +00:00
if (BytecodeViewer.viewer.showClassMethods.isSelected()) {
2019-04-17 06:45:15 +00:00
if (!methods.isEmpty()) {
methodsList = new JComboBox<>();
for (Integer line : methods.getMethodsLines()) {
methodsList.addItem(line);
}
methodsList.setRenderer(new PaneUpdaterThread.MethodsRenderer());
2021-04-12 22:31:22 +00:00
methodsList.addActionListener(e -> {
int line = (int) Objects.requireNonNull(methodsList.getSelectedItem());
RSyntaxTextArea area = null;
switch (paneId) {
case 0:
area = viewer.t1.panelArea;
break;
case 1:
area = viewer.t2.panelArea;
break;
case 2:
area = viewer.t3.panelArea;
break;
2019-04-17 06:45:15 +00:00
}
2021-04-12 22:31:22 +00:00
if (area != null)
ClassViewer.selectMethod(area, line);
2019-04-17 06:45:15 +00:00
});
JPanel panel = new JPanel(new BorderLayout());
panel.add(scrollPane.getColumnHeader().getComponent(0), BorderLayout.NORTH);
panel.add(methodsList, BorderLayout.SOUTH);
methodsList.setBackground(BLANK);
scrollPane.getColumnHeader().removeAll();
scrollPane.getColumnHeader().add(panel);
}
}
2018-01-31 15:41:24 +00:00
}
}