diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index a04e78f253eef3b07dd400c8878ae39cfddef5c2..c8b154cf1ea2cbe212266b2a59682f8c2ecad513 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -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) { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java index 0dbc9c4af70936f04d70e1220d7fe9c965cc247f..e6f4a60756deddc016dfd736d6052915fb52d9df 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java @@ -537,6 +537,13 @@ public class JadxSettingsWindow extends JDialog { } languageCbx.addActionListener(e -> settings.setLangLocale((LangLocale) languageCbx.getSelectedItem())); + JComboBox 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); diff --git a/jadx-gui/src/main/java/jadx/gui/settings/LineNumbersMode.java b/jadx-gui/src/main/java/jadx/gui/settings/LineNumbersMode.java new file mode 100644 index 0000000000000000000000000000000000000000..cb730c17a9457144db1d9ce4ab501b568fddfb79 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/settings/LineNumbersMode.java @@ -0,0 +1,8 @@ +package jadx.gui.settings; + +public enum LineNumbersMode { + DISABLE, + NORMAL, + DEBUG, + AUTO +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java index 5bab58d60ac88a22330a56a5b915d10fbdc6273f..2d6f70ddc5713a3eea03a0b7c570a0b7c10cfc46 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java @@ -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 void initLineNumbers() { + private JScrollPane buildCodeScrollPane(AbstractCodeArea codeArea) { if (codeArea instanceof SmaliArea) { - return; + return new RTextScrollPane(codeArea); } - initLineNumbers(isUseSourceLines()); - } - - private void initLineNumbers(boolean useSourceLines) { - lineNumbers = new LineNumbers(codeArea); - lineNumbers.setUseSourceLines(useSourceLines); - codeScrollPane.setRowHeaderView(lineNumbers); + return new JScrollPane(codeArea); } - private boolean isUseSourceLines() { + private void initLineNumbers() { if (codeArea instanceof SmaliArea) { - return false; + return; } + 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 uniqueSourceLines = new HashSet<>(lineMapping.values()); - return uniqueSourceLines.size() > 3; + Set 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(); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java index 4fcaa7b53e35c6a9f32f15777d259da62dfe9d93..a1941e72e74396c6ba22ff6b3338fa63d5133363 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java @@ -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(); diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index 76145b96b8d1ccf2fb8669032411902165191e55..8b12fae0d085d305f3ce9185fc2b7460c0c1a3ad 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -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 diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 53b8b16d1a11136727b1b01c450489d2bf83e33a..ecc31344c75bad0fa1d4c715b8c4a8ff110a941a 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -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 diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index e6df6293fd73afa02b754e5c4ec39abeb484dd84..550700d842bf9dcf09a3b852c7c4484e07df6e19 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -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 diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index 17ff585613b6d94146f1d5a98c977fee48f01eb4..45e517e474b29675f98cd44b014716cc81b23072 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -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=디컴파일 안된 코드 표시 diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index 8fc6a5307d8f4c2e042fe0767584f51275c6b5c4..a07ecfadb9c1d4f2755a9459a391277c4561ffce 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -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=显示不一致的代码