style: enforce strict style rules with editorconfig (PR #510)
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
indent_style = tab
|
||||
tab_width = 4
|
||||
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.xml]
|
||||
indent_size = 1
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.bat]
|
||||
end_of_line = crlf
|
||||
+94
-81
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'org.sonarqube' version '2.7'
|
||||
id 'com.github.ben-manes.versions' version '0.21.0'
|
||||
id 'org.sonarqube' version '2.7'
|
||||
id 'com.github.ben-manes.versions' version '0.21.0'
|
||||
id 'org.ec4j.editorconfig' version '0.0.3'
|
||||
}
|
||||
|
||||
ext.jadxVersion = System.getenv('JADX_VERSION') ?: "dev"
|
||||
@@ -8,125 +9,137 @@ version = jadxVersion
|
||||
println("jadx version: ${jadxVersion}")
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'jacoco'
|
||||
|
||||
version = jadxVersion
|
||||
version = jadxVersion
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
tasks.withType(JavaCompile) {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
if (!"$it".contains(':jadx-samples:')) {
|
||||
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
}
|
||||
}
|
||||
if (!"$it".contains(':jadx-samples:')) {
|
||||
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
}
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
jar {
|
||||
version = jadxVersion
|
||||
manifest {
|
||||
mainAttributes('jadx-version': jadxVersion)
|
||||
}
|
||||
}
|
||||
jar {
|
||||
version = jadxVersion
|
||||
manifest {
|
||||
mainAttributes('jadx-version': jadxVersion)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'org.slf4j:slf4j-api:1.7.26'
|
||||
dependencies {
|
||||
compile 'org.slf4j:slf4j-api:1.7.26'
|
||||
|
||||
testCompile 'ch.qos.logback:logback-classic:1.2.3'
|
||||
testCompile 'org.hamcrest:hamcrest-library:2.1'
|
||||
testCompile 'org.mockito:mockito-core:2.25.1'
|
||||
testCompile 'ch.qos.logback:logback-classic:1.2.3'
|
||||
testCompile 'org.hamcrest:hamcrest-library:2.1'
|
||||
testCompile 'org.mockito:mockito-core:2.25.1'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.1'
|
||||
}
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.1'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.2"
|
||||
}
|
||||
jacocoTestReport {
|
||||
reports {
|
||||
xml.enabled = true
|
||||
html.enabled = true
|
||||
}
|
||||
}
|
||||
jacoco {
|
||||
toolVersion = "0.8.2"
|
||||
}
|
||||
jacocoTestReport {
|
||||
reports {
|
||||
xml.enabled = true
|
||||
html.enabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property 'sonar.exclusions', '**/jadx/samples/**/*,**/test-app/**/*'
|
||||
property 'sonar.coverage.exclusions', '**/jadx/gui/**/*'
|
||||
}
|
||||
properties {
|
||||
property 'sonar.exclusions', '**/jadx/samples/**/*,**/test-app/**/*'
|
||||
property 'sonar.coverage.exclusions', '**/jadx/gui/**/*'
|
||||
}
|
||||
}
|
||||
|
||||
editorconfig {
|
||||
excludes = ['gradle/'
|
||||
, 'jadx-test-app/test-app' // ignore issues in submodule
|
||||
, '**/out/' // IntelliJ Idea build dirs
|
||||
, '**/certificate-test/' // binary test files (.RSA)
|
||||
, '**/*.svg'
|
||||
, '**/*.arsc'
|
||||
]
|
||||
}
|
||||
|
||||
dependencyUpdates.resolutionStrategy = {
|
||||
componentSelection { rules ->
|
||||
rules.all { ComponentSelection selection ->
|
||||
boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm', 'atlassian'].any { qualifier ->
|
||||
selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
|
||||
}
|
||||
if (rejected) {
|
||||
selection.reject('Release candidate')
|
||||
}
|
||||
}
|
||||
}
|
||||
componentSelection { rules ->
|
||||
rules.all { ComponentSelection selection ->
|
||||
boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm', 'atlassian'].any { qualifier ->
|
||||
selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
|
||||
}
|
||||
if (rejected) {
|
||||
selection.reject('Release candidate')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task copyArtifacts(type: Sync, dependsOn: ['jadx-cli:installDist', 'jadx-gui:installDist']) {
|
||||
destinationDir file("$buildDir/jadx")
|
||||
['jadx-cli', 'jadx-gui'].each {
|
||||
from tasks.getByPath(":${it}:installDist").destinationDir
|
||||
}
|
||||
destinationDir file("$buildDir/jadx")
|
||||
['jadx-cli', 'jadx-gui'].each {
|
||||
from tasks.getByPath(":${it}:installDist").destinationDir
|
||||
}
|
||||
}
|
||||
|
||||
task pack(type: Zip, dependsOn: copyArtifacts) {
|
||||
destinationDir buildDir
|
||||
archiveName "jadx-${jadxVersion}.zip"
|
||||
from copyArtifacts.destinationDir
|
||||
destinationDir buildDir
|
||||
archiveName "jadx-${jadxVersion}.zip"
|
||||
from copyArtifacts.destinationDir
|
||||
}
|
||||
|
||||
task copyExe(type: Copy, dependsOn: 'jadx-gui:createExe') {
|
||||
group 'jadx'
|
||||
description = 'Copy exe to build dir'
|
||||
destinationDir buildDir
|
||||
from tasks.getByPath('jadx-gui:createExe').outputs
|
||||
include '*.exe'
|
||||
group 'jadx'
|
||||
description = 'Copy exe to build dir'
|
||||
destinationDir buildDir
|
||||
from tasks.getByPath('jadx-gui:createExe').outputs
|
||||
include '*.exe'
|
||||
}
|
||||
|
||||
task dist(dependsOn: [pack, copyExe]) {
|
||||
group 'jadx'
|
||||
description = 'Build jadx distribution zip'
|
||||
group 'jadx'
|
||||
description = 'Build jadx distribution zip'
|
||||
}
|
||||
|
||||
task samples(dependsOn: 'jadx-samples:samples') {
|
||||
group 'jadx'
|
||||
group 'jadx'
|
||||
}
|
||||
|
||||
task testAppCheck(dependsOn: 'jadx-test-app:testAppCheck') {
|
||||
group 'jadx'
|
||||
group 'jadx'
|
||||
}
|
||||
|
||||
task cleanBuildDir(type: Delete) {
|
||||
group 'jadx'
|
||||
delete buildDir
|
||||
group 'jadx'
|
||||
delete buildDir
|
||||
}
|
||||
|
||||
build.dependsOn(dist, samples)
|
||||
check.dependsOn editorconfigCheck
|
||||
|
||||
test.dependsOn(samples)
|
||||
|
||||
clean.dependsOn(cleanBuildDir)
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ public class JadxCLIArgs {
|
||||
}
|
||||
if (verbose) {
|
||||
ch.qos.logback.classic.Logger rootLogger =
|
||||
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
// remove INFO ThresholdFilter
|
||||
Appender<ILoggingEvent> appender = rootLogger.getAppender("STDOUT");
|
||||
if (appender != null) {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
|
||||
@@ -137,7 +137,7 @@ public class JadxArgs {
|
||||
public boolean isDebugInfo() {
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
|
||||
public void setDebugInfo(boolean debugInfo) {
|
||||
this.debugInfo = debugInfo;
|
||||
}
|
||||
@@ -257,5 +257,4 @@ public class JadxArgs {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates a test which is known to fail.
|
||||
*
|
||||
*
|
||||
* <p>This would cause a failure to be considered as success and a success as failure,
|
||||
* with the benefit of updating the related issue when it has been resolved even unintentionally.</p>
|
||||
*
|
||||
*
|
||||
* <p>To have an effect, the test class must be annotated with:
|
||||
*
|
||||
*
|
||||
* <code>
|
||||
* @ExtendWith(NotYetImplementedExtension.class)
|
||||
* @ExtendWith(NotYetImplementedExtension.class)
|
||||
* </code>
|
||||
* </p>
|
||||
*/
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package jadx.tests.integration.generics;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class TestImportGenericMap extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
@@ -25,16 +25,15 @@ public class TestImportGenericMap extends IntegrationTest {
|
||||
|
||||
final class SuperClass<O extends SuperClass.ToImport> {
|
||||
|
||||
interface ToImport {
|
||||
}
|
||||
interface ToImport {
|
||||
}
|
||||
|
||||
interface NotToImport {
|
||||
}
|
||||
interface NotToImport {
|
||||
}
|
||||
|
||||
static final class Class1<C extends NotToImport> {
|
||||
}
|
||||
static final class Class1<C extends NotToImport> {
|
||||
}
|
||||
|
||||
public <C extends NotToImport> SuperClass(Class1<C> zzf) {
|
||||
}
|
||||
|
||||
}
|
||||
public <C extends NotToImport> SuperClass(Class1<C> zzf) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss} %-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss} %-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import jadx.api.JavaClass;
|
||||
@@ -47,7 +45,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
|
||||
List<String> excludedPackages = wrapper.getExcludedPackages();
|
||||
this.enabled = excludedPackages.isEmpty()
|
||||
|| excludedPackages.stream().filter(p -> !p.isEmpty())
|
||||
.noneMatch(p -> name.equals(p) || name.startsWith(p + '.'));
|
||||
.noneMatch(p -> name.equals(p) || name.startsWith(p + '.'));
|
||||
}
|
||||
|
||||
public final void update() {
|
||||
@@ -130,7 +128,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
|
||||
public String makeLongString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import static javax.swing.KeyStroke.getKeyStroke;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.DisplayMode;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.MenuEvent;
|
||||
import javax.swing.event.MenuListener;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeWillExpandListener;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
import java.awt.*;
|
||||
import java.awt.dnd.DnDConstants;
|
||||
import java.awt.dnd.DropTarget;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -22,38 +27,6 @@ import java.util.Arrays;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.ProgressMonitor;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.WindowConstants;
|
||||
import javax.swing.event.MenuEvent;
|
||||
import javax.swing.event.MenuListener;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeWillExpandListener;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.Theme;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -83,6 +56,8 @@ import jadx.gui.utils.Link;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.Utils;
|
||||
|
||||
import static javax.swing.KeyStroke.getKeyStroke;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class MainWindow extends JFrame {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainWindow.class);
|
||||
@@ -343,10 +318,10 @@ public class MainWindow extends JFrame {
|
||||
Object obj = tree.getLastSelectedPathComponent();
|
||||
if (obj instanceof JPackage) {
|
||||
JPackagePopUp menu = new JPackagePopUp((JPackage) obj);
|
||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void syncWithEditor() {
|
||||
ContentPanel selectedContentPanel = tabbedPane.getSelectedCodePanel();
|
||||
if (selectedContentPanel == null) {
|
||||
@@ -608,8 +583,7 @@ public class MainWindow extends JFrame {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (SwingUtilities.isRightMouseButton(e)) {
|
||||
treeRightClickAction(e);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
treeClickAction();
|
||||
}
|
||||
}
|
||||
@@ -780,7 +754,7 @@ public class MainWindow extends JFrame {
|
||||
public void menuCanceled(MenuEvent e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class JPackagePopUp extends JPopupMenu {
|
||||
JMenuItem excludeItem = new JCheckBoxMenuItem("Exclude");
|
||||
|
||||
@@ -791,8 +765,7 @@ public class MainWindow extends JFrame {
|
||||
String fullName = pkg.getFullName();
|
||||
if (excludeItem.isSelected()) {
|
||||
wrapper.addExcludedPackage(fullName);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
wrapper.removeExcludedPackage(fullName);
|
||||
}
|
||||
reOpenFile();
|
||||
|
||||
@@ -1,226 +1,226 @@
|
||||
package jadx.gui.ui.codearea;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.MatteBorder;
|
||||
import javax.swing.event.CaretEvent;
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.Utilities;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
|
||||
import org.fife.ui.rsyntaxtextarea.Token;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LineNumbers extends JPanel implements CaretListener {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LineNumbers.class);
|
||||
|
||||
private static final long serialVersionUID = -4978268673635308190L;
|
||||
|
||||
private static final int NUM_HEIGHT = Integer.MAX_VALUE - 1000000;
|
||||
private static final Map<?, ?> DESKTOP_HINTS = (Map<?, ?>) Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints");
|
||||
|
||||
private final CodeArea codeArea;
|
||||
private boolean useSourceLines = true;
|
||||
|
||||
private int lastDigits;
|
||||
private int lastLine;
|
||||
private Map<String, FontMetrics> fonts;
|
||||
|
||||
private final transient Color numberColor;
|
||||
private final transient Color currentColor;
|
||||
private final transient Border border;
|
||||
|
||||
public LineNumbers(CodeArea component) {
|
||||
this.codeArea = component;
|
||||
setFont(component.getFont());
|
||||
SyntaxScheme syntaxScheme = codeArea.getSyntaxScheme();
|
||||
numberColor = syntaxScheme.getStyle(Token.LITERAL_NUMBER_DECIMAL_INT).foreground;
|
||||
currentColor = syntaxScheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).foreground;
|
||||
border = new MatteBorder(0, 0, 0, 1, syntaxScheme.getStyle(Token.COMMENT_MULTILINE).foreground);
|
||||
setBackground(codeArea.getBackground());
|
||||
setForeground(numberColor);
|
||||
|
||||
setBorderGap(5);
|
||||
setPreferredWidth();
|
||||
|
||||
component.addCaretListener(this);
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
useSourceLines = !useSourceLines;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setBorderGap(int borderGap) {
|
||||
Border inner = new EmptyBorder(0, borderGap, 0, borderGap);
|
||||
setBorder(new CompoundBorder(border, inner));
|
||||
lastDigits = 0;
|
||||
}
|
||||
|
||||
private void setPreferredWidth() {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int lines = root.getElementCount();
|
||||
int digits = Math.max(String.valueOf(lines).length(), 3);
|
||||
if (lastDigits != digits) {
|
||||
lastDigits = digits;
|
||||
FontMetrics fontMetrics = getFontMetrics(getFont());
|
||||
int width = fontMetrics.charWidth('0') * digits;
|
||||
Insets insets = getInsets();
|
||||
int preferredWidth = insets.left + insets.right + width;
|
||||
|
||||
Dimension d = getPreferredSize();
|
||||
if (d != null) {
|
||||
d.setSize(preferredWidth, NUM_HEIGHT);
|
||||
setPreferredSize(d);
|
||||
setSize(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
applyRenderHints(g);
|
||||
|
||||
Font font = codeArea.getFont();
|
||||
font = font.deriveFont(font.getSize2D() - 1.0f);
|
||||
g.setFont(font);
|
||||
|
||||
Dimension size = getSize();
|
||||
g.setColor(codeArea.getBackground());
|
||||
g.fillRect(0, 0, size.width, size.height);
|
||||
|
||||
FontMetrics fontMetrics = codeArea.getFontMetrics(font);
|
||||
Insets insets = getInsets();
|
||||
int availableWidth = size.width - insets.left - insets.right;
|
||||
Rectangle clip = g.getClipBounds();
|
||||
int rowStartOffset = codeArea.viewToModel(new Point(0, clip.y));
|
||||
int endOffset = codeArea.viewToModel(new Point(0, clip.y + clip.height));
|
||||
|
||||
while (rowStartOffset <= endOffset) {
|
||||
try {
|
||||
String lineNumber = getTextLineNumber(rowStartOffset);
|
||||
if (lineNumber != null) {
|
||||
if (isCurrentLine(rowStartOffset)) {
|
||||
g.setColor(currentColor);
|
||||
} else {
|
||||
g.setColor(numberColor);
|
||||
}
|
||||
int stringWidth = fontMetrics.stringWidth(lineNumber);
|
||||
int x = availableWidth - stringWidth + insets.left;
|
||||
int y = getOffsetY(rowStartOffset, fontMetrics);
|
||||
g.drawString(lineNumber, x, y);
|
||||
}
|
||||
rowStartOffset = Utilities.getRowEnd(codeArea, rowStartOffset) + 1;
|
||||
} catch (Exception e) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Line numbers draw error", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyRenderHints(Graphics g) {
|
||||
if (g instanceof Graphics2D) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
if (DESKTOP_HINTS != null) {
|
||||
g2d.setRenderingHints(DESKTOP_HINTS);
|
||||
} else {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCurrentLine(int rowStartOffset) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
return root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getTextLineNumber(int rowStartOffset) {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int index = root.getElementIndex(rowStartOffset);
|
||||
Element line = root.getElement(index);
|
||||
if (line.getStartOffset() != rowStartOffset) {
|
||||
return null;
|
||||
}
|
||||
int lineNumber = index + 1;
|
||||
if (useSourceLines) {
|
||||
Integer sourceLine = codeArea.getSourceLine(lineNumber);
|
||||
if (sourceLine == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(sourceLine);
|
||||
}
|
||||
return String.valueOf(lineNumber);
|
||||
}
|
||||
|
||||
private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException {
|
||||
Rectangle r = codeArea.modelToView(rowStartOffset);
|
||||
if (r == null) {
|
||||
throw new BadLocationException("Can't get Y offset", rowStartOffset);
|
||||
}
|
||||
int lineHeight = fontMetrics.getHeight();
|
||||
int y = r.y + r.height;
|
||||
int descent = 0;
|
||||
if (r.height == lineHeight) {
|
||||
descent = fontMetrics.getDescent();
|
||||
} else {
|
||||
if (fonts == null) {
|
||||
fonts = new HashMap<>();
|
||||
}
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int index = root.getElementIndex(rowStartOffset);
|
||||
Element line = root.getElement(index);
|
||||
for (int i = 0; i < line.getElementCount(); i++) {
|
||||
Element child = line.getElement(i);
|
||||
AttributeSet as = child.getAttributes();
|
||||
String fontFamily = (String) as.getAttribute(StyleConstants.FontFamily);
|
||||
Integer fontSize = (Integer) as.getAttribute(StyleConstants.FontSize);
|
||||
String key = fontFamily + fontSize;
|
||||
FontMetrics fm = fonts.computeIfAbsent(key, k -> {
|
||||
Font font = new Font(fontFamily, Font.PLAIN, fontSize);
|
||||
return codeArea.getFontMetrics(font);
|
||||
});
|
||||
descent = Math.max(descent, fm.getDescent());
|
||||
}
|
||||
}
|
||||
return y - descent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int currentLine = root.getElementIndex(caretPosition);
|
||||
if (lastLine != currentLine) {
|
||||
repaint();
|
||||
lastLine = currentLine;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseSourceLines(boolean useSourceLines) {
|
||||
this.useSourceLines = useSourceLines;
|
||||
}
|
||||
}
|
||||
package jadx.gui.ui.codearea;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.MatteBorder;
|
||||
import javax.swing.event.CaretEvent;
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.Utilities;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
|
||||
import org.fife.ui.rsyntaxtextarea.Token;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LineNumbers extends JPanel implements CaretListener {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LineNumbers.class);
|
||||
|
||||
private static final long serialVersionUID = -4978268673635308190L;
|
||||
|
||||
private static final int NUM_HEIGHT = Integer.MAX_VALUE - 1000000;
|
||||
private static final Map<?, ?> DESKTOP_HINTS = (Map<?, ?>) Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints");
|
||||
|
||||
private final CodeArea codeArea;
|
||||
private boolean useSourceLines = true;
|
||||
|
||||
private int lastDigits;
|
||||
private int lastLine;
|
||||
private Map<String, FontMetrics> fonts;
|
||||
|
||||
private final transient Color numberColor;
|
||||
private final transient Color currentColor;
|
||||
private final transient Border border;
|
||||
|
||||
public LineNumbers(CodeArea component) {
|
||||
this.codeArea = component;
|
||||
setFont(component.getFont());
|
||||
SyntaxScheme syntaxScheme = codeArea.getSyntaxScheme();
|
||||
numberColor = syntaxScheme.getStyle(Token.LITERAL_NUMBER_DECIMAL_INT).foreground;
|
||||
currentColor = syntaxScheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).foreground;
|
||||
border = new MatteBorder(0, 0, 0, 1, syntaxScheme.getStyle(Token.COMMENT_MULTILINE).foreground);
|
||||
setBackground(codeArea.getBackground());
|
||||
setForeground(numberColor);
|
||||
|
||||
setBorderGap(5);
|
||||
setPreferredWidth();
|
||||
|
||||
component.addCaretListener(this);
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
useSourceLines = !useSourceLines;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setBorderGap(int borderGap) {
|
||||
Border inner = new EmptyBorder(0, borderGap, 0, borderGap);
|
||||
setBorder(new CompoundBorder(border, inner));
|
||||
lastDigits = 0;
|
||||
}
|
||||
|
||||
private void setPreferredWidth() {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int lines = root.getElementCount();
|
||||
int digits = Math.max(String.valueOf(lines).length(), 3);
|
||||
if (lastDigits != digits) {
|
||||
lastDigits = digits;
|
||||
FontMetrics fontMetrics = getFontMetrics(getFont());
|
||||
int width = fontMetrics.charWidth('0') * digits;
|
||||
Insets insets = getInsets();
|
||||
int preferredWidth = insets.left + insets.right + width;
|
||||
|
||||
Dimension d = getPreferredSize();
|
||||
if (d != null) {
|
||||
d.setSize(preferredWidth, NUM_HEIGHT);
|
||||
setPreferredSize(d);
|
||||
setSize(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
applyRenderHints(g);
|
||||
|
||||
Font font = codeArea.getFont();
|
||||
font = font.deriveFont(font.getSize2D() - 1.0f);
|
||||
g.setFont(font);
|
||||
|
||||
Dimension size = getSize();
|
||||
g.setColor(codeArea.getBackground());
|
||||
g.fillRect(0, 0, size.width, size.height);
|
||||
|
||||
FontMetrics fontMetrics = codeArea.getFontMetrics(font);
|
||||
Insets insets = getInsets();
|
||||
int availableWidth = size.width - insets.left - insets.right;
|
||||
Rectangle clip = g.getClipBounds();
|
||||
int rowStartOffset = codeArea.viewToModel(new Point(0, clip.y));
|
||||
int endOffset = codeArea.viewToModel(new Point(0, clip.y + clip.height));
|
||||
|
||||
while (rowStartOffset <= endOffset) {
|
||||
try {
|
||||
String lineNumber = getTextLineNumber(rowStartOffset);
|
||||
if (lineNumber != null) {
|
||||
if (isCurrentLine(rowStartOffset)) {
|
||||
g.setColor(currentColor);
|
||||
} else {
|
||||
g.setColor(numberColor);
|
||||
}
|
||||
int stringWidth = fontMetrics.stringWidth(lineNumber);
|
||||
int x = availableWidth - stringWidth + insets.left;
|
||||
int y = getOffsetY(rowStartOffset, fontMetrics);
|
||||
g.drawString(lineNumber, x, y);
|
||||
}
|
||||
rowStartOffset = Utilities.getRowEnd(codeArea, rowStartOffset) + 1;
|
||||
} catch (Exception e) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Line numbers draw error", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyRenderHints(Graphics g) {
|
||||
if (g instanceof Graphics2D) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
if (DESKTOP_HINTS != null) {
|
||||
g2d.setRenderingHints(DESKTOP_HINTS);
|
||||
} else {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCurrentLine(int rowStartOffset) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
return root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getTextLineNumber(int rowStartOffset) {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int index = root.getElementIndex(rowStartOffset);
|
||||
Element line = root.getElement(index);
|
||||
if (line.getStartOffset() != rowStartOffset) {
|
||||
return null;
|
||||
}
|
||||
int lineNumber = index + 1;
|
||||
if (useSourceLines) {
|
||||
Integer sourceLine = codeArea.getSourceLine(lineNumber);
|
||||
if (sourceLine == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(sourceLine);
|
||||
}
|
||||
return String.valueOf(lineNumber);
|
||||
}
|
||||
|
||||
private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException {
|
||||
Rectangle r = codeArea.modelToView(rowStartOffset);
|
||||
if (r == null) {
|
||||
throw new BadLocationException("Can't get Y offset", rowStartOffset);
|
||||
}
|
||||
int lineHeight = fontMetrics.getHeight();
|
||||
int y = r.y + r.height;
|
||||
int descent = 0;
|
||||
if (r.height == lineHeight) {
|
||||
descent = fontMetrics.getDescent();
|
||||
} else {
|
||||
if (fonts == null) {
|
||||
fonts = new HashMap<>();
|
||||
}
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int index = root.getElementIndex(rowStartOffset);
|
||||
Element line = root.getElement(index);
|
||||
for (int i = 0; i < line.getElementCount(); i++) {
|
||||
Element child = line.getElement(i);
|
||||
AttributeSet as = child.getAttributes();
|
||||
String fontFamily = (String) as.getAttribute(StyleConstants.FontFamily);
|
||||
Integer fontSize = (Integer) as.getAttribute(StyleConstants.FontSize);
|
||||
String key = fontFamily + fontSize;
|
||||
FontMetrics fm = fonts.computeIfAbsent(key, k -> {
|
||||
Font font = new Font(fontFamily, Font.PLAIN, fontSize);
|
||||
return codeArea.getFontMetrics(font);
|
||||
});
|
||||
descent = Math.max(descent, fm.getDescent());
|
||||
}
|
||||
}
|
||||
return y - descent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int currentLine = root.getElementIndex(caretPosition);
|
||||
if (lastLine != currentLine) {
|
||||
repaint();
|
||||
lastLine = currentLine;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseSourceLines(boolean useSourceLines) {
|
||||
this.useSourceLines = useSourceLines;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +1,108 @@
|
||||
package jadx.gui.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.PropertyResourceBundle;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Vector;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public class NLS {
|
||||
|
||||
private static final Vector<LangLocale> i18nLocales = new Vector<>();
|
||||
|
||||
private static final Map<LangLocale, ResourceBundle> i18nMessagesMap = new HashMap<>();
|
||||
|
||||
private static final ResourceBundle fallbackMessagesMap;
|
||||
private static final LangLocale localLocale;
|
||||
|
||||
// Use these two fields to avoid invoking Map.get() method twice.
|
||||
private static ResourceBundle localizedMessagesMap;
|
||||
private static LangLocale currentLocale;
|
||||
|
||||
static {
|
||||
localLocale = new LangLocale(Locale.getDefault());
|
||||
|
||||
i18nLocales.add(new LangLocale("en", "US")); // As default language
|
||||
i18nLocales.add(new LangLocale("zh", "CN"));
|
||||
i18nLocales.add(new LangLocale("es", "ES"));
|
||||
|
||||
i18nLocales.forEach(NLS::load);
|
||||
|
||||
LangLocale defLang = i18nLocales.get(0);
|
||||
fallbackMessagesMap = i18nMessagesMap.get(defLang);
|
||||
localizedMessagesMap = i18nMessagesMap.get(defLang);
|
||||
}
|
||||
|
||||
private NLS() {
|
||||
}
|
||||
|
||||
private static void load(LangLocale locale) {
|
||||
ResourceBundle bundle;
|
||||
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
|
||||
String resName = String.format("i18n/Messages_%s.properties", locale.get());
|
||||
URL bundleUrl = classLoader.getResource(resName);
|
||||
if (bundleUrl == null) {
|
||||
throw new JadxRuntimeException("Locale resource not found: " + resName);
|
||||
}
|
||||
try (Reader reader = new InputStreamReader(bundleUrl.openStream(), StandardCharsets.UTF_8)) {
|
||||
bundle = new PropertyResourceBundle(reader);
|
||||
} catch (IOException e) {
|
||||
throw new JadxRuntimeException("Failed to load " + resName, e);
|
||||
}
|
||||
i18nMessagesMap.put(locale, bundle);
|
||||
}
|
||||
|
||||
public static String str(String key) {
|
||||
try {
|
||||
return localizedMessagesMap.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return fallbackMessagesMap.getString(key); // definitely exists
|
||||
}
|
||||
}
|
||||
|
||||
public static String str(String key, LangLocale locale) {
|
||||
ResourceBundle bundle = i18nMessagesMap.get(locale);
|
||||
if (bundle != null) {
|
||||
try {
|
||||
return bundle.getString(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
// use fallback string
|
||||
}
|
||||
}
|
||||
return fallbackMessagesMap.getString(key); // definitely exists
|
||||
}
|
||||
|
||||
public static void setLocale(LangLocale locale) {
|
||||
if (i18nMessagesMap.containsKey(locale)) {
|
||||
currentLocale = locale;
|
||||
} else {
|
||||
currentLocale = i18nLocales.get(0);
|
||||
}
|
||||
localizedMessagesMap = i18nMessagesMap.get(currentLocale);
|
||||
}
|
||||
|
||||
public static Vector<LangLocale> getI18nLocales() {
|
||||
return i18nLocales;
|
||||
}
|
||||
|
||||
public static LangLocale currentLocale() {
|
||||
return currentLocale;
|
||||
}
|
||||
|
||||
public static LangLocale defaultLocale() {
|
||||
if (i18nMessagesMap.containsKey(localLocale)) {
|
||||
return localLocale;
|
||||
}
|
||||
// fallback to english if unsupported
|
||||
return i18nLocales.get(0);
|
||||
}
|
||||
}
|
||||
package jadx.gui.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.PropertyResourceBundle;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Vector;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public class NLS {
|
||||
|
||||
private static final Vector<LangLocale> i18nLocales = new Vector<>();
|
||||
|
||||
private static final Map<LangLocale, ResourceBundle> i18nMessagesMap = new HashMap<>();
|
||||
|
||||
private static final ResourceBundle fallbackMessagesMap;
|
||||
private static final LangLocale localLocale;
|
||||
|
||||
// Use these two fields to avoid invoking Map.get() method twice.
|
||||
private static ResourceBundle localizedMessagesMap;
|
||||
private static LangLocale currentLocale;
|
||||
|
||||
static {
|
||||
localLocale = new LangLocale(Locale.getDefault());
|
||||
|
||||
i18nLocales.add(new LangLocale("en", "US")); // As default language
|
||||
i18nLocales.add(new LangLocale("zh", "CN"));
|
||||
i18nLocales.add(new LangLocale("es", "ES"));
|
||||
|
||||
i18nLocales.forEach(NLS::load);
|
||||
|
||||
LangLocale defLang = i18nLocales.get(0);
|
||||
fallbackMessagesMap = i18nMessagesMap.get(defLang);
|
||||
localizedMessagesMap = i18nMessagesMap.get(defLang);
|
||||
}
|
||||
|
||||
private NLS() {
|
||||
}
|
||||
|
||||
private static void load(LangLocale locale) {
|
||||
ResourceBundle bundle;
|
||||
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
|
||||
String resName = String.format("i18n/Messages_%s.properties", locale.get());
|
||||
URL bundleUrl = classLoader.getResource(resName);
|
||||
if (bundleUrl == null) {
|
||||
throw new JadxRuntimeException("Locale resource not found: " + resName);
|
||||
}
|
||||
try (Reader reader = new InputStreamReader(bundleUrl.openStream(), StandardCharsets.UTF_8)) {
|
||||
bundle = new PropertyResourceBundle(reader);
|
||||
} catch (IOException e) {
|
||||
throw new JadxRuntimeException("Failed to load " + resName, e);
|
||||
}
|
||||
i18nMessagesMap.put(locale, bundle);
|
||||
}
|
||||
|
||||
public static String str(String key) {
|
||||
try {
|
||||
return localizedMessagesMap.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return fallbackMessagesMap.getString(key); // definitely exists
|
||||
}
|
||||
}
|
||||
|
||||
public static String str(String key, LangLocale locale) {
|
||||
ResourceBundle bundle = i18nMessagesMap.get(locale);
|
||||
if (bundle != null) {
|
||||
try {
|
||||
return bundle.getString(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
// use fallback string
|
||||
}
|
||||
}
|
||||
return fallbackMessagesMap.getString(key); // definitely exists
|
||||
}
|
||||
|
||||
public static void setLocale(LangLocale locale) {
|
||||
if (i18nMessagesMap.containsKey(locale)) {
|
||||
currentLocale = locale;
|
||||
} else {
|
||||
currentLocale = i18nLocales.get(0);
|
||||
}
|
||||
localizedMessagesMap = i18nMessagesMap.get(currentLocale);
|
||||
}
|
||||
|
||||
public static Vector<LangLocale> getI18nLocales() {
|
||||
return i18nLocales;
|
||||
}
|
||||
|
||||
public static LangLocale currentLocale() {
|
||||
return currentLocale;
|
||||
}
|
||||
|
||||
public static LangLocale defaultLocale() {
|
||||
if (i18nMessagesMap.containsKey(localLocale)) {
|
||||
return localLocale;
|
||||
}
|
||||
// fallback to english if unsupported
|
||||
return i18nLocales.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
+25
-25
@@ -1,52 +1,52 @@
|
||||
project.ext {
|
||||
mainSamplesClass = "jadx.samples.RunTests"
|
||||
samplesJadxSrcDir = "${buildDir}/samples-jadx/src"
|
||||
samplesJadxOutDir = "${buildDir}/samples-jadx/output"
|
||||
mainSamplesClass = "jadx.samples.RunTests"
|
||||
samplesJadxSrcDir = "${buildDir}/samples-jadx/src"
|
||||
samplesJadxOutDir = "${buildDir}/samples-jadx/output"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":jadx-core"))
|
||||
compile(project(":jadx-cli"))
|
||||
compile(project(":jadx-core"))
|
||||
compile(project(":jadx-cli"))
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.compilerArgs << '-g:none'
|
||||
options.compilerArgs << '-g:none'
|
||||
}
|
||||
|
||||
task samplesRun(type: JavaExec, dependsOn: compileJava) {
|
||||
classpath = sourceSets.main.output
|
||||
main = mainSamplesClass
|
||||
task samplesRun(type: JavaExec, dependsOn: compileJava) {
|
||||
classpath = sourceSets.main.output
|
||||
main = mainSamplesClass
|
||||
}
|
||||
|
||||
task samplesJar(type: Jar, dependsOn: samplesRun) {
|
||||
baseName = 'samples'
|
||||
from sourceSets.main.output
|
||||
baseName = 'samples'
|
||||
from sourceSets.main.output
|
||||
}
|
||||
|
||||
task samplesJadxCreate(type: JavaExec, dependsOn: samplesJar) {
|
||||
classpath = sourceSets.main.output + configurations.compile
|
||||
main = project(":jadx-cli").mainClassName
|
||||
args = ['-d', samplesJadxSrcDir, samplesJar.archivePath]
|
||||
task samplesJadxCreate(type: JavaExec, dependsOn: samplesJar) {
|
||||
classpath = sourceSets.main.output + configurations.compile
|
||||
main = project(":jadx-cli").mainClassName
|
||||
args = ['-d', samplesJadxSrcDir, samplesJar.archivePath]
|
||||
}
|
||||
|
||||
task samplesJadxCompile(type: JavaCompile, dependsOn: samplesJadxCreate) {
|
||||
classpath = configurations.compile
|
||||
destinationDir = file samplesJadxOutDir
|
||||
source = samplesJadxSrcDir
|
||||
options.encoding = "UTF-8"
|
||||
task samplesJadxCompile(type: JavaCompile, dependsOn: samplesJadxCreate) {
|
||||
classpath = configurations.compile
|
||||
destinationDir = file samplesJadxOutDir
|
||||
source = samplesJadxSrcDir
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
task samplesJadxRun(type: JavaExec, dependsOn: samplesJadxCompile) {
|
||||
classpath = files samplesJadxOutDir
|
||||
main = mainSamplesClass
|
||||
task samplesJadxRun(type: JavaExec, dependsOn: samplesJadxCompile) {
|
||||
classpath = files samplesJadxOutDir
|
||||
main = mainSamplesClass
|
||||
}
|
||||
|
||||
task samples(dependsOn: samplesJadxRun) {
|
||||
}
|
||||
|
||||
task cleanGeneratedFiles(type: Delete) {
|
||||
delete samplesJadxSrcDir
|
||||
delete samplesJadxOutDir
|
||||
delete samplesJadxSrcDir
|
||||
delete samplesJadxOutDir
|
||||
}
|
||||
|
||||
clean.dependsOn cleanGeneratedFiles
|
||||
|
||||
@@ -5,14 +5,14 @@ public class TestInitializers extends AbstractTest {
|
||||
private static String a;
|
||||
private static int counter;
|
||||
private A c_a;
|
||||
|
||||
|
||||
public static class A {
|
||||
public static String a;
|
||||
|
||||
|
||||
static {
|
||||
a = "a1";
|
||||
}
|
||||
|
||||
|
||||
public boolean z() {
|
||||
return true;
|
||||
}
|
||||
@@ -29,11 +29,11 @@ public class TestInitializers extends AbstractTest {
|
||||
b = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public B(int _b) {
|
||||
b = _b;
|
||||
}
|
||||
|
||||
|
||||
public void setB(int _b) {
|
||||
b = _b;
|
||||
}
|
||||
@@ -41,11 +41,11 @@ public class TestInitializers extends AbstractTest {
|
||||
public int getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
public int getBBB() {
|
||||
return bbb;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
bbb = 123;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class TestInitializers extends AbstractTest {
|
||||
a = "a0";
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
c_a = new A();
|
||||
}
|
||||
@@ -90,15 +90,14 @@ public class TestInitializers extends AbstractTest {
|
||||
|
||||
assertTrue((new B()).getB() == -1);
|
||||
assertTrue(counter == 1);
|
||||
|
||||
|
||||
B b3 = new B(3);
|
||||
assertTrue((b3.getB() == 3) && (b3.getBBB() == 123));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new TestInitializers().testRun();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ public class TestInner3 extends AbstractTest {
|
||||
private String i0;
|
||||
|
||||
public class A {
|
||||
|
||||
|
||||
protected String a;
|
||||
|
||||
|
||||
public A() {
|
||||
a="";
|
||||
a = "";
|
||||
}
|
||||
|
||||
public String a() {
|
||||
@@ -39,7 +39,7 @@ public class TestInner3 extends AbstractTest {
|
||||
public String i() {
|
||||
|
||||
String result = TestInner3.this.i0 + I0.this.i0 + I0.this.i1 + i0 + i1 + i2;
|
||||
|
||||
|
||||
A a = new A() {
|
||||
|
||||
public String a() {
|
||||
@@ -82,5 +82,4 @@ public class TestInner3 extends AbstractTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
new TestInner2().testRun();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user