feat(gui): add option to change line numbers mode (#1223)
This commit is contained in:
@@ -78,6 +78,7 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
private String srhResourceFileExt = ".xml|.html|.js|.json|.txt";
|
||||
private boolean keepCommonDialogOpen = false;
|
||||
private boolean smaliAreaShowBytecode = false;
|
||||
private LineNumbersMode lineNumbersMode = LineNumbersMode.AUTO;
|
||||
|
||||
private int mainWindowVerticalSplitterLoc = 300;
|
||||
private int debuggerStackFrameSplitterLoc = 300;
|
||||
@@ -556,6 +557,14 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
this.commentsLevel = level;
|
||||
}
|
||||
|
||||
public LineNumbersMode getLineNumbersMode() {
|
||||
return lineNumbersMode;
|
||||
}
|
||||
|
||||
public void setLineNumbersMode(LineNumbersMode lineNumbersMode) {
|
||||
this.lineNumbersMode = lineNumbersMode;
|
||||
}
|
||||
|
||||
private void upgradeSettings(int fromVersion) {
|
||||
LOG.debug("upgrade settings from version: {} to {}", fromVersion, CURRENT_SETTINGS_VERSION);
|
||||
if (fromVersion == 0) {
|
||||
|
||||
@@ -537,6 +537,13 @@ public class JadxSettingsWindow extends JDialog {
|
||||
}
|
||||
languageCbx.addActionListener(e -> settings.setLangLocale((LangLocale) languageCbx.getSelectedItem()));
|
||||
|
||||
JComboBox<LineNumbersMode> lineNumbersMode = new JComboBox<>(LineNumbersMode.values());
|
||||
lineNumbersMode.setSelectedItem(settings.getLineNumbersMode());
|
||||
lineNumbersMode.addActionListener(e -> {
|
||||
settings.setLineNumbersMode((LineNumbersMode) lineNumbersMode.getSelectedItem());
|
||||
mainWindow.loadSettings();
|
||||
});
|
||||
|
||||
JCheckBox update = new JCheckBox();
|
||||
update.setSelected(settings.isCheckForUpdates());
|
||||
update.addItemListener(e -> settings.setCheckForUpdates(e.getStateChange() == ItemEvent.SELECTED));
|
||||
@@ -557,6 +564,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
|
||||
SettingsGroup group = new SettingsGroup(NLS.str("preferences.other"));
|
||||
group.addRow(NLS.str("preferences.language"), languageCbx);
|
||||
group.addRow(NLS.str("preferences.lineNumbersMode"), lineNumbersMode);
|
||||
group.addRow(NLS.str("preferences.check_for_updates"), update);
|
||||
group.addRow(NLS.str("preferences.cfg"), cfg);
|
||||
group.addRow(NLS.str("preferences.raw_cfg"), rawCfg);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package jadx.gui.settings;
|
||||
|
||||
public enum LineNumbersMode {
|
||||
DISABLE,
|
||||
NORMAL,
|
||||
DEBUG,
|
||||
AUTO
|
||||
}
|
||||
@@ -21,12 +21,15 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
|
||||
import org.fife.ui.rtextarea.Gutter;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.LineNumbersMode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.dialog.SearchDialog;
|
||||
import jadx.gui.utils.CaretPositionFix;
|
||||
@@ -44,12 +47,11 @@ public class CodePanel extends JPanel {
|
||||
private final SearchBar searchBar;
|
||||
private final AbstractCodeArea codeArea;
|
||||
private final JScrollPane codeScrollPane;
|
||||
private LineNumbers lineNumbers;
|
||||
|
||||
public CodePanel(AbstractCodeArea codeArea) {
|
||||
this.codeArea = codeArea;
|
||||
searchBar = new SearchBar(codeArea);
|
||||
codeScrollPane = codeArea instanceof SmaliArea ? new RTextScrollPane(codeArea) : new JScrollPane(codeArea);
|
||||
this.searchBar = new SearchBar(codeArea);
|
||||
this.codeScrollPane = buildCodeScrollPane(codeArea);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
@@ -116,23 +118,43 @@ public class CodePanel extends JPanel {
|
||||
initLineNumbers();
|
||||
}
|
||||
|
||||
private JScrollPane buildCodeScrollPane(AbstractCodeArea codeArea) {
|
||||
if (codeArea instanceof SmaliArea) {
|
||||
return new RTextScrollPane(codeArea);
|
||||
}
|
||||
return new JScrollPane(codeArea);
|
||||
}
|
||||
|
||||
private void initLineNumbers() {
|
||||
if (codeArea instanceof SmaliArea) {
|
||||
return;
|
||||
}
|
||||
initLineNumbers(isUseSourceLines());
|
||||
}
|
||||
|
||||
private void initLineNumbers(boolean useSourceLines) {
|
||||
lineNumbers = new LineNumbers(codeArea);
|
||||
lineNumbers.setUseSourceLines(useSourceLines);
|
||||
codeScrollPane.setRowHeaderView(lineNumbers);
|
||||
}
|
||||
|
||||
private boolean isUseSourceLines() {
|
||||
if (codeArea instanceof SmaliArea) {
|
||||
return false;
|
||||
LineNumbersMode mode = getSettings().getLineNumbersMode();
|
||||
boolean canShowDebugLines = canShowDebugLines();
|
||||
if (mode == LineNumbersMode.AUTO) {
|
||||
mode = canShowDebugLines ? LineNumbersMode.DEBUG : LineNumbersMode.NORMAL;
|
||||
} else if (mode == LineNumbersMode.DEBUG && !canShowDebugLines) {
|
||||
// nothing to show => hide lines view
|
||||
mode = LineNumbersMode.DISABLE;
|
||||
}
|
||||
switch (mode) {
|
||||
case DISABLE:
|
||||
codeScrollPane.setRowHeaderView(null);
|
||||
break;
|
||||
case NORMAL:
|
||||
Gutter gutter = new Gutter(codeArea);
|
||||
gutter.setLineNumberFont(getSettings().getFont());
|
||||
codeScrollPane.setRowHeaderView(gutter);
|
||||
break;
|
||||
case DEBUG:
|
||||
LineNumbers jadxGutter = new LineNumbers(codeArea);
|
||||
jadxGutter.setUseSourceLines(true);
|
||||
codeScrollPane.setRowHeaderView(jadxGutter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canShowDebugLines() {
|
||||
ICodeInfo codeInfo = codeArea.getNode().getCodeInfo();
|
||||
if (codeInfo == null) {
|
||||
return false;
|
||||
@@ -141,8 +163,8 @@ public class CodePanel extends JPanel {
|
||||
if (lineMapping.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Set<Integer> uniqueSourceLines = new HashSet<>(lineMapping.values());
|
||||
return uniqueSourceLines.size() > 3;
|
||||
Set<Integer> uniqueDebugLines = new HashSet<>(lineMapping.values());
|
||||
return uniqueDebugLines.size() > 3;
|
||||
}
|
||||
|
||||
public SearchBar getSearchBar() {
|
||||
@@ -161,11 +183,16 @@ public class CodePanel extends JPanel {
|
||||
JViewport viewport = getCodeScrollPane().getViewport();
|
||||
Point viewPosition = viewport.getViewPosition();
|
||||
codeArea.refresh();
|
||||
initLineNumbers(lineNumbers.isUseSourceLines());
|
||||
initLineNumbers();
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
viewport.setViewPosition(viewPosition);
|
||||
caretFix.restore();
|
||||
});
|
||||
}
|
||||
|
||||
private JadxSettings getSettings() {
|
||||
return this.codeArea.getContentPanel().getTabbedPane()
|
||||
.getMainWindow().getSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
private void setPreferredWidth() {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int lines = root.getElementCount();
|
||||
int digits = Math.max(String.valueOf(lines).length(), 4);
|
||||
int digits = Math.max(numberLength(lines), numberLength(getMaxDebugLine()));
|
||||
if (lastDigits != digits) {
|
||||
lastDigits = digits;
|
||||
FontMetrics fontMetrics = getFontMetrics(getFont());
|
||||
@@ -109,6 +109,10 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
}
|
||||
}
|
||||
|
||||
private int numberLength(int value) {
|
||||
return String.valueOf(value).length();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
@@ -255,6 +259,11 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
return String.valueOf(sourceLine);
|
||||
}
|
||||
|
||||
private int getMaxDebugLine() {
|
||||
return codeInfo.getLineMapping().keySet().stream()
|
||||
.mapToInt(Integer::intValue).max().orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
|
||||
@@ -119,6 +119,7 @@ preferences.decompile=Dekompilierung
|
||||
preferences.project=Projekt
|
||||
preferences.other=Andere
|
||||
preferences.language=Sprachen
|
||||
#preferences.lineNumbersMode=Editor line numbers mode
|
||||
preferences.check_for_updates=Nach Updates beim Start suchen
|
||||
preferences.fallback=Zwischencode ausgeben (einfacher Speicherauszug)
|
||||
preferences.showInconsistentCode=Inkonsistenten Code anzeigen
|
||||
|
||||
@@ -119,6 +119,7 @@ preferences.decompile=Decompilation
|
||||
preferences.project=Project
|
||||
preferences.other=Other
|
||||
preferences.language=Language
|
||||
preferences.lineNumbersMode=Editor line numbers mode
|
||||
preferences.check_for_updates=Check for updates on startup
|
||||
preferences.fallback=Fallback mode (simple dump)
|
||||
preferences.showInconsistentCode=Show inconsistent code
|
||||
|
||||
@@ -119,6 +119,7 @@ preferences.decompile=Descompilación
|
||||
#preferences.project=
|
||||
preferences.other=Otros
|
||||
preferences.language=Idioma
|
||||
#preferences.lineNumbersMode=Editor line numbers mode
|
||||
preferences.check_for_updates=Buscar actualizaciones al iniciar
|
||||
preferences.fallback=Modo fallback (simple dump)
|
||||
preferences.showInconsistentCode=Mostrar código inconsistente
|
||||
|
||||
@@ -119,6 +119,7 @@ preferences.decompile=디컴파일
|
||||
preferences.project=프로젝트
|
||||
preferences.other=기타
|
||||
preferences.language=언어
|
||||
#preferences.lineNumbersMode=Editor line numbers mode
|
||||
preferences.check_for_updates=시작시 업데이트 확인
|
||||
preferences.fallback=대체 모드 (단순 덤프)
|
||||
preferences.showInconsistentCode=디컴파일 안된 코드 표시
|
||||
|
||||
@@ -119,6 +119,7 @@ preferences.decompile=反编译
|
||||
preferences.project=项目
|
||||
preferences.other=其他
|
||||
preferences.language=语言
|
||||
#preferences.lineNumbersMode=Editor line numbers mode
|
||||
preferences.check_for_updates=启动时检查更新
|
||||
preferences.fallback=输出中间代码
|
||||
preferences.showInconsistentCode=显示不一致的代码
|
||||
|
||||
Reference in New Issue
Block a user