fix(gui): show skipped resources count during search (#1808)
This commit is contained in:
@@ -5,6 +5,7 @@ import java.util.regex.Pattern;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
|
||||
public class SearchSettings {
|
||||
|
||||
@@ -13,6 +14,7 @@ public class SearchSettings {
|
||||
private final boolean ignoreCase;
|
||||
|
||||
private JClass activeCls;
|
||||
private JResource activeResource;
|
||||
private Pattern regexPattern;
|
||||
private ISearchMethod searchMethod;
|
||||
|
||||
@@ -64,6 +66,14 @@ public class SearchSettings {
|
||||
this.activeCls = activeCls;
|
||||
}
|
||||
|
||||
public JResource getActiveResource() {
|
||||
return activeResource;
|
||||
}
|
||||
|
||||
public void setActiveResource(JResource activeResource) {
|
||||
this.activeResource = activeResource;
|
||||
}
|
||||
|
||||
public ISearchMethod getSearchMethod() {
|
||||
return searchMethod;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.gui.search.providers;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
@@ -24,12 +25,15 @@ import jadx.gui.treemodel.JResSearchNode;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
import jadx.gui.treemodel.JRoot;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.dialog.SearchDialog;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class ResourceSearchProvider implements ISearchProvider {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ResourceSearchProvider.class);
|
||||
|
||||
private final SearchSettings searchSettings;
|
||||
private final Set<String> extSet;
|
||||
private final SearchDialog searchDialog;
|
||||
private final int sizeLimit;
|
||||
private boolean anyExt;
|
||||
|
||||
@@ -39,11 +43,20 @@ public class ResourceSearchProvider implements ISearchProvider {
|
||||
private final Deque<JResource> resQueue;
|
||||
private int pos;
|
||||
|
||||
public ResourceSearchProvider(MainWindow mw, SearchSettings searchSettings) {
|
||||
private int loadErrors = 0;
|
||||
private int skipBySize = 0;
|
||||
|
||||
public ResourceSearchProvider(MainWindow mw, SearchSettings searchSettings, SearchDialog searchDialog) {
|
||||
this.searchSettings = searchSettings;
|
||||
this.sizeLimit = mw.getSettings().getSrhResourceSkipSize() * 1048576;
|
||||
this.extSet = buildAllowedFilesExtensions(mw.getSettings().getSrhResourceFileExt());
|
||||
this.resQueue = initResQueue(mw);
|
||||
this.searchDialog = searchDialog;
|
||||
JResource activeResource = searchSettings.getActiveResource();
|
||||
if (activeResource != null) {
|
||||
this.resQueue = new ArrayDeque<>(Collections.singleton(activeResource));
|
||||
} else {
|
||||
this.resQueue = initResQueue(mw);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,32 +106,49 @@ public class ResourceSearchProvider implements ISearchProvider {
|
||||
private @Nullable JResource getNextResFile(Cancelable cancelable) {
|
||||
while (true) {
|
||||
JResource node = resQueue.peekLast();
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
node.loadNode();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error load resource node: {}", node, e);
|
||||
resQueue.removeLast();
|
||||
continue;
|
||||
}
|
||||
if (cancelable.isCanceled()) {
|
||||
if (node == null || cancelable.isCanceled()) {
|
||||
return null;
|
||||
}
|
||||
if (node.getType() == JResource.JResType.FILE) {
|
||||
if (shouldProcess(node)) {
|
||||
if (shouldProcess(node) && loadResNode(node)) {
|
||||
return node;
|
||||
}
|
||||
resQueue.removeLast();
|
||||
} else {
|
||||
// dir
|
||||
resQueue.removeLast();
|
||||
loadResNode(node);
|
||||
addChildren(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgressInfo() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (loadErrors != 0) {
|
||||
sb.append(" ").append(NLS.str("search_dialog.resources_load_errors", loadErrors));
|
||||
}
|
||||
if (skipBySize != 0) {
|
||||
sb.append(" ").append(NLS.str("search_dialog.resources_skip_by_size", skipBySize));
|
||||
}
|
||||
if (sb.length() != 0) {
|
||||
sb.append(" ").append(NLS.str("search_dialog.resources_check_logs"));
|
||||
}
|
||||
searchDialog.updateProgressLabel(sb.toString());
|
||||
}
|
||||
|
||||
private boolean loadResNode(JResource node) {
|
||||
try {
|
||||
node.loadNode();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error load resource node: {}", node, e);
|
||||
loadErrors++;
|
||||
updateProgressInfo();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void addChildren(JResource resNode) {
|
||||
resQueue.addAll(resNode.getSubNodes());
|
||||
}
|
||||
@@ -167,19 +197,24 @@ public class ResourceSearchProvider implements ISearchProvider {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (sizeLimit == 0) {
|
||||
if (sizeLimit <= 0) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
int charsCount = resNode.getCodeInfo().getCodeStr().length();
|
||||
long size = charsCount * 8L;
|
||||
if (size > sizeLimit) {
|
||||
LOG.debug("Resource search skipped because of size limit: {} res size {} bytes", resNode, size);
|
||||
LOG.info("Resource search skipped because of size limit. Resource '{}' size {} bytes, limit: {}",
|
||||
resNode.getName(), size, sizeLimit);
|
||||
skipBySize++;
|
||||
updateProgressInfo();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Resource load error: {}", resNode, e);
|
||||
loadErrors++;
|
||||
updateProgressInfo();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.api.metadata.annotations.NodeDeclareRef;
|
||||
@@ -78,6 +80,7 @@ public abstract class CommonSearchDialog extends JFrame {
|
||||
protected ResultsModel resultsModel;
|
||||
protected ResultsTable resultsTable;
|
||||
protected JLabel resultsInfoLabel;
|
||||
protected JLabel progressInfoLabel;
|
||||
protected JLabel warnLabel;
|
||||
protected ProgressPanel progressPane;
|
||||
|
||||
@@ -297,6 +300,15 @@ public abstract class CommonSearchDialog extends JFrame {
|
||||
resultsInfoLabel = new JLabel("");
|
||||
resultsInfoLabel.setFont(mainWindow.getSettings().getFont());
|
||||
|
||||
progressInfoLabel = new JLabel("");
|
||||
progressInfoLabel.setFont(mainWindow.getSettings().getFont());
|
||||
progressInfoLabel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
LogViewerDialog.openWithLevel(mainWindow, Level.INFO);
|
||||
}
|
||||
});
|
||||
|
||||
JPanel resultsActionsPanel = new JPanel();
|
||||
resultsActionsPanel.setLayout(new BoxLayout(resultsActionsPanel, BoxLayout.LINE_AXIS));
|
||||
resultsActionsPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
|
||||
@@ -313,6 +325,8 @@ public abstract class CommonSearchDialog extends JFrame {
|
||||
protected void addResultsActions(JPanel resultsActionsPanel) {
|
||||
resultsActionsPanel.add(Box.createRigidArea(new Dimension(20, 0)));
|
||||
resultsActionsPanel.add(resultsInfoLabel);
|
||||
resultsActionsPanel.add(Box.createRigidArea(new Dimension(20, 0)));
|
||||
resultsActionsPanel.add(progressInfoLabel);
|
||||
resultsActionsPanel.add(Box.createHorizontalGlue());
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ import jadx.gui.search.providers.MethodSearchProvider;
|
||||
import jadx.gui.search.providers.ResourceSearchProvider;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.JumpPosition;
|
||||
import jadx.gui.utils.NLS;
|
||||
@@ -452,9 +453,18 @@ public class SearchDialog extends CommonSearchDialog {
|
||||
resultsInfoLabel.setText("Can't search in current tab");
|
||||
return false;
|
||||
}
|
||||
JClass activeCls = currentPos.getNode().getRootClass();
|
||||
searchSettings.setActiveCls(activeCls);
|
||||
allClasses = Collections.singletonList(activeCls.getCls());
|
||||
JNode currentNode = currentPos.getNode();
|
||||
if (currentNode instanceof JClass) {
|
||||
JClass activeCls = currentNode.getRootClass();
|
||||
searchSettings.setActiveCls(activeCls);
|
||||
allClasses = Collections.singletonList(activeCls.getCls());
|
||||
} else if (currentNode instanceof JResource) {
|
||||
searchSettings.setActiveResource((JResource) currentNode);
|
||||
allClasses = Collections.emptyList();
|
||||
} else {
|
||||
resultsInfoLabel.setText("Can't search in current tab");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
allClasses = mainWindow.getWrapper().getIncludedClassesWithInners();
|
||||
}
|
||||
@@ -475,9 +485,10 @@ public class SearchDialog extends CommonSearchDialog {
|
||||
merged.add(new FieldSearchProvider(mainWindow, searchSettings, allClasses));
|
||||
}
|
||||
if (options.contains(CODE)) {
|
||||
if (allClasses.size() == 1) {
|
||||
int clsCount = allClasses.size();
|
||||
if (clsCount == 1) {
|
||||
newSearchTask.addProviderJob(new CodeSearchProvider(mainWindow, searchSettings, allClasses));
|
||||
} else {
|
||||
} else if (clsCount > 1) {
|
||||
List<List<JavaClass>> batches = mainWindow.getCacheObject().getDecompileBatches();
|
||||
if (batches == null) {
|
||||
List<JavaClass> topClasses = ListUtils.filter(allClasses, c -> !c.isInner());
|
||||
@@ -490,7 +501,7 @@ public class SearchDialog extends CommonSearchDialog {
|
||||
}
|
||||
}
|
||||
if (options.contains(RESOURCE)) {
|
||||
newSearchTask.addProviderJob(new ResourceSearchProvider(mainWindow, searchSettings));
|
||||
newSearchTask.addProviderJob(new ResourceSearchProvider(mainWindow, searchSettings, this));
|
||||
}
|
||||
if (options.contains(COMMENT)) {
|
||||
newSearchTask.addProviderJob(new CommentSearchProvider(mainWindow, searchSettings));
|
||||
@@ -549,6 +560,7 @@ public class SearchDialog extends CommonSearchDialog {
|
||||
synchronized (pendingResults) {
|
||||
pendingResults.clear();
|
||||
}
|
||||
updateProgressLabel("");
|
||||
progressPane.setVisible(false);
|
||||
warnLabel.setVisible(false);
|
||||
loadAllButton.setEnabled(false);
|
||||
@@ -598,6 +610,10 @@ public class SearchDialog extends CommonSearchDialog {
|
||||
});
|
||||
}
|
||||
|
||||
public void updateProgressLabel(String text) {
|
||||
UiUtils.uiRun(() -> progressInfoLabel.setText(text));
|
||||
}
|
||||
|
||||
private void searchFinished(ITaskInfo status, Boolean complete) {
|
||||
UiUtils.uiThreadGuard();
|
||||
LOG.debug("Search complete: {}, complete: {}", status, complete);
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=Alle laden
|
||||
#search_dialog.stop=Stop
|
||||
search_dialog.results_incomplete=%d+ gefunden
|
||||
search_dialog.results_complete=%d gefunden (komplett)
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=Knoten
|
||||
search_dialog.col_code=Code
|
||||
#search_dialog.sort_results=Sort results
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=Load all
|
||||
search_dialog.stop=Stop
|
||||
search_dialog.results_incomplete=Found %d+
|
||||
search_dialog.results_complete=Found %d (complete)
|
||||
search_dialog.resources_load_errors=Load errors: %d
|
||||
search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=Node
|
||||
search_dialog.col_code=Code
|
||||
search_dialog.sort_results=Sort results
|
||||
@@ -200,7 +203,7 @@ preferences.rename_printable=To make printable
|
||||
preferences.search_group_title=Search
|
||||
preferences.search_results_per_page=Results per page (0 - no limit)
|
||||
preferences.res_file_ext=Resource files extensions ('xml|html', * for all)
|
||||
preferences.res_skip_file=Skip resources files if larger (MB)
|
||||
preferences.res_skip_file=Skip resources files if larger (MB) (0 - disable)
|
||||
|
||||
msg.open_file=Please open file
|
||||
msg.saving_sources=Saving sources
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.ignorecase=Ignorar minúsculas/mayúsculas
|
||||
#search_dialog.stop=Stop
|
||||
#search_dialog.results_incomplete=Found %d+
|
||||
#search_dialog.results_complete=Found %d (complete)
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=Nodo
|
||||
search_dialog.col_code=Código
|
||||
#search_dialog.sort_results=Sort results
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=모두 로드
|
||||
search_dialog.stop=정지
|
||||
search_dialog.results_incomplete=%d+개 찾음
|
||||
search_dialog.results_complete=%d개 찾음 (검색 완료)
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=노드
|
||||
search_dialog.col_code=코드
|
||||
search_dialog.sort_results=결과 정렬
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=Carregar todas
|
||||
search_dialog.stop=Parar
|
||||
search_dialog.results_incomplete=Encontradas %d+
|
||||
search_dialog.results_complete=Encontradas %d (completos)
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=Nó
|
||||
search_dialog.col_code=Código
|
||||
search_dialog.sort_results=Ordenar resultados
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=Загрузить все
|
||||
search_dialog.stop=Стоп
|
||||
search_dialog.results_incomplete=Найдено %d+
|
||||
search_dialog.results_complete=Найдено %d (поиск завершен)
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=Вхождения
|
||||
search_dialog.col_code=Код
|
||||
search_dialog.sort_results=Сортировка результатов
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=加载所有
|
||||
search_dialog.stop=停止
|
||||
search_dialog.results_incomplete=已找到 %d+
|
||||
search_dialog.results_complete=全部找到 %d
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=节点
|
||||
search_dialog.col_code=代码
|
||||
search_dialog.sort_results=结果分类
|
||||
|
||||
@@ -112,6 +112,9 @@ search_dialog.load_all=載入全部
|
||||
search_dialog.stop=停止
|
||||
search_dialog.results_incomplete=找到 %d+
|
||||
search_dialog.results_complete=找到 %d (完整)
|
||||
#search_dialog.resources_load_errors=Load errors: %d
|
||||
#search_dialog.resources_skip_by_size=Skipped by size: %d
|
||||
#search_dialog.resources_check_logs=(click to check logs)
|
||||
search_dialog.col_node=無
|
||||
search_dialog.col_code=程式碼
|
||||
search_dialog.sort_results=排序結果
|
||||
|
||||
Reference in New Issue
Block a user