Skip to content

Commit

Permalink
Add methods list, Add synchronize viewing (Panes)
Browse files Browse the repository at this point in the history
Add improvements of viewing
  • Loading branch information
DreamSworK committed May 14, 2017
1 parent bf781c1 commit 6a6984e
Show file tree
Hide file tree
Showing 5 changed files with 426 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/main/java/the/bytecode/club/bytecodeviewer/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public class Settings<T> {
public static final Settings<Integer> FILE_NAVIGATION_PANE_HEIGHT = new Settings<>("fileNavigationPaneHeight", 50);
public static final Settings<Integer> SEARCHING_PANE_WIDTH = new Settings<>("searchingPaneWidth", 200);
public static final Settings<Integer> SEARCHING_PANE_HEIGHT = new Settings<>("searchingPaneHeight", 50);
public static final Settings<Boolean> SYNCHRONIZE_VIEWING = new Settings<>("synchronizeViewing", false);
public static final Settings<Boolean> SHOW_METHODS_LIST = new Settings<>("showMethodsList", false);

private String key;
private T value;
Expand Down
135 changes: 129 additions & 6 deletions src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Resources;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.Methods.*;

import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
Expand Down Expand Up @@ -42,16 +44,18 @@
*
* @author Konloch
* @author WaterWolf
* @author DreamSworK
*/

public class ClassViewer extends Viewer {
private static final long serialVersionUID = -8650495368920680024L;
private final MainViewerGUI gui = BytecodeViewer.viewer;
private List<Thread> decompileThreads = new ArrayList<>();

public void setPanes() {
for (int i = 0; i < BytecodeViewer.viewer.allPanes.size(); i++) {
ButtonGroup group = BytecodeViewer.viewer.allPanes.get(i);
for (Map.Entry<JRadioButtonMenuItem, Decompiler> entry : BytecodeViewer.viewer.allDecompilers.get(group).entrySet()) {
for (int i = 0; i < gui.allPanes.size(); i++) {
ButtonGroup group = gui.allPanes.get(i);
for (Map.Entry<JRadioButtonMenuItem, Decompiler> entry : gui.allDecompilers.get(group).entrySet()) {
if (group.isSelected(entry.getKey().getModel())) {
decompilers.set(i, entry.getValue());
}
Expand All @@ -61,9 +65,9 @@ public void setPanes() {

public boolean isPaneEditable(int pane) {
setPanes();
ButtonGroup buttonGroup = BytecodeViewer.viewer.allPanes.get(pane);
ButtonGroup buttonGroup = gui.allPanes.get(pane);
Decompiler selected = decompilers.get(pane);
if (buttonGroup != null && BytecodeViewer.viewer.editButtons.get(buttonGroup) != null && BytecodeViewer.viewer.editButtons.get(buttonGroup).get(selected)!= null && BytecodeViewer.viewer.editButtons.get(buttonGroup).get(selected).isSelected()) {
if (buttonGroup != null && gui.editButtons.get(buttonGroup) != null && gui.editButtons.get(buttonGroup).get(selected)!= null && gui.editButtons.get(buttonGroup).get(selected).isSelected()) {
return true;
}
return false;
Expand Down Expand Up @@ -126,10 +130,129 @@ public void hierarchyChanged(HierarchyEvent e) {
public List<JPanel> searches = Arrays.asList(new JPanel(new BorderLayout()), new JPanel(new BorderLayout()), new JPanel(new BorderLayout()));
public List<JCheckBox> exacts = Arrays.asList(new JCheckBox("Exact"), new JCheckBox("Exact"), new JCheckBox("Exact"));
public List<JTextField> fields = Arrays.asList(new JTextField(), new JTextField(), new JTextField());
public List<Methods> methods = Arrays.asList(new Methods(), new Methods(), new Methods());
public List<Integer> activeLines = Arrays.asList(0, 0, 0);
public List<RSyntaxTextArea> javas = Arrays.asList(null, null, null);
public List<RSyntaxTextArea> smalis = Arrays.asList(null, null, null);
public List<RSyntaxTextArea> krakataus = Arrays.asList(null, null, null);

public static void selectMethod(RSyntaxTextArea area, int methodLine) {
if (methodLine != area.getCaretLineNumber()) {
setCaretLine(area, methodLine);
setViewLine(area, methodLine);
}
}

public static void selectMethod(ClassViewer classViewer, int paneId, Method method) {
RSyntaxTextArea area = classViewer.javas.get(paneId);
if (area != null) {
Methods methods = classViewer.methods.get(paneId);
if (methods != null) {
int methodLine = methods.findMethod(method);
if (methodLine != -1) {
selectMethod(area, methodLine);
}
}
}
}

public static String getLineText(RSyntaxTextArea area, int line) {
try {
if (line < area.getLineCount()) {
int start = area.getLineStartOffset(line);
int end = area.getLineEndOffset(line);
return area.getText(start, end - start).trim();
}
} catch (BadLocationException ignored) {}
return "";
}

public static int getMaxViewLine(RSyntaxTextArea area) {
Container parent = area.getParent();
if (parent instanceof JViewport) {
JViewport viewport = (JViewport) parent;
int y = viewport.getViewSize().height - viewport.getExtentSize().height;
int lineHeight = area.getLineHeight();
return y >= lineHeight ? y / lineHeight : 0;
}
return 0;
}

public static int getViewLine(RSyntaxTextArea area) {
Container parent = area.getParent();
if (parent instanceof JViewport) {
JViewport viewport = (JViewport) parent;
Point point = viewport.getViewPosition();
int lineHeight = area.getLineHeight();
return point.y >= lineHeight ? point.y / lineHeight : 0;
}
return 0;
}

public static void setViewLine(RSyntaxTextArea area, int line) {
Container parent = area.getParent();
if (parent instanceof JViewport) {
JViewport viewport = (JViewport) parent;
int maxLine = ClassViewer.getMaxViewLine(area);
line = line < maxLine ? line : maxLine;
viewport.setViewPosition(new Point(0, line * area.getLineHeight()));
}
}

public static void setCaretLine(RSyntaxTextArea area, int line) {
try {
area.setCaretPosition(area.getLineStartOffset(line));
} catch (BadLocationException ignored) {}
}

static class SynchronizeActionListener implements ActionListener {
private ClassViewer classViewer;
private int activePaneId;

public SynchronizeActionListener(ClassViewer classViewer, int paneId) {
this.classViewer = classViewer;
this.activePaneId = paneId;
}

public void actionPerformed(ActionEvent e) {
int activePanes = 0;
for (int i = 0; i < classViewer.javas.size(); i++) {
if (classViewer.javas.get(i) != null)
activePanes++;
}
if (activePanes > 1) {
final RSyntaxTextArea activeArea = classViewer.javas.get(activePaneId);
if (activeArea != null) {
Methods activeMethods = classViewer.methods.get(activePaneId);
if (activeMethods != null) {
int activeLine = classViewer.activeLines.get(activePaneId);
int activeMethodLine = activeMethods.findActiveMethod(activeLine);
if (activeMethodLine != -1) {
selectMethod(activeArea, activeMethodLine);
Method activeMethod = activeMethods.getMethod(activeMethodLine);
if (activeMethod != null) {
for (int i = 0; i < classViewer.javas.size(); i++) {
if (i != activePaneId) {
RSyntaxTextArea area = classViewer.javas.get(i);
if (area != null) {
Methods methods = classViewer.methods.get(i);
if (methods != null) {
int methodLine = methods.findMethod(activeMethod);
if (methodLine != -1) {
selectMethod(area, methodLine);
}
}
}
}
}
}
}
}
}
}
}
}

/**
* This was really interesting to write.
*
Expand Down Expand Up @@ -330,7 +453,7 @@ public void keyTyped(KeyEvent arg0) {
hex.setMaximumSize(new Dimension(0, Integer.MAX_VALUE));
hex.setSize(0, Integer.MAX_VALUE);

BytecodeViewer.viewer.setIcon(true);
gui.setIcon(true);
startPaneUpdater(null);
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ public void componentResized(ComponentEvent e) {
public final JMenuItem mntmNewMenuItem_12 = new JMenuItem("Decompile & Save Opened Class..");
public WorkPane workPane = new WorkPane(this);
public final JCheckBoxMenuItem refreshOnChange = new JCheckBoxMenuItem("Refresh On View Change");
public final JCheckBoxMenuItem synchronizeViewing = new JCheckBoxMenuItem("Synchronize Viewing");
public final JCheckBoxMenuItem showMethodsList = new JCheckBoxMenuItem("Show Methods List");
public AboutWindow aboutWindow = new AboutWindow();
public final JMenuItem mntmSaveAsApk = new JMenuItem("Save As DEX..");
public final JMenuItem mntmCodeSequenceDiagram = new JMenuItem("Code Sequence Diagram");
Expand Down Expand Up @@ -952,6 +954,8 @@ public void actionPerformed(ActionEvent arg0) {
addSettingsMenuItem(settingsMenu, compileOnSave, Settings.COMPILE_ON_SAVE);
addSettingsMenuItem(settingsMenu, compileOnRefresh, Settings.COMPILE_ON_REFRESH);
addSettingsMenuItem(settingsMenu, refreshOnChange, Settings.REFRESH_ON_CHANGE);
addSettingsMenuItem(settingsMenu, synchronizeViewing, Settings.SYNCHRONIZE_VIEWING);
addSettingsMenuItem(settingsMenu, showMethodsList, Settings.SHOW_METHODS_LIST);

settingsMenu.add(new JSeparator());

Expand Down
138 changes: 138 additions & 0 deletions src/main/java/the/bytecode/club/bytecodeviewer/gui/Methods.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package the.bytecode.club.bytecodeviewer.gui;

import java.util.*;
import java.util.regex.Pattern;

/**
* Methods parser.
*
* @author DreamSworK
*
*/
public class Methods {

public static class Method {
public String name;
public List<String> params;

public Method(String name, List<String> params) {
this.name = name;
this.params = params;
}

public String toString() {
String params = this.params.toString();
return this.name + "(" + params.substring(1, params.length() - 1) + ")";
}
}

public static final Pattern regex = Pattern.compile("\\s*(?:static|public|private|protected|final|abstract)[\\w\\s.<>\\[\\]]*\\s+(?<name>[\\w]+)\\s*\\((?<params>[\\w\\s,.<>\\[\\]$?]*)\\)");

private TreeMap<Integer, Method> methods = new TreeMap<>();

private static String removeBrackets(String string) {
if (string.indexOf('<') != -1 && string.indexOf('>') != -1) {
return removeBrackets(string.replaceAll("<[^<>]*>", ""));
}
return string;
}

public void addMethod(int line, String name, String params) {
String[] args = {};
if (!params.isEmpty()) {
params = removeBrackets(params);
args = params.split(",");
for (int i = 0; i < args.length; i++) {
args[i] = args[i].trim();
if (args[i].indexOf(' ') != -1) {
String[] strings = args[i].split(" ");
args[i] = strings[strings.length - 2];
}
int dot = args[i].lastIndexOf('.');
if (dot != -1) {
args[i] = args[i].substring(dot + 1);
}
int dollar = args[i].lastIndexOf('$');
if (dollar != -1) {
args[i] = args[i].substring(dollar + 1);
}
}
}
Method method = new Method(name, Arrays.asList(args));
methods.put(line, method);
}

public boolean isEmpty() {
return methods.isEmpty();
}

public Method getMethod(int line) {
return methods.get(line);
}

public Integer[] getMethodsLines() {
Integer[] lines = new Integer[methods.size()];
return methods.keySet().toArray(lines);
}

public String getMethodName(int line) {
Method method = methods.get(line);
if (method != null) {
if (!method.name.isEmpty())
return method.name;
}
return "";
}

public List<String> getMethodParams(int line) {
Method method = methods.get(line);
if (method != null) {
if (!method.params.isEmpty())
return method.params;
}
return null;
}

public int findMethod(Method method) {
return findMethod(method.name, method.params);
}

public int findMethod(String name, List<String> params) {
for (Map.Entry<Integer, Method> entry: methods.entrySet()) {
if (name.equals(entry.getValue().name) && params.size() == entry.getValue().params.size()) {
if (params.equals(entry.getValue().params)) {
return entry.getKey();
}
}
}
return -1;
}

public int findActiveMethod(int line) {
if (!methods.isEmpty()) {
Map.Entry<Integer, Method> low = methods.floorEntry(line);
if (low != null) {
return low.getKey();
}
}
return -1;
}

public int findNearestMethod(int line) {
if (!methods.isEmpty()) {
if (methods.size() == 1) {
return methods.firstKey();
} else {
Map.Entry<Integer, Method> low = methods.floorEntry(line);
Map.Entry<Integer, Method> high = methods.ceilingEntry(line);
if (low != null && high != null) {
return Math.abs(line - low.getKey()) < Math.abs(line - high.getKey()) ? low.getKey() : high.getKey();
}
else if (low != null || high != null) {
return low != null ? low.getKey() : high.getKey();
}
}
}
return -1;
}
}
Loading

0 comments on commit 6a6984e

Please sign in to comment.