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

280 lines
12 KiB
Java
Raw Normal View History

package the.bytecode.club.bytecodeviewer.gui.util;
2021-04-12 20:19:12 +00:00
import java.awt.BorderLayout;
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.*;
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.gui.components.MethodsRenderer;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
2021-04-12 20:19:12 +00:00
import the.bytecode.club.bytecodeviewer.util.MethodParser;
2019-04-17 06:45:15 +00:00
import static the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane.BLANK_COLOR;
2019-04-17 06:45:15 +00:00
2021-06-26 03:33:06 +00:00
/***************************************************************************
* 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/>. *
***************************************************************************/
/**
* 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
*/
public abstract class PaneUpdaterThread implements Runnable
{
2019-04-17 06:45:15 +00:00
public ClassViewer viewer;
public SearchableRSyntaxTextArea updateUpdaterTextArea;
2019-04-17 06:45:15 +00:00
public JComboBox<Integer> methodsList;
private Thread thread;
public int paneIndex;
public int decompilerViewIndex;
public PaneUpdaterThread(int paneIndex, int decompilerViewIndex)
{
this.paneIndex = paneIndex;
this.decompilerViewIndex = decompilerViewIndex;
}
2018-01-31 15:41:24 +00:00
public abstract void doShit();
public void startNewThread()
{
thread = new Thread(this);
thread.start();
}
2018-01-31 15:41:24 +00:00
@Override
public void run()
{
if(decompilerViewIndex == 0)
return;
2018-01-31 15:41:24 +00:00
doShit();
2021-06-29 00:06:50 +00:00
2021-06-29 00:51:25 +00:00
//this still freezes the swing UI
2019-04-17 06:45:15 +00:00
synchronizePane();
2021-06-29 00:54:39 +00:00
//attach CTRL + Mouse Wheel Zoom
SwingUtilities.invokeLater(()->
attachCtrlMouseWheelZoom(updateUpdaterTextArea.getScrollPane(), updateUpdaterTextArea));
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
}
public final CaretListener caretListener = new CaretListener()
{
2019-04-17 06:45:15 +00:00
@Override
public void caretUpdate(CaretEvent e)
{
MethodParser methods = viewer.methods.get(paneIndex);
if (methods != null)
{
int methodLine = methods.findActiveMethod(updateUpdaterTextArea.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;
if (viewer.resourceViewPanel3.panel != 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 != paneIndex) {
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;
if (viewer.resourceViewPanel3.panel != null)
2019-04-17 06:45:15 +00:00
panes = 3;
if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
if (updateUpdaterTextArea.isShowing() && (updateUpdaterTextArea.hasFocus() || updateUpdaterTextArea.getMousePosition() != null)) {
int caretLine = updateUpdaterTextArea.getCaretLineNumber();
int maxViewLine = ClassViewer.getMaxViewLine(updateUpdaterTextArea);
int activeViewLine = ClassViewer.getViewLine(updateUpdaterTextArea);
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(paneIndex);
2019-04-17 06:45:15 +00:00
if (activeMethods != null) {
int activeMethodLine = activeMethods.findActiveMethod(activeLine);
if (activeMethodLine != -1) {
activeLineDelta = activeLine - activeMethodLine;
activeMethod = activeMethods.getMethod(activeMethodLine);
ClassViewer.selectMethod(updateUpdaterTextArea, activeMethodLine);
2019-04-17 06:45:15 +00:00
}
}
for (int i = 0; i < panes; i++) {
if (i != paneIndex) {
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.resourceViewPanel1.updateThread.updateUpdaterTextArea;
2021-04-12 20:19:12 +00:00
break;
case 1:
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea;
2021-04-12 20:19:12 +00:00
break;
case 2:
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea;
2021-04-12 20:19:12 +00:00
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);
}
}
}
}
}
}
}
};
public void synchronizePane()
{
if(decompilerViewIndex == 5 || decompilerViewIndex < 0)
return;
JViewport viewport = updateUpdaterTextArea.getScrollPane().getViewport();
SwingUtilities.invokeLater(()->
{
viewport.addChangeListener(viewportListener);
updateUpdaterTextArea.addCaretListener(caretListener);
});
final MethodParser methods = viewer.methods.get(paneIndex);
for (int i = 0; i < updateUpdaterTextArea.getLineCount(); i++)
{
String lineText = updateUpdaterTextArea.getLineText(i);
2019-04-17 06:45:15 +00:00
Matcher regexMatcher = MethodParser.regex.matcher(lineText);
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);
}
}
//TODO fix this
if (BytecodeViewer.viewer.showClassMethods.isSelected())
{
if (!methods.isEmpty())
{
2019-04-17 06:45:15 +00:00
methodsList = new JComboBox<>();
for (Integer line : methods.getMethodsLines())
2019-04-17 06:45:15 +00:00
methodsList.addItem(line);
methodsList.setRenderer(new MethodsRenderer(this));
methodsList.addActionListener(e ->
{
2021-04-12 22:31:22 +00:00
int line = (int) Objects.requireNonNull(methodsList.getSelectedItem());
RSyntaxTextArea area = null;
switch (paneIndex)
{
case 0:
area = viewer.resourceViewPanel1.updateThread.updateUpdaterTextArea;
break;
case 1:
area = viewer.resourceViewPanel2.updateThread.updateUpdaterTextArea;
break;
case 2:
area = viewer.resourceViewPanel3.updateThread.updateUpdaterTextArea;
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(updateUpdaterTextArea.getScrollPane().getColumnHeader().getComponent(0), BorderLayout.NORTH);
2019-04-17 06:45:15 +00:00
panel.add(methodsList, BorderLayout.SOUTH);
methodsList.setBackground(BLANK_COLOR);
2021-06-29 00:54:39 +00:00
SwingUtilities.invokeLater(()->
{
updateUpdaterTextArea.getScrollPane().getColumnHeader().removeAll();
updateUpdaterTextArea.getScrollPane().getColumnHeader().add(panel);
});
2019-04-17 06:45:15 +00:00
}
}
2018-01-31 15:41:24 +00:00
}
}