Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Cynthia Foxwell 2023-08-03 21:58:09 -06:00
commit 95d3969e2e
18 changed files with 1032 additions and 866 deletions

View File

@ -23,6 +23,7 @@ jobs:
with: with:
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
distribution: 'temurin' distribution: 'temurin'
cache: maven
- name: Build with Maven - name: Build with Maven
run: mvn -B package --file pom.xml run: mvn -B package --file pom.xml
- name: Extract Maven project version - name: Extract Maven project version

26
LICENSE
View File

@ -646,29 +646,3 @@ the "copyright" line and a pointer to where the full notice is found.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Bytecode Viewer(BCV) Copyright (C) 2014 Kalen "Konloch" Kinloch - http://bytecodeviewer.com - http://the.bytecode.club
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

69
pom.xml
View File

@ -13,41 +13,42 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Dependency versions --> <!-- Dependency versions -->
<annotations.version>23.0.0</annotations.version> <annotations.version>24.0.1</annotations.version>
<antlr4.version>4.9.3</antlr4.version> <antlr4.version>4.9.3</antlr4.version>
<apktool.version>2.6.1</apktool.version> <apktool.version>2.8.0</apktool.version>
<asm.version>9.4</asm.version> <asm.version>9.5</asm.version>
<bined.version>0.2.0</bined.version> <bined.version>0.2.0</bined.version>
<byteanalysis.version>1.0bcv</byteanalysis.version> <byteanalysis.version>1.0bcv</byteanalysis.version>
<cfr.version>0.152</cfr.version> <cfr.version>0.152</cfr.version>
<cloning.version>1.9.12</cloning.version> <cloning.version>1.9.12</cloning.version>
<commons-cli.version>1.5.0</commons-cli.version> <commons-cli.version>1.5.0</commons-cli.version>
<commons-codec.version>1.15</commons-codec.version> <commons-codec.version>1.16.0</commons-codec.version>
<commons-compiler.version>3.1.8</commons-compiler.version> <commons-compiler.version>3.1.10</commons-compiler.version>
<commons-compress.version>1.21</commons-compress.version> <commons-compress.version>1.23.0</commons-compress.version>
<commons-io.version>2.11.0</commons-io.version> <commons-io.version>2.13.0</commons-io.version>
<commons-lang3.version>3.12.0</commons-lang3.version> <commons-lang3.version>3.12.0</commons-lang3.version>
<commons-text.version>1.10.0</commons-text.version> <commons-text.version>1.10.0</commons-text.version>
<darklaf.version>3.0.2</darklaf.version> <darklaf.version>3.0.2</darklaf.version>
<darklaf-extensions-rsta.version>0.4.1</darklaf-extensions-rsta.version> <darklaf-extensions-rsta.version>0.4.1</darklaf-extensions-rsta.version>
<decompiler-fernflower.version>6.0.0.Final</decompiler-fernflower.version> <decompiler-fernflower.version>6.2.5.Final</decompiler-fernflower.version>
<dex2jar.version>v56</dex2jar.version> <dex2jar.version>v64</dex2jar.version>
<fernflower.version>1.9.2</fernflower.version> <fernflower.version>1.9.2</fernflower.version>
<gson.version>2.9.1</gson.version> <gson.version>2.10.1</gson.version>
<guava.version>31.1-jre</guava.version> <guava.version>32.1.1-jre</guava.version>
<httprequest.version>2.2.0</httprequest.version>
<imgscalr-lib.version>4.2</imgscalr-lib.version> <imgscalr-lib.version>4.2</imgscalr-lib.version>
<jadx.version>1.4.4</jadx.version> <jadx.version>1.4.7</jadx.version>
<jd-gui.version>1.6.6bcv</jd-gui.version> <jd-gui.version>1.6.6bcv</jd-gui.version>
<jgraphx.version>3.4.1.3</jgraphx.version> <jgraphx.version>3.4.1.3</jgraphx.version>
<js.version>21.2.0</js.version> <js.version>21.2.0</js.version>
<objenesis.version>3.3</objenesis.version> <objenesis.version>3.3</objenesis.version>
<paged-data.version>0.2.0</paged-data.version> <paged-data.version>0.2.0</paged-data.version>
<procyon.version>0.6.0</procyon.version> <procyon.version>0.6.0</procyon.version>
<rsyntaxtextarea.version>3.3.0</rsyntaxtextarea.version> <rsyntaxtextarea.version>3.3.3</rsyntaxtextarea.version>
<semantic-version.version>2.1.1</semantic-version.version> <semantic-version.version>2.1.1</semantic-version.version>
<slf4j.version>2.0.3</slf4j.version> <slf4j.version>2.0.7</slf4j.version>
<smali.version>2.5.2</smali.version> <smali.version>3.0.3</smali.version>
<snakeyaml.version>1.33</snakeyaml.version> <safeyaml.version>1.34.1</safeyaml.version>
<treelayout.version>1.0.3</treelayout.version> <treelayout.version>1.0.3</treelayout.version>
<webp-imageio.version>0.2.2</webp-imageio.version> <webp-imageio.version>0.2.2</webp-imageio.version>
<xpp3.version>1.1.4c</xpp3.version> <xpp3.version>1.1.4c</xpp3.version>
@ -73,6 +74,11 @@
</repositories> </repositories>
<dependencies> <dependencies>
<dependency>
<groupId>com.konloch</groupId>
<artifactId>HTTPRequest</artifactId>
<version>${httprequest.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.jetbrains</groupId> <groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId> <artifactId>annotations</artifactId>
@ -271,19 +277,19 @@
<version>${slf4j.version}</version> <version>${slf4j.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.smali</groupId> <groupId>com.android.tools.smali</groupId>
<artifactId>smali</artifactId> <artifactId>smali</artifactId>
<version>${smali.version}</version> <version>${smali.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.smali</groupId> <groupId>com.android.tools.smali</groupId>
<artifactId>baksmali</artifactId> <artifactId>smali-baksmali</artifactId>
<version>${smali.version}</version> <version>${smali.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.yaml</groupId> <groupId>com.konloch</groupId>
<artifactId>snakeyaml</artifactId> <artifactId>safeyaml</artifactId>
<version>${snakeyaml.version}</version> <version>${safeyaml.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>xpp3</groupId> <groupId>xpp3</groupId>
@ -314,11 +320,23 @@
<groupId>io.github.skylot</groupId> <groupId>io.github.skylot</groupId>
<artifactId>jadx-dex-input</artifactId> <artifactId>jadx-dex-input</artifactId>
<version>${jadx.version}</version> <version>${jadx.version}</version>
<exclusions>
<exclusion>
<groupId>org.smali</groupId>
<artifactId>baksmali</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.github.skylot</groupId> <groupId>io.github.skylot</groupId>
<artifactId>jadx-smali-input</artifactId> <artifactId>jadx-smali-input</artifactId>
<version>${jadx.version}</version> <version>${jadx.version}</version>
<exclusions>
<exclusion>
<groupId>org.smali</groupId>
<artifactId>smali</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.ThexXTURBOXx</groupId> <groupId>com.github.ThexXTURBOXx</groupId>
@ -380,7 +398,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <version>3.11.0</version>
<configuration> <configuration>
<source>${maven.compiler.source}</source> <source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target> <target>${maven.compiler.target}</target>
@ -390,7 +408,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.0</version> <version>3.5.0</version>
<configuration> <configuration>
<source>${maven.compiler.source}</source> <source>${maven.compiler.source}</source>
</configuration> </configuration>
@ -398,7 +416,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version> <version>3.4.1</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@ -419,6 +437,7 @@
<exclude>META-INF/*LICENSE*</exclude> <exclude>META-INF/*LICENSE*</exclude>
<exclude>META-INF/*NOTICE*</exclude> <exclude>META-INF/*NOTICE*</exclude>
<exclude>META-INF/MANIFEST.MF</exclude> <exclude>META-INF/MANIFEST.MF</exclude>
<exclude>LICENSE</exclude>
</excludes> </excludes>
</filter> </filter>
<!-- Ignore all ASM-related files from d2j-external but MCTLE fix --> <!-- Ignore all ASM-related files from d2j-external but MCTLE fix -->

View File

@ -1,276 +0,0 @@
package me.konloch.kontainer.io;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
/**
* A wrapper for Java SE classes to write/read an HTTP Request
*
* @author Konloch
*/
public class HTTPRequest {
public URL url;
private int timeout = 30000;
private String cookie;
private String referer;
private String postData;
private String useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0";
private Proxy proxy;
private boolean setFollowRedirects = true;
private BufferedReader reader;
private DataOutputStream writer;
private HttpURLConnection connection;
private Set<Entry<String, List<String>>> lastConnectionHeaders;
private int statusCode;
/**
* Creates a new HTTPRequest object
*
* @param url
*/
public HTTPRequest(URL url) {
this.url = url;
}
/**
* Sets a referer to send to the web server
*/
public void setReferer(String referer) {
this.referer = referer;
}
/**
* Set a cookie string to send to the web server
*/
public void setCookie(String cookie) {
this.cookie = cookie;
}
/**
* Sets post data to send to the web server
*/
public void setPostData(String postData) {
this.postData = postData;
}
/**
* Sets a custom useragent, default 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0'
*/
public void setUseragent(String useragent) {
this.useragent = useragent;
}
/**
* Sets the seconds till timeout, default 30,000 milliseconds
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
/**
* Sets a proxy to connect through
*/
public void setProxy(Proxy proxy) {
this.proxy = proxy;
}
/**
* Used to get the headers the webserver sent on our last connection
*/
public Set<Entry<String, List<String>>> getLastConnectionHeaders() {
return lastConnectionHeaders;
}
public int getStatusCode()
{
return statusCode;
}
/**
* By default, follow redirects are enabled
*/
public void setFollowRedirects(boolean setFollowRedirects) {
this.setFollowRedirects = setFollowRedirects;
}
/**
* Used to set up the connection to read the content.
*/
private void setup() throws Exception {
if (proxy != null)
connection = (HttpURLConnection) url.openConnection(proxy);
else
connection = (HttpURLConnection) url.openConnection();
if (cookie != null)
connection.setRequestProperty("Cookie", cookie);
if (referer != null)
connection.addRequestProperty("Referer", referer);
connection.setRequestProperty("User-Agent", useragent);
connection.setReadTimeout(timeout);
connection.setConnectTimeout(timeout);
connection.setUseCaches(false);
HttpURLConnection.setFollowRedirects(setFollowRedirects);
if (postData != null) {
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
writer = new DataOutputStream(connection.getOutputStream());
writer.writeBytes(postData);
writer.flush();
}
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
/**
* Reads the entire page and returns a string array
*
* @return
* @throws Exception
*/
public String[] read() throws Exception {
List<String> st;
try {
setup();
st = new ArrayList<>();
String s;
while ((s = reader.readLine()) != null)
st.add(s);
lastConnectionHeaders = connection.getHeaderFields().entrySet();
statusCode = connection.getResponseCode();
} catch (Exception e) {
cleanup();
throw e;
} finally {
cleanup();
}
return st.toArray(new String[0]);
}
/**
* Reads as many lines as expected unless it reaches the end.
*
* @param linesToRead
* @return
* @throws Exception
*/
public String[] read(int linesToRead) throws Exception {
List<String> st;
try {
setup();
st = new ArrayList<>();
for (int i = 0; i < linesToRead; i++) {
String s = reader.readLine();
if (s != null)
st.add(s);
}
lastConnectionHeaders = connection.getHeaderFields().entrySet();
statusCode = connection.getResponseCode();
} catch (Exception e) {
cleanup();
throw e;
} finally {
cleanup();
}
return st.toArray(new String[0]);
}
/**
* Only reads the first line
*
* @return
* @throws Exception
*/
public String readSingle() throws Exception {
String s;
try {
setup();
s = reader.readLine();
lastConnectionHeaders = connection.getHeaderFields().entrySet();
statusCode = connection.getResponseCode();
} catch (Exception e) {
cleanup();
throw e;
} finally {
cleanup();
}
return s;
}
/**
* Reads until it reaches the expected line then it returns it.
*
* @param linesToRead
* @return
* @throws Exception
*/
public String readSingle(int linesToRead) throws Exception {
String s;
try {
setup();
for (int i = 0; i < linesToRead - 1; i++)
reader.readLine();
s = reader.readLine();
lastConnectionHeaders = connection.getHeaderFields().entrySet();
statusCode = connection.getResponseCode();
} catch (Exception e) {
cleanup();
throw e;
} finally {
cleanup();
}
return s;
}
/**
* Used to clean up the connection, closes the connections and nulls the objects
*/
private void cleanup() {
try {
reader.close();
} catch (Exception ignored) {
}
try {
writer.close();
} catch (Exception ignored) {
}
try {
connection.disconnect();
} catch (Exception ignored) {
}
reader = null;
writer = null;
connection = null;
}
}

View File

@ -129,8 +129,6 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
public class BytecodeViewer public class BytecodeViewer
{ {
//TODO fix this for tab dragging & better tab controls
public static boolean EXPERIMENTAL_TAB_CODE = false;
//the launch args called on BCV //the launch args called on BCV
public static String[] launchArgs; public static String[] launchArgs;
@ -198,7 +196,7 @@ public class BytecodeViewer
//setup swing components //setup swing components
viewer = new MainViewerGUI(); viewer = new MainViewerGUI();
SwingUtilities.updateComponentTreeUI(viewer); //SwingUtilities.updateComponentTreeUI(viewer);
//load settings and set swing components state //load settings and set swing components state
SettingsSerializer.loadSettings(); SettingsSerializer.loadSettings();

View File

@ -9,7 +9,7 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import me.konloch.kontainer.io.HTTPRequest; import com.konloch.httprequest.HTTPRequest;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
@ -277,7 +277,6 @@ public class Boot {
public static void populateUrlList() throws Exception { public static void populateUrlList() throws Exception {
HTTPRequest req = new HTTPRequest(new URL("https://github.com/Konloch/bytecode-viewer/tree/master/libs")); HTTPRequest req = new HTTPRequest(new URL("https://github.com/Konloch/bytecode-viewer/tree/master/libs"));
req.setTimeout(30000);
for (String s : req.read()) for (String s : req.read())
if (s.contains("href=\"/Konloch/bytecode-viewer/blob/master/libs/")) { if (s.contains("href=\"/Konloch/bytecode-viewer/blob/master/libs/")) {
urlList.add("https://github.com" + s.split("href=")[1].split("\"")[1]); urlList.add("https://github.com" + s.split("href=")[1].split("\"")[1]);

View File

@ -10,7 +10,7 @@ import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import me.konloch.kontainer.io.HTTPRequest; import com.konloch.httprequest.HTTPRequest;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.api.BCV; import the.bytecode.club.bytecodeviewer.api.BCV;
@ -257,7 +257,7 @@ public class UpdateCheck implements Runnable
{ {
HTTPRequest request = new HTTPRequest(new URL(url)); HTTPRequest request = new HTTPRequest(new URL(url));
request.readSingle(); request.readSingle();
return request.getStatusCode() == 200; return request.getLastStatusCode() == 200;
} }
private static void download(String url, File saveTo, Runnable onFinish) throws Exception private static void download(String url, File saveTo, Runnable onFinish) throws Exception

View File

@ -118,7 +118,12 @@ public class FernFlowerDecompiler extends InternalDecompiler
tempClass.delete(); tempClass.delete();
final File outputJava = new File(start + ".java"); String javaDir = start;
if (BytecodeViewer.viewer.ren.isSelected()) {
javaDir = tempDirectory + "class_0";
}
final File outputJava = new File(javaDir + ".java");
if (outputJava.exists()) { if (outputJava.exists()) {
String s; String s;
try { try {

View File

@ -367,8 +367,11 @@ public class MainViewerGUI extends JFrame
searchBoxPane.setMinimumSize(new Dimension(200, 50)); searchBoxPane.setMinimumSize(new Dimension(200, 50));
searchBoxPane.setMaximumSize(new Dimension(200, 2147483647)); searchBoxPane.setMaximumSize(new Dimension(200, 2147483647));
workPane.setPreferredSize(new Dimension(1500, 1000));
splitPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, resourcePane, searchBoxPane); splitPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, resourcePane, searchBoxPane);
splitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane1, workPane); splitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane1, workPane);
getContentPane().add(splitPane2); getContentPane().add(splitPane2);
splitPane2.setResizeWeight(0.05); splitPane2.setResizeWeight(0.05);
splitPane1.setResizeWeight(0.5); splitPane1.setResizeWeight(0.5);
@ -376,6 +379,7 @@ public class MainViewerGUI extends JFrame
uiComponents.add(resourcePane); uiComponents.add(resourcePane);
uiComponents.add(searchBoxPane); uiComponents.add(searchBoxPane);
uiComponents.add(workPane); uiComponents.add(workPane);
// uiComponents.add(hierarchy);
viewPane1.setDefault(); viewPane1.setDefault();
viewPane2.setDefault(); viewPane2.setDefault();

View File

@ -5,6 +5,7 @@ import java.awt.Color;
import java.awt.Font; import java.awt.Font;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener; import java.awt.event.MouseWheelListener;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
@ -13,6 +14,7 @@ import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.RTextScrollPane;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
@ -50,9 +52,9 @@ import the.bytecode.club.bytecodeviewer.util.JTextAreaUtils;
* @author Konloch * @author Konloch
* @since 6/25/2021 * @since 6/25/2021
*/ */
public class SearchableRSyntaxTextArea extends RSyntaxTextArea public class SearchableRSyntaxTextArea extends RSyntaxTextArea {
{
private final RTextScrollPane scrollPane = new RTextScrollPane(this); private RTextScrollPane scrollPane = new RTextScrollPane(this);
private final JPanel searchPanel = new JPanel(new BorderLayout()); private final JPanel searchPanel = new JPanel(new BorderLayout());
private final JTextField searchInput = new JTextField(); private final JTextField searchInput = new JTextField();
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE); private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
@ -63,18 +65,14 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
private final Color blackScrollForeground = new Color(0x575859); private final Color blackScrollForeground = new Color(0x575859);
private Runnable onCtrlS; private Runnable onCtrlS;
public SearchableRSyntaxTextArea() public SearchableRSyntaxTextArea() {
{ if (Configuration.lafTheme == LAFTheme.HIGH_CONTRAST_DARK) {
if(Configuration.lafTheme == LAFTheme.HIGH_CONTRAST_DARK)
{
//this fixes the white border on the jScrollBar panes //this fixes the white border on the jScrollBar panes
scrollPane.getHorizontalScrollBar().setBackground(blackScrollBackground); scrollPane.getHorizontalScrollBar().setBackground(blackScrollBackground);
scrollPane.getHorizontalScrollBar().setForeground(blackScrollForeground); scrollPane.getHorizontalScrollBar().setForeground(blackScrollForeground);
scrollPane.getVerticalScrollBar().setBackground(blackScrollBackground); scrollPane.getVerticalScrollBar().setBackground(blackScrollBackground);
scrollPane.getVerticalScrollBar().setForeground(blackScrollForeground); scrollPane.getVerticalScrollBar().setForeground(blackScrollForeground);
} } else if (Configuration.lafTheme.isDark()) {
else if(Configuration.lafTheme.isDark())
{
//this fixes the white border on the jScrollBar panes //this fixes the white border on the jScrollBar panes
scrollPane.getHorizontalScrollBar().setBackground(darkScrollBackground); scrollPane.getHorizontalScrollBar().setBackground(darkScrollBackground);
scrollPane.getHorizontalScrollBar().setForeground(darkScrollForeground); scrollPane.getHorizontalScrollBar().setForeground(darkScrollForeground);
@ -111,8 +109,7 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
searchInput.requestFocus(); searchInput.requestFocus();
if (onCtrlS != null && (keyEvent.getKeyCode() == KeyEvent.VK_S) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) if (onCtrlS != null && (keyEvent.getKeyCode() == KeyEvent.VK_S) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) {
{
onCtrlS.run(); onCtrlS.run();
return; return;
} }
@ -125,7 +122,7 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
//set number-bar font //set number-bar font
setFont(newFont); setFont(newFont);
SwingUtilities.invokeLater(()-> { SwingUtilities.invokeLater(() -> {
//attach CTRL + Mouse Wheel Zoom //attach CTRL + Mouse Wheel Zoom
attachCtrlMouseWheelZoom(); attachCtrlMouseWheelZoom();
@ -135,49 +132,44 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
} }
public void search(String search, boolean forwardSearchDirection, boolean caseSensitiveSearch) public void search(String search, boolean forwardSearchDirection, boolean caseSensitiveSearch) {
{
JTextAreaUtils.search(this, search, forwardSearchDirection, caseSensitiveSearch); JTextAreaUtils.search(this, search, forwardSearchDirection, caseSensitiveSearch);
} }
public void highlight(String pattern, boolean caseSensitiveSearch) public void highlight(String pattern, boolean caseSensitiveSearch) {
{
JTextAreaUtils.highlight(this, pattern, caseSensitiveSearch); JTextAreaUtils.highlight(this, pattern, caseSensitiveSearch);
} }
public void attachCtrlMouseWheelZoom() public void attachCtrlMouseWheelZoom() {
{ scrollPane.addMouseWheelListener(e -> {
//get the existing scroll event if (getText().isEmpty()) return;
MouseWheelListener ogListener = scrollPane.getMouseWheelListeners().length > 0 ? if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
scrollPane.getMouseWheelListeners()[0] : null;
//remove the existing event
if(ogListener != null)
scrollPane.removeMouseWheelListener(ogListener);
//add a new event
scrollPane.addMouseWheelListener(e ->
{
if (getText().isEmpty())
return;
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
{
Font font = getFont(); Font font = getFont();
int size = font.getSize(); int size = font.getSize();
if (e.getWheelRotation() > 0)
if (e.getWheelRotation() > 0) //Up
setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2)); setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));
else //Down else
setFont(new Font(font.getName(), font.getStyle(), ++size)); setFont(new Font(font.getName(), font.getStyle(), ++size));
e.consume(); e.consume();
} }
else if(ogListener != null)
{
ogListener.mouseWheelMoved(e);
}
}); });
scrollPane = new RTextScrollPane() {
@Override
protected void processMouseWheelEvent(MouseWheelEvent event) {
if (!isWheelScrollingEnabled()) {
if (getParent() != null) {
getParent().dispatchEvent(SwingUtilities.convertMouseEvent(this, event, getParent()));
return;
}
}
super.processMouseWheelEvent(event);
}
};
scrollPane.setWheelScrollingEnabled(false);
} }
public String getLineText(int line) { public String getLineText(int line) {
@ -187,42 +179,36 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
int end = getLineEndOffset(line); int end = getLineEndOffset(line);
return getText(start, end - start).trim(); return getText(start, end - start).trim();
} }
} catch (BadLocationException ignored) { } } catch (BadLocationException ignored) {
}
return ""; return "";
} }
public void setOnCtrlS(Runnable onCtrlS) public void setOnCtrlS(Runnable onCtrlS) {
{
this.onCtrlS = onCtrlS; this.onCtrlS = onCtrlS;
} }
public RTextScrollPane getScrollPane() public RTextScrollPane getScrollPane() {
{
return scrollPane; return scrollPane;
} }
public JPanel getSearchPanel() public JPanel getSearchPanel() {
{
return searchPanel; return searchPanel;
} }
public JTextField getSearchInput() public JTextField getSearchInput() {
{
return searchInput; return searchInput;
} }
public JCheckBox getCaseSensitiveSearch() public JCheckBox getCaseSensitiveSearch() {
{
return caseSensitiveSearch; return caseSensitiveSearch;
} }
public JLabel getTitleHeader() public JLabel getTitleHeader() {
{
return titleHeader; return titleHeader;
} }
public Runnable getOnCtrlS() public Runnable getOnCtrlS() {
{
return onCtrlS; return onCtrlS;
} }
} }

View File

@ -0,0 +1,74 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
import com.github.weisj.darklaf.components.CloseButton;
import the.bytecode.club.bytecodeviewer.gui.components.listeners.MouseClickedListener;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import javax.swing.*;
import java.awt.*;
public class CloseButtonComponent extends JPanel {
private final JTabbedPane pane;
public CloseButtonComponent(final JTabbedPane pane) {
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
if (pane == null) {
throw new NullPointerException("TabbedPane is null");
}
this.pane = pane;
setOpaque(false);
JLabel label = new JLabel() {
public String getText() {
int i = pane.indexOfTabComponent(CloseButtonComponent.this);
if (i != -1) {
return pane.getTitleAt(i);
}
return null;
}
};
add(label);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
JButton button = new CloseButton();
add(button);
JPopupMenu rightClickMenu = new JPopupMenu();
JMenuItem closeAllTabs = new JMenuItem(String.valueOf(TranslatedStrings.CLOSE_ALL_BUT_THIS));
JMenuItem closeTab = new JMenuItem(String.valueOf(TranslatedStrings.CLOSE_TAB));
rightClickMenu.add(closeAllTabs);
rightClickMenu.add(closeTab);
button.setComponentPopupMenu(rightClickMenu);
button.addMouseListener(new MouseClickedListener(e ->
{
if (pane.indexOfTabComponent(CloseButtonComponent.this) != -1)
pane.remove(pane.indexOfTabComponent(CloseButtonComponent.this));
}));
closeTab.addActionListener(e ->
{
if (pane.indexOfTabComponent(CloseButtonComponent.this) != -1)
pane.remove(pane.indexOfTabComponent(CloseButtonComponent.this));
});
closeAllTabs.addActionListener(e ->
{
while (true) {
if (pane.getTabCount() <= 1)
return;
if (pane.indexOfTabComponent(CloseButtonComponent.this) != 0)
pane.remove(0);
else
pane.remove(1);
}
});
setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
}
}

View File

@ -0,0 +1,572 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
import com.github.weisj.darklaf.ui.tabbedpane.DarkTabbedPaneUI;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
public class DraggableTabbedPane extends JTabbedPane {
public static final long serialVersionUID = 1L;
private static final int LINEWIDTH = 3;
private static final String NAME = "TabTransferData";
private final DataFlavor FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME);
private static final GhostGlassPane s_glassPane = new GhostGlassPane();
private boolean m_isDrawRect = false;
private final Rectangle2D m_lineRect = new Rectangle2D.Double();
private final Color m_lineColor = new Color(0, 100, 255);
private TabAcceptor m_acceptor;
public DraggableTabbedPane() {
super(SwingConstants.TOP, SCROLL_TAB_LAYOUT);
this.putClientProperty(DarkTabbedPaneUI.KEY_DND, true);
/*if (!Configuration.showDarkLAFComponentIcons) {
final DragSourceListener dsl = new DragSourceListener() {
public void dragEnter(DragSourceDragEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
public void dragExit(DragSourceEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
s_glassPane.setPoint(new Point(-1000, -1000));
s_glassPane.repaint();
}
public void dragOver(DragSourceDragEvent e) {
TabTransferData data = getTabTransferData(e);
if (data == null) {
e.getDragSourceContext().setCursor(
DragSource.DefaultMoveNoDrop);
return;
}
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
public void dragDropEnd(DragSourceDropEvent e) {
m_isDrawRect = false;
m_lineRect.setRect(0, 0, 0, 0);
if (hasGhost()) {
s_glassPane.setVisible(false);
s_glassPane.setImage(null);
}
}
public void dropActionChanged(DragSourceDragEvent e) {
}
};
final DragGestureListener dgl = e -> {
Point tabPt = e.getDragOrigin();
int dragTabIndex = indexAtLocation(tabPt.x, tabPt.y);
if (dragTabIndex < 0) {
return;
}
initGlassPane(e.getComponent(), e.getDragOrigin(), dragTabIndex);
try {
e.startDrag(DragSource.DefaultMoveDrop, new TabTransferable(DraggableTabbedPane.this, dragTabIndex), dsl);
} catch (InvalidDnDOperationException idoe) {
idoe.printStackTrace();
}
};
new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new CDropTargetListener(), true);
new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl);
m_acceptor = (a_component, a_index) -> true;
}*/
}
public TabAcceptor getAcceptor() {
return m_acceptor;
}
public void setAcceptor(TabAcceptor a_value) {
m_acceptor = a_value;
}
private TabTransferData getTabTransferData(DropTargetDropEvent a_event) {
Transferable t = a_event.getTransferable();
if (!t.isDataFlavorSupported(FLAVOR)) return null;
try {
return (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private TabTransferData getTabTransferData(DropTargetDragEvent a_event) {
Transferable t = a_event.getTransferable();
if (!t.isDataFlavorSupported(FLAVOR)) return null;
try {
return (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private TabTransferData getTabTransferData(DragSourceDragEvent a_event) {
Transferable t = a_event.getDragSourceContext().getTransferable();
if (!t.isDataFlavorSupported(FLAVOR)) return null;
try {
return (TabTransferData) a_event.getDragSourceContext().getTransferable().getTransferData(FLAVOR);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
class TabTransferable implements Transferable {
private TabTransferData m_data = null;
public TabTransferable(DraggableTabbedPane a_tabbedPane, int a_tabIndex) {
m_data = new TabTransferData(a_tabbedPane, a_tabIndex);
}
public Object getTransferData(DataFlavor flavor) {
return m_data;
}
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] f = new DataFlavor[1];
f[0] = FLAVOR;
return f;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.getHumanPresentableName().equals(NAME);
}
}
static class TabTransferData {
private DraggableTabbedPane m_tabbedPane = null;
private int m_tabIndex = -1;
public TabTransferData() {
}
public TabTransferData(DraggableTabbedPane a_tabbedPane, int a_tabIndex) {
m_tabbedPane = a_tabbedPane;
m_tabIndex = a_tabIndex;
}
public DraggableTabbedPane getTabbedPane() {
return m_tabbedPane;
}
public void setTabbedPane(DraggableTabbedPane pane) {
m_tabbedPane = pane;
}
public int getTabIndex() {
return m_tabIndex;
}
public void setTabIndex(int index) {
m_tabIndex = index;
}
}
private Point buildGhostLocation(Point a_location) {
Point retval = new Point(a_location);
switch (getTabPlacement()) {
case JTabbedPane.TOP: {
retval.y = 1;
retval.x -= s_glassPane.getGhostWidth() / 2;
}
break;
case JTabbedPane.BOTTOM: {
retval.y = getHeight() - 1 - s_glassPane.getGhostHeight();
retval.x -= s_glassPane.getGhostWidth() / 2;
}
break;
case JTabbedPane.LEFT: {
retval.x = 1;
retval.y -= s_glassPane.getGhostHeight() / 2;
}
break;
case JTabbedPane.RIGHT: {
retval.x = getWidth() - 1 - s_glassPane.getGhostWidth();
retval.y -= s_glassPane.getGhostHeight() / 2;
}
break;
}
retval = SwingUtilities.convertPoint(DraggableTabbedPane.this, retval, s_glassPane);
return retval;
}
class CDropTargetListener implements DropTargetListener {
public void dragEnter(DropTargetDragEvent e) {
if (isDragAcceptable(e)) {
e.acceptDrag(e.getDropAction());
} else {
e.rejectDrag();
}
}
public void dragExit(DropTargetEvent e) {
m_isDrawRect = false;
}
public void dropActionChanged(DropTargetDragEvent e) {
}
public void dragOver(final DropTargetDragEvent e) {
TabTransferData data = getTabTransferData(e);
if (data == null) return;
if (getTabPlacement() == JTabbedPane.TOP
|| getTabPlacement() == JTabbedPane.BOTTOM) {
initTargetLeftRightLine(getTargetTabIndex(e.getLocation()), data);
} else {
initTargetTopBottomLine(getTargetTabIndex(e.getLocation()), data);
}
repaint();
if (hasGhost()) {
s_glassPane.setPoint(buildGhostLocation(e.getLocation()));
s_glassPane.repaint();
}
}
public void drop(DropTargetDropEvent a_event) {
if (isDropAcceptable(a_event)) {
convertTab(getTabTransferData(a_event), getTargetTabIndex(a_event.getLocation()));
a_event.dropComplete(true);
} else {
a_event.dropComplete(false);
}
m_isDrawRect = false;
repaint();
BytecodeViewer.viewer.workPane.tabs.setTabComponentAt(getSelectedIndex(), new CloseButtonComponent(DraggableTabbedPane.this));
}
public boolean isDragAcceptable(DropTargetDragEvent e) {
Transferable t = e.getTransferable();
if (t == null) {
return false;
}
DataFlavor[] flavor = e.getCurrentDataFlavors();
if (!t.isDataFlavorSupported(flavor[0])) {
return false;
}
TabTransferData data = getTabTransferData(e);
if (data == null) return false;
if (DraggableTabbedPane.this == data.getTabbedPane()
&& data.getTabIndex() >= 0) {
return true;
}
if (DraggableTabbedPane.this != data.getTabbedPane()) {
if (m_acceptor != null) {
return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex());
}
}
return false;
}
public boolean isDropAcceptable(DropTargetDropEvent e) {
Transferable t = e.getTransferable();
if (t == null) {
return false;
}
DataFlavor[] flavor = e.getCurrentDataFlavors();
if (!t.isDataFlavorSupported(flavor[0])) {
return false;
}
TabTransferData data = getTabTransferData(e);
if (data == null) return false;
if (DraggableTabbedPane.this == data.getTabbedPane()
&& data.getTabIndex() >= 0) {
return true;
}
if (DraggableTabbedPane.this != data.getTabbedPane()) {
if (m_acceptor != null) {
return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex());
}
}
return false;
}
}
private boolean m_hasGhost = true;
public void setPaintGhost(boolean flag) {
m_hasGhost = flag;
}
public boolean hasGhost() {
return m_hasGhost;
}
/**
* returns potential index for drop.
*
* @param a_point point given in the drop site component's coordinate
* @return returns potential index for drop.
*/
private int getTargetTabIndex(Point a_point) {
boolean isTopOrBottom = getTabPlacement() == JTabbedPane.TOP
|| getTabPlacement() == JTabbedPane.BOTTOM;
// if the pane is empty, the target index is always zero.
if (getTabCount() == 0) {
return 0;
}
for (int i = 0; i < getTabCount(); i++) {
Rectangle r = getBoundsAt(i);
if (isTopOrBottom) {
r.setRect(r.x - r.width / 2D, r.y, r.width, r.height);
} else {
r.setRect(r.x, r.y - r.height / 2D, r.width, r.height);
}
if (r.contains(a_point)) {
return i;
}
}
Rectangle r = getBoundsAt(getTabCount() - 1);
if (isTopOrBottom) {
int x = r.x + r.width / 2;
r.setRect(x, r.y, getWidth() - x, r.height);
} else {
int y = r.y + r.height / 2;
r.setRect(r.x, y, r.width, getHeight() - y);
}
return r.contains(a_point) ? getTabCount() : -1;
}
private void convertTab(TabTransferData a_data, int a_targetIndex) {
if (a_data == null) return;
DraggableTabbedPane source = a_data.getTabbedPane();
int sourceIndex = a_data.getTabIndex();
if (sourceIndex < 0) {
return;
}
Component cmp = source.getComponentAt(sourceIndex);
String str = source.getTitleAt(sourceIndex);
if (this != source) {
source.remove(sourceIndex);
if (a_targetIndex == getTabCount()) {
addTab(str, cmp);
} else {
if (a_targetIndex < 0) {
a_targetIndex = 0;
}
insertTab(str, null, cmp, null, a_targetIndex);
}
setSelectedComponent(cmp);
return;
}
if (a_targetIndex < 0 || sourceIndex == a_targetIndex) {
return;
}
if (a_targetIndex == getTabCount()) {
source.remove(sourceIndex);
addTab(str, cmp);
setSelectedIndex(getTabCount() - 1);
} else if (sourceIndex > a_targetIndex) {
source.remove(sourceIndex);
insertTab(str, null, cmp, null, a_targetIndex);
setSelectedIndex(a_targetIndex);
} else {
source.remove(sourceIndex);
insertTab(str, null, cmp, null, a_targetIndex - 1);
setSelectedIndex(a_targetIndex - 1);
}
}
private void initTargetLeftRightLine(int next, TabTransferData a_data) {
if (next < 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
}
if (a_data == null) return;
if ((a_data.getTabbedPane() == this) && (a_data.getTabIndex() == next || next - a_data.getTabIndex() == 1)) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
} else if (getTabCount() == 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
} else if (next == 0) {
Rectangle rect = getBoundsAt(0);
m_lineRect.setRect(-LINEWIDTH / 2D, rect.y, LINEWIDTH, rect.height);
m_isDrawRect = true;
} else if (next == getTabCount()) {
Rectangle rect = getBoundsAt(getTabCount() - 1);
m_lineRect.setRect(rect.x + rect.width - LINEWIDTH / 2D, rect.y, LINEWIDTH, rect.height);
m_isDrawRect = true;
} else {
Rectangle rect = getBoundsAt(next - 1);
m_lineRect.setRect(rect.x + rect.width - LINEWIDTH / 2D, rect.y, LINEWIDTH, rect.height);
m_isDrawRect = true;
}
}
private void initTargetTopBottomLine(int next, TabTransferData a_data) {
if (next < 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
}
if (a_data == null) return;
if ((a_data.getTabbedPane() == this) && (a_data.getTabIndex() == next || next - a_data.getTabIndex() == 1)) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
} else if (getTabCount() == 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
} else if (next == getTabCount()) {
Rectangle rect = getBoundsAt(getTabCount() - 1);
m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH / 2D, rect.width, LINEWIDTH);
m_isDrawRect = true;
} else if (next == 0) {
Rectangle rect = getBoundsAt(0);
m_lineRect.setRect(rect.x, -LINEWIDTH / 2D, rect.width, LINEWIDTH);
m_isDrawRect = true;
} else {
Rectangle rect = getBoundsAt(next - 1);
m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH / 2D, rect.width, LINEWIDTH);
m_isDrawRect = true;
}
}
private void initGlassPane(Component c, Point tabPt, int a_tabIndex) {
getRootPane().setGlassPane(s_glassPane);
if (hasGhost()) {
Rectangle rect = getBoundsAt(a_tabIndex);
BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
c.paint(g);
image = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
s_glassPane.setImage(image);
}
s_glassPane.setPoint(buildGhostLocation(tabPt));
s_glassPane.setVisible(true);
}
private Rectangle getTabAreaBound() {
Rectangle lastTab = getUI().getTabBounds(this, getTabCount() - 1);
return new Rectangle(0, 0, getWidth(), lastTab.y + lastTab.height);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (m_isDrawRect) {
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(m_lineColor);
g2.fill(m_lineRect);
}
}
public interface TabAcceptor {
boolean isDropAcceptable(DraggableTabbedPane a_component, int a_index);
}
}
class GhostGlassPane extends JPanel {
public static final long serialVersionUID = 1L;
private final AlphaComposite m_composite;
private final Point m_location = new Point(0, 0);
private BufferedImage m_draggingGhost = null;
public GhostGlassPane() {
setOpaque(false);
m_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);
}
public void setImage(BufferedImage draggingGhost) {
m_draggingGhost = draggingGhost;
}
public void setPoint(Point a_location) {
m_location.x = a_location.x;
m_location.y = a_location.y;
}
public int getGhostWidth() {
if (m_draggingGhost == null) {
return 0;
}
return m_draggingGhost.getWidth(this);
}
public int getGhostHeight() {
if (m_draggingGhost == null) {
return 0;
}
return m_draggingGhost.getHeight(this);
}
public void paintComponent(Graphics g) {
if (m_draggingGhost == null) {
return;
}
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(m_composite);
g2.drawImage(m_draggingGhost, (int) m_location.getX(), (int) m_location.getY(), null);
}
}

View File

@ -35,14 +35,13 @@ import javax.swing.plaf.basic.BasicButtonUI;
* Using CloseButton of darklaf instead. 4/17/2022 * Using CloseButton of darklaf instead. 4/17/2022
*/ */
@Deprecated @Deprecated
public class TabExitButton extends JButton implements ActionListener public class TabExitButton extends JButton implements ActionListener {
{
private final TabbedPane tabbedPane; private final TabbedPane tabbedPane;
private final int tabIndex; private final int tabIndex;
private final String tabWorkingName; private final String tabWorkingName;
public TabExitButton(TabbedPane tabbedPane, int tabIndex, String tabWorkingName) public TabExitButton(TabbedPane tabbedPane, int tabIndex, String tabWorkingName) {
{
this.tabbedPane = tabbedPane; this.tabbedPane = tabbedPane;
this.tabIndex = tabIndex; this.tabIndex = tabIndex;
this.tabWorkingName = tabWorkingName; this.tabWorkingName = tabWorkingName;
@ -65,29 +64,26 @@ public class TabExitButton extends JButton implements ActionListener
addActionListener(this); addActionListener(this);
} }
public int getTabIndex() public int getTabIndex() {
{
return tabIndex; return tabIndex;
} }
@Override @Override
public void actionPerformed(final ActionEvent e) public void actionPerformed(final ActionEvent e) {
{
final int i = tabbedPane.tabs.indexOfTabComponent(tabbedPane); final int i = tabbedPane.tabs.indexOfTabComponent(tabbedPane);
if (i != -1) if (i != -1) {
{
tabbedPane.tabs.remove(i); tabbedPane.tabs.remove(i);
} }
} }
// we don't want to update UI for this button // we don't want to update UI for this button
@Override @Override
public void updateUI() { } public void updateUI() {
}
// paint the cross // paint the cross
@Override @Override
protected void paintComponent(final Graphics g) protected void paintComponent(final Graphics g) {
{
super.paintComponent(g); super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g.create(); final Graphics2D g2 = (Graphics2D) g.create();
// shift the image for pressed buttons // shift the image for pressed buttons
@ -97,8 +93,9 @@ public class TabExitButton extends JButton implements ActionListener
g2.setStroke(new BasicStroke(2)); g2.setStroke(new BasicStroke(2));
g2.setColor(Color.BLACK); g2.setColor(Color.BLACK);
if (getModel().isRollover()) if (getModel().isRollover()) {
g2.setColor(Color.MAGENTA); g2.setColor(Color.MAGENTA);
}
final int delta = 6; final int delta = 6;
g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1); g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
@ -106,18 +103,15 @@ public class TabExitButton extends JButton implements ActionListener
g2.dispose(); g2.dispose();
} }
public TabbedPane getTabbedPane() public TabbedPane getTabbedPane() {
{
return tabbedPane; return tabbedPane;
} }
public String getTabWorkingName() public String getTabWorkingName() {
{
return tabWorkingName; return tabWorkingName;
} }
public static long getSerialVersionUID() public static long getSerialVersionUID() {
{
return serialVersionUID; return serialVersionUID;
} }

View File

@ -1,29 +1,13 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer; package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import com.github.weisj.darklaf.components.CloseButton;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.components.ButtonHoverAnimation; import the.bytecode.club.bytecodeviewer.gui.components.ButtonHoverAnimation;
import the.bytecode.club.bytecodeviewer.gui.components.MaxWidthJLabel; import the.bytecode.club.bytecodeviewer.gui.components.MaxWidthJLabel;
import the.bytecode.club.bytecodeviewer.gui.components.listeners.MouseClickedListener;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
import the.bytecode.club.bytecodeviewer.gui.util.DelayTabbedPaneThread; import the.bytecode.club.bytecodeviewer.gui.util.DelayTabbedPaneThread;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseListener;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -50,206 +34,42 @@ import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
* @author WaterWolf * @author WaterWolf
* @since 09/26/2011 * @since 09/26/2011
*/ */
public class TabbedPane extends JPanel public class TabbedPane extends JPanel {
{
public final JTabbedPane tabs;
public final JLabel label;
private DelayTabbedPaneThread probablyABadIdea;
private long startedDragging = 0;
public final String tabName;
public final String fileContainerName;
public final ResourceViewer resource;
private static long lastMouseClick = System.currentTimeMillis();
public final static MouseListener buttonHoverAnimation = new ButtonHoverAnimation();
public static final Color BLANK_COLOR = new Color(0, 0, 0, 0);
public TabbedPane(int tabIndex, String tabWorkingName, String fileContainerName, String name, final JTabbedPane existingTabs, ResourceViewer resource) public final JTabbedPane tabs;
{ public final JLabel label;
// unset default FlowLayout' gaps private DelayTabbedPaneThread probablyABadIdea;
super(new FlowLayout(FlowLayout.LEFT, 0, 0)); private long startedDragging = 0;
public final String tabName;
public final String fileContainerName;
public final ResourceViewer resource;
private static long lastMouseClick = System.currentTimeMillis();
public final static MouseListener buttonHoverAnimation = new ButtonHoverAnimation();
public static final Color BLANK_COLOR = new Color(0, 0, 0, 0);
this.tabName = name; public TabbedPane(int tabIndex, String tabWorkingName, String fileContainerName, String name, final JTabbedPane existingTabs, ResourceViewer resource) {
this.fileContainerName = fileContainerName; // unset default FlowLayout' gaps
this.resource = resource; super(new FlowLayout(FlowLayout.LEFT, 0, 0));
if (existingTabs == null) this.tabName = name;
throw new NullPointerException("TabbedPane is null"); this.fileContainerName = fileContainerName;
this.resource = resource;
this.tabs = existingTabs; if (existingTabs == null)
setOpaque(false); throw new NullPointerException("TabbedPane is null");
// make JLabel read titles from JTabbedPane this.tabs = existingTabs;
label = new MaxWidthJLabel(tabName, 400, 20); setOpaque(false);
this.add(label); // make JLabel read titles from JTabbedPane
// add more space between the label and the button label = new MaxWidthJLabel(tabName, 400, 20);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
// tab button
JButton exitButton = new CloseButton();
this.add(exitButton);
// add more space to the top of the component
setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
//define the right click pop-up menu this.add(label);
JPopupMenu rightClickMenu = new JPopupMenu(); // add more space between the label and the button
JMenuItem closeAllTabs = new JMenuItem(TranslatedStrings.CLOSE_ALL_BUT_THIS + ": " + name); label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
JMenuItem closeTab = new JMenuItem(TranslatedStrings.CLOSE_TAB + ": " + name); // add more space to the top of the component
setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
}
rightClickMenu.add(closeAllTabs); private static final long serialVersionUID = -4774885688297538774L;
rightClickMenu.add(closeTab);
//setComponentPopupMenu(rightClickMenu);
exitButton.setComponentPopupMenu(rightClickMenu);
exitButton.addMouseListener(new MouseClickedListener(e ->
{
if (this.getTabIndex() != -1)
existingTabs.remove(this.getTabIndex());
}));
closeTab.addActionListener(e ->
{
if (this.getTabIndex() != -1)
existingTabs.remove(this.getTabIndex());
});
closeAllTabs.addActionListener(e ->
{
while (true)
{
if (existingTabs.getTabCount() <= 1)
return;
if (this.getTabIndex() != 0)
existingTabs.remove(0);
else
existingTabs.remove(1);
}
});
//tab dragging
if(BytecodeViewer.EXPERIMENTAL_TAB_CODE)
{
/*label.addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent arg0) {
}
@Override public void mouseExited(MouseEvent arg0) {
}
@Override public void mousePressed(MouseEvent e) {
onMousePressed(e);
}
@Override public void mouseReleased(MouseEvent e) {
stopDragging(e.getX(), e.getY());
}
});*/
this.addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent arg0) {}
@Override public void mouseExited(MouseEvent arg0) {}
@Override public void mousePressed(MouseEvent e) {
onMousePressed(e);
}
@Override public void mouseReleased(MouseEvent e) {
stopDragging(e.getX(), e.getY());
}
});
}
//middle click close
if(BytecodeViewer.EXPERIMENTAL_TAB_CODE)
{
this.addMouseListener(new MouseAdapter()
{
@Override
public void mouseReleased(MouseEvent e)
{
if (e.getButton() != MouseEvent.BUTTON2)
return;
final int i = existingTabs.indexOfTabComponent(TabbedPane.this);
if (i != -1)
existingTabs.remove(i);
}
});
}
}
private void stopDragging(int mouseX, int mouseY)
{
if (System.currentTimeMillis() - startedDragging >= 210)
{
Rectangle bounds = new Rectangle(1, 1, mouseX, mouseY);
System.out.println("debug-5: " + mouseX + ", " + mouseY);
int totalTabs = BytecodeViewer.viewer.workPane.tabs.getTabCount();
int index = -1;
for (int i = 0; i < totalTabs; i++)
{
Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
if (c != null && bounds.intersects(c.getBounds()))
index = i; //replace this tabs position
}
if (index == -1)
{
for (int i = 0; i < totalTabs; i++)
{
Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
//do some check to see if it's past the X or Y
if (c != null) {
System.out.println("debug-6: " + c.getBounds());
}
}
}
if (index != -1)
{
BytecodeViewer.viewer.workPane.tabs.remove(this);
BytecodeViewer.viewer.workPane.tabs.setTabComponentAt(index, this);
}
}
SwingUtilities.invokeLater(() ->
{
label.setBackground(BLANK_COLOR);
label.updateUI();
});
}
public void onMousePressed(MouseEvent e)
{
BytecodeViewer.viewer.workPane.tabs.dispatchEvent(e);
if(e.getButton() == 1)
{
startedDragging = System.currentTimeMillis();
//dragging = true;
if (probablyABadIdea != null)
probablyABadIdea.stopped = true;
probablyABadIdea = new DelayTabbedPaneThread(TabbedPane.this);
probablyABadIdea.start();
repaint();
System.out.println(e.getX()+", "+e.getY());
Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY());
for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++)
{
Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
if(c != null && bounds.intersects(c.getBounds()))
BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i);
}
}
else
{
stopDragging(e.getX(), e.getY());
}
}
private static final long serialVersionUID = -4774885688297538774L;
public int getTabIndex() {
return tabs.indexOfTabComponent(this);
}
} }

View File

@ -1,18 +1,5 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer; package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
@ -24,6 +11,13 @@ import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJButton; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJButton;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedVisibleComponent; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedVisibleComponent;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashSet;
import java.util.Set;
import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU; import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU;
/*************************************************************************** /***************************************************************************
@ -45,219 +39,205 @@ import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU;
***************************************************************************/ ***************************************************************************/
/** /**
* The pane that contains all of the resources as tabs. * This pane contains all the resources, as tabs.
* *
* @author Konloch * @author Konloch
* @author WaterWolf * @author WaterWolf
* @since 09/26/2011 * @since 09/26/2011
*/ */
public class Workspace extends TranslatedVisibleComponent public class Workspace extends TranslatedVisibleComponent {
{
public final JTabbedPane tabs;
public final JPanel buttonPanel;
public final JButton refreshClass;
public final Set<String> openedTabs = new HashSet<>();
public Workspace() public JTabbedPane tabs;
{ public final JPanel buttonPanel;
super("Workspace", TranslatedComponents.WORK_SPACE); public final JButton refreshClass;
public final Set<String> openedTabs = new HashSet<>();
this.tabs = new JTabbedPane(); public Workspace() {
super("Workspace", TranslatedComponents.WORK_SPACE);
JPopupMenu popUp = new JPopupMenu(); this.tabs = new DraggableTabbedPane();
JMenuItem closeAllTabs = new JMenuItem("Close All But This");
JMenuItem closeTab = new JMenuItem("Close Tab");
closeTab.addActionListener(e ->
{
TabExitButton tabExitButton = (TabExitButton) ((JPopupMenu)((JMenuItem) e.getSource()).getParent()).getInvoker();
final int index = tabExitButton.getTabIndex();
if (index != -1) JPopupMenu popUp = new JPopupMenu();
tabs.remove(index); JMenuItem closeAllTabs = new JMenuItem("Close All But This");
}); JMenuItem closeTab = new JMenuItem("Close Tab");
closeTab.addActionListener(e ->
{
TabExitButton tabExitButton = (TabExitButton) ((JPopupMenu) ((JMenuItem) e.getSource()).getParent()).getInvoker();
final int index = tabExitButton.getTabIndex();
closeAllTabs.addActionListener(e -> if (index != -1)
{ tabs.remove(index);
TabExitButton tabExitButton = (TabExitButton) ((JPopupMenu)((JMenuItem) e.getSource()).getParent()).getInvoker(); });
final int index = tabExitButton.getTabIndex();
while (true) closeAllTabs.addActionListener(e ->
{ {
if (tabs.getTabCount() <= 1) TabExitButton tabExitButton = (TabExitButton) ((JPopupMenu) ((JMenuItem) e.getSource()).getParent()).getInvoker();
return; final int index = tabExitButton.getTabIndex();
if (index != 0) while (true) {
tabs.remove(0); if (tabs.getTabCount() <= 1)
else return;
tabs.remove(1);
}
});
tabs.addMouseListener(new MouseListener() if (index != 0)
{ tabs.remove(0);
@Override else
public void mouseClicked(MouseEvent e) { } tabs.remove(1);
@Override }
public void mouseEntered(MouseEvent arg0) { } });
@Override
public void mouseExited(MouseEvent arg0) { }
@Override tabs.addMouseListener(new MouseListener() {
public void mousePressed(MouseEvent e) @Override
{ public void mouseClicked(MouseEvent e) {
if (BLOCK_TAB_MENU) }
return;
if (e.getButton() == 3) @Override
{ public void mouseEntered(MouseEvent arg0) {
Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); }
for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) @Override
{ public void mouseExited(MouseEvent arg0) {
Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); }
if (c != null && bounds.intersects(c.getBounds()))
{
popUp.setVisible(true);
closeAllTabs.setText(TranslatedStrings.CLOSE_TAB + ": " + ((TabbedPane) c).tabName);
closeTab.setText(TranslatedStrings.CLOSE_TAB + ": " + ((TabbedPane) c).tabName);
}
else
{
popUp.setVisible(false);
}
}
}
}
@Override @Override
public void mouseReleased(MouseEvent e) { } public void mousePressed(MouseEvent e) {
}); if (BLOCK_TAB_MENU)
return;
popUp.add(closeAllTabs); if (e.getButton() == 3) {
popUp.add(closeTab); Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY());
if (!BLOCK_TAB_MENU) for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) {
tabs.setComponentPopupMenu(popUp); Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
if (c != null && bounds.intersects(c.getBounds())) {
popUp.setVisible(true);
closeAllTabs.setText(TranslatedStrings.CLOSE_TAB + ": " + ((TabbedPane) c).tabName);
closeTab.setText(TranslatedStrings.CLOSE_TAB + ": " + ((TabbedPane) c).tabName);
} else {
popUp.setVisible(false);
}
}
}
}
getContentPane().setLayout(new BorderLayout()); @Override
getContentPane().add(tabs, BorderLayout.CENTER); public void mouseReleased(MouseEvent e) {
}
});
buttonPanel = new JPanel(new FlowLayout()); popUp.add(closeAllTabs);
popUp.add(closeTab);
refreshClass = new TranslatedJButton("Refresh", TranslatedComponents.REFRESH); if (!BLOCK_TAB_MENU)
refreshClass.addActionListener((event)-> tabs.setComponentPopupMenu(popUp);
{
refreshClass.setEnabled(false);
Thread t = new Thread(() -> new WorkspaceRefresh(event).run(), "Refresh");
t.start();
});
buttonPanel.add(refreshClass); getContentPane().setLayout(new BorderLayout());
buttonPanel.setVisible(false); getContentPane().add(tabs, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH); buttonPanel = new JPanel(new FlowLayout());
tabs.addContainerListener(new TabRemovalEvent()); refreshClass = new TranslatedJButton("Refresh", TranslatedComponents.REFRESH);
tabs.addChangeListener(arg0 -> buttonPanel.setVisible(tabs.getSelectedIndex() != -1)); refreshClass.addActionListener((event) ->
{
refreshClass.setEnabled(false);
Thread t = new Thread(() -> new WorkspaceRefresh(event).run(), "Refresh");
t.start();
});
this.setVisible(true); buttonPanel.add(refreshClass);
} buttonPanel.setVisible(false);
//load class resources getContentPane().add(buttonPanel, BorderLayout.SOUTH);
public void addClassResource(final ResourceContainer container, final String name)
{
addResource(container, name, new ClassViewer(container, name));
}
//Load file resources tabs.addContainerListener(new TabRemovalEvent());
public void addFileResource(final ResourceContainer container, final String name) tabs.addChangeListener(arg0 -> buttonPanel.setVisible(tabs.getSelectedIndex() != -1));
{
addResource(container, name, new FileViewer(container, name));
}
private void addResource(final ResourceContainer container, final String name, final ResourceViewer resourceView) this.setVisible(true);
{ }
// Warn user and prevent 'nothing' from opening if no Decompiler is selected
if(BytecodeViewer.viewer.viewPane1.getSelectedDecompiler() == Decompiler.NONE &&
BytecodeViewer.viewer.viewPane2.getSelectedDecompiler() == Decompiler.NONE &&
BytecodeViewer.viewer.viewPane3.getSelectedDecompiler() == Decompiler.NONE)
{
BytecodeViewer.showMessage(TranslatedStrings.SUGGESTED_FIX_NO_DECOMPILER_WARNING.toString());
return;
}
//unlock the refresh button //load class resources
BytecodeViewer.viewer.workPane.refreshClass.setEnabled(true); public void addClassResource(final ResourceContainer container, final String name) {
addResource(container, name, new ClassViewer(container, name));
}
final String workingName = container.getWorkingName(name); //Load file resources
public void addFileResource(final ResourceContainer container, final String name) {
addResource(container, name, new FileViewer(container, name));
}
//create a new tab if the resource isn't opened currently private void addResource(final ResourceContainer container, final String name, final ResourceViewer resourceView) {
if (!openedTabs.contains(workingName)) // Warn user and prevent 'nothing' from opening if no Decompiler is selected
{ if (BytecodeViewer.viewer.viewPane1.getSelectedDecompiler() == Decompiler.NONE &&
addResourceToTab(resourceView, workingName, container.name, name); BytecodeViewer.viewer.viewPane2.getSelectedDecompiler() == Decompiler.NONE &&
} BytecodeViewer.viewer.viewPane3.getSelectedDecompiler() == Decompiler.NONE) {
else //if the resource is already opened select this tab as the active one BytecodeViewer.showMessage(TranslatedStrings.SUGGESTED_FIX_NO_DECOMPILER_WARNING.toString());
{ return;
//TODO openedTabs could be changed to a HashMap<String, Integer> for faster lookups }
//search through each tab //unlock the refresh button
for(int i = 0; i < tabs.getTabCount(); i++) BytecodeViewer.viewer.workPane.refreshClass.setEnabled(true);
{
//find the matching resource and open it
ResourceViewer tab = ((TabbedPane)tabs.getTabComponentAt(i)).resource;
if(tab.resource.workingName.equals(workingName))
{
tabs.setSelectedIndex(i);
break;
}
}
}
}
public void addResourceToTab(ResourceViewer resourceView, String workingName, String containerName, String name) final String workingName = container.getWorkingName(name);
{
//start processing the resource to be viewed
if(resourceView instanceof ClassViewer)
resourceView.refresh(null);
//add the resource view to the tabs //create a new tab if the resource isn't opened currently
tabs.add(resourceView); if (!openedTabs.contains(workingName)) {
addResourceToTab(resourceView, workingName, container.name, name);
} else //if the resource is already opened select this tab as the active one
{
//TODO openedTabs could be changed to a HashMap<String, Integer> for faster lookups
//get the resource view index //search through each tab
final int tabIndex = tabs.indexOfComponent(resourceView); for (int i = 0; i < tabs.getTabCount(); i++) {
//find the matching resource and open it
ResourceViewer tab = (ResourceViewer) tabs.getComponentAt(i);
if (tab.resource.workingName.equals(workingName)) {
tabs.setSelectedIndex(i);
break;
}
}
}
}
//create a new tabbed pane public void addResourceToTab(ResourceViewer resourceView, String workingName, String containerName, String name) {
TabbedPane tabbedPane = new TabbedPane(tabIndex, workingName, containerName, name, tabs, resourceView); //start processing the resource to be viewed
resourceView.tabbedPane = tabbedPane; if (resourceView instanceof ClassViewer)
resourceView.resource.workingName = workingName; resourceView.refresh(null);
//set the tabs index //add the resource view to the tabs
tabs.setTabComponentAt(tabIndex, tabbedPane); tabs.add(resourceView);
//open the tab that was just added //get the resource view index
tabs.setSelectedIndex(tabIndex); final int tabIndex = tabs.indexOfComponent(resourceView);
//set resource as opened in a tab //create a new tabbed pane
openedTabs.add(workingName); resourceView.tabbedPane = new TabbedPane(tabIndex, workingName, containerName, name, tabs, resourceView);
resourceView.resource.workingName = workingName;
//refresh the tab title //set the tabs index
resourceView.refreshTitle(); tabs.setTabComponentAt(tabIndex, new CloseButtonComponent(tabs));
}
public ResourceViewer getActiveResource() { //open the tab that was just added
return (ResourceViewer) tabs.getSelectedComponent(); tabs.setSelectedIndex(tabIndex);
}
public Component[] getLoadedViewers() { //set resource as opened in a tab
return tabs.getComponents(); openedTabs.add(workingName);
}
public void resetWorkspace() //refresh the tab title
{ resourceView.refreshTitle();
tabs.removeAll(); }
tabs.updateUI();
}
private static final long serialVersionUID = 6542337997679487946L; public ResourceViewer getActiveResource() {
return (ResourceViewer) tabs.getSelectedComponent();
}
public Component[] getLoadedViewers() {
return tabs.getComponents();
}
public void resetWorkspace() {
tabs.removeAll();
tabs.updateUI();
}
private static final long serialVersionUID = 6542337997679487946L;
} }

View File

@ -14,6 +14,7 @@ import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.Arrays;
import java.util.List; import java.util.List;
/*************************************************************************** /***************************************************************************
@ -67,11 +68,13 @@ public class MemberWithAnnotationSearch implements SearchPanel {
if (srchText.isEmpty()) return; if (srchText.isEmpty()) return;
node.fields.stream().filter(fn -> hasAnnotation(srchText, fn.invisibleAnnotations, fn.visibleAnnotations)).forEach(fn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, null, fn, fn.name + " " + fn.desc, ""))); node.fields.stream().filter(fn -> hasAnnotation(srchText, Arrays.asList(fn.invisibleAnnotations, fn.visibleAnnotations)))
node.methods.stream().filter(mn -> hasAnnotation(srchText, mn.invisibleAnnotations, mn.visibleAnnotations)).forEach(mn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, mn, null, mn.name + mn.desc, ""))); .forEach(fn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, null, fn, fn.name + " " + fn.desc, "")));
node.methods.stream().filter(mn -> hasAnnotation(srchText, Arrays.asList(mn.invisibleAnnotations, mn.visibleAnnotations)))
.forEach(mn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, mn, null, mn.name + mn.desc, "")));
} }
public static boolean hasAnnotation(String annotation, List<AnnotationNode>... annoLists) { public static boolean hasAnnotation(String annotation, List<List<AnnotationNode>> annoLists) {
if (annoLists == null) return false; if (annoLists == null) return false;
for (List<AnnotationNode> annos : annoLists) { for (List<AnnotationNode> annos : annoLists) {
if (annos == null) continue; if (annos == null) continue;

View File

@ -1,6 +1,10 @@
package the.bytecode.club.bytecodeviewer.util; package the.bytecode.club.bytecodeviewer.util;
import com.googlecode.d2j.dex.Dex2jar; import com.googlecode.d2j.dex.Dex2jar;
import com.googlecode.d2j.dex.DexExceptionHandler;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.node.DexMethodNode;
import org.objectweb.asm.MethodVisitor;
import java.io.File; import java.io.File;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
@ -38,7 +42,16 @@ public class Dex2Jar {
*/ */
public static synchronized void dex2Jar(File input, File output) { public static synchronized void dex2Jar(File input, File output) {
try { try {
Dex2jar d2Jar = Dex2jar.from(input); Dex2jar d2Jar = Dex2jar.from(input)
.withExceptionHandler(new DexExceptionHandler() {
public void handleFileException(Exception e) {
e.printStackTrace();
}
public void handleMethodTranslateException(Method method, DexMethodNode methodNode, MethodVisitor mv, Exception e) {
e.printStackTrace();
}
});
d2Jar.to(output.toPath()); d2Jar.to(output.toPath());
} catch (com.googlecode.d2j.DexException e) { } catch (com.googlecode.d2j.DexException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -1,7 +1,7 @@
package the.bytecode.club.bytecodeviewer.util; package the.bytecode.club.bytecodeviewer.util;
import java.net.URL; import java.net.URL;
import me.konloch.kontainer.io.HTTPRequest; import com.konloch.httprequest.HTTPRequest;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
/*************************************************************************** /***************************************************************************