Commit c134837c authored by Jan Peter Stotz's avatar Jan Peter Stotz

pagination for search results.

parent f0a57e67
...@@ -12,11 +12,8 @@ import java.awt.event.MouseAdapter; ...@@ -12,11 +12,8 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.util.ArrayList; import java.util.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
...@@ -30,7 +27,6 @@ import jadx.gui.jobs.BackgroundJob; ...@@ -30,7 +27,6 @@ import jadx.gui.jobs.BackgroundJob;
import jadx.gui.jobs.BackgroundWorker; import jadx.gui.jobs.BackgroundWorker;
import jadx.gui.jobs.DecompileJob; import jadx.gui.jobs.DecompileJob;
import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JNode;
import jadx.gui.treemodel.TextNode;
import jadx.gui.utils.CacheObject; import jadx.gui.utils.CacheObject;
import jadx.gui.utils.NLS; import jadx.gui.utils.NLS;
import jadx.gui.utils.Position; import jadx.gui.utils.Position;
...@@ -41,7 +37,7 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -41,7 +37,7 @@ public abstract class CommonSearchDialog extends JDialog {
private static final Logger LOG = LoggerFactory.getLogger(CommonSearchDialog.class); private static final Logger LOG = LoggerFactory.getLogger(CommonSearchDialog.class);
private static final long serialVersionUID = 8939332306115370276L; private static final long serialVersionUID = 8939332306115370276L;
public static final int MAX_RESULTS_COUNT = 100; public static final int RESULTS_PER_PAGE = 100;
protected final transient TabbedPane tabbedPane; protected final transient TabbedPane tabbedPane;
protected final transient CacheObject cache; protected final transient CacheObject cache;
...@@ -50,6 +46,7 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -50,6 +46,7 @@ public abstract class CommonSearchDialog extends JDialog {
protected ResultsModel resultsModel; protected ResultsModel resultsModel;
protected ResultsTable resultsTable; protected ResultsTable resultsTable;
protected JLabel resultsInfoLabel;
protected JLabel warnLabel; protected JLabel warnLabel;
protected ProgressPanel progressPane; protected ProgressPanel progressPane;
...@@ -94,6 +91,11 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -94,6 +91,11 @@ public abstract class CommonSearchDialog extends JDialog {
}); });
} }
protected synchronized void performSearch() {
resultsTable.updateTable();
updateProgressLabel();
}
protected void openSelectedItem() { protected void openSelectedItem() {
int selectedId = resultsTable.getSelectedRow(); int selectedId = resultsTable.getSelectedRow();
if (selectedId == -1) { if (selectedId == -1) {
...@@ -141,6 +143,7 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -141,6 +143,7 @@ public abstract class CommonSearchDialog extends JDialog {
protected JPanel initResultsTable() { protected JPanel initResultsTable() {
ResultsTableCellRenderer renderer = new ResultsTableCellRenderer(); ResultsTableCellRenderer renderer = new ResultsTableCellRenderer();
resultsModel = new ResultsModel(renderer); resultsModel = new ResultsModel(renderer);
resultsModel.addTableModelListener((e) -> updateProgressLabel());
resultsTable = new ResultsTable(resultsModel); resultsTable = new ResultsTable(resultsModel);
resultsTable.setShowHorizontalLines(false); resultsTable.setShowHorizontalLines(false);
resultsTable.setDragEnabled(false); resultsTable.setDragEnabled(false);
...@@ -149,12 +152,7 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -149,12 +152,7 @@ public abstract class CommonSearchDialog extends JDialog {
resultsTable.setColumnSelectionAllowed(false); resultsTable.setColumnSelectionAllowed(false);
resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
resultsTable.setAutoscrolls(false); resultsTable.setAutoscrolls(false);
resultsTable.setDefaultRenderer(Object.class, renderer);
Enumeration<TableColumn> columns = resultsTable.getColumnModel().getColumns();
while (columns.hasMoreElements()) {
TableColumn column = columns.nextElement();
column.setCellRenderer(renderer);
}
resultsTable.addMouseListener(new MouseAdapter() { resultsTable.addMouseListener(new MouseAdapter() {
@Override @Override
...@@ -183,10 +181,43 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -183,10 +181,43 @@ public abstract class CommonSearchDialog extends JDialog {
resultsPanel.add(new JScrollPane(resultsTable, resultsPanel.add(new JScrollPane(resultsTable,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)); ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
JPanel paginationPanel = new JPanel();
paginationPanel.setAlignmentX( Component.LEFT_ALIGNMENT );
paginationPanel.setLayout(new BoxLayout(paginationPanel, BoxLayout.X_AXIS));
resultsInfoLabel = new JLabel("");
JButton nextPageButton = new JButton("->");
nextPageButton.setToolTipText(NLS.str("search_dialog.next_page"));
nextPageButton.addActionListener((e) -> {
resultsModel.nextPage();
resultsTable.updateTable();
resultsTable.scrollRectToVisible(new Rectangle(0,0,1,1));
});
JButton prevPageButton = new JButton("<-");
prevPageButton.setToolTipText(NLS.str("search_dialog.prev_page"));
prevPageButton.addActionListener((e) -> {
resultsModel.prevPage();
resultsTable.updateTable();
resultsTable.scrollRectToVisible(new Rectangle(0,0,1,1));
});
paginationPanel.add(prevPageButton);
paginationPanel.add(nextPageButton);
paginationPanel.add(resultsInfoLabel);
resultsPanel.add(paginationPanel);
resultsPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); resultsPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
return resultsPanel; return resultsPanel;
} }
protected void updateProgressLabel() {
String statusText = String.format(NLS.str("search_dialog.info_label"), resultsModel.getDisplayedResultsStart(),
resultsModel.getDisplayedResultsEnd(), resultsModel.getResultCount());
resultsInfoLabel.setText(statusText);
}
protected static class ResultsTable extends JTable { protected static class ResultsTable extends JTable {
private static final long serialVersionUID = 3901184054736618969L; private static final long serialVersionUID = 3901184054736618969L;
...@@ -239,23 +270,18 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -239,23 +270,18 @@ public abstract class CommonSearchDialog extends JDialog {
private static final long serialVersionUID = -7821286846923903208L; private static final long serialVersionUID = -7821286846923903208L;
private static final String[] COLUMN_NAMES = {"Node", "Code"}; private static final String[] COLUMN_NAMES = {"Node", "Code"};
private final transient List<JNode> rows = new ArrayList<>(); private final transient ArrayList<JNode> rows = new ArrayList<>();
private final transient ResultsTableCellRenderer renderer; private final transient ResultsTableCellRenderer renderer;
private transient boolean addDescColumn; private transient boolean addDescColumn;
private transient int start = 0;
public ResultsModel(ResultsTableCellRenderer renderer) { public ResultsModel(ResultsTableCellRenderer renderer) {
this.renderer = renderer; this.renderer = renderer;
} }
protected void addAll(Iterable<? extends JNode> nodes) { protected void addAll(Collection<? extends JNode> nodes) {
rows.ensureCapacity(rows.size() + nodes.size());
for (JNode node : nodes) { for (JNode node : nodes) {
int size = getRowCount();
if (size >= MAX_RESULTS_COUNT) {
if (size == MAX_RESULTS_COUNT) {
add(new TextNode("Search results truncated (limit: " + MAX_RESULTS_COUNT + ")"));
}
return;
}
add(node); add(node);
} }
} }
...@@ -268,6 +294,7 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -268,6 +294,7 @@ public abstract class CommonSearchDialog extends JDialog {
} }
public void clear() { public void clear() {
start = 0;
addDescColumn = false; addDescColumn = false;
rows.clear(); rows.clear();
renderer.clear(); renderer.clear();
...@@ -277,9 +304,39 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -277,9 +304,39 @@ public abstract class CommonSearchDialog extends JDialog {
return addDescColumn; return addDescColumn;
} }
public int getResultCount() {
return rows.size();
}
public int getDisplayedResultsStart() {
if (rows.size() == 0)
return 0;
return start + 1;
}
public int getDisplayedResultsEnd() {
return Math.min(rows.size(), start + RESULTS_PER_PAGE);
}
public void nextPage() {
if (start + RESULTS_PER_PAGE < rows.size()) {
renderer.clear();
start += RESULTS_PER_PAGE;
fireTableStructureChanged();
}
}
public void prevPage() {
if (start - RESULTS_PER_PAGE >= 0) {
renderer.clear();
start -= RESULTS_PER_PAGE;
fireTableStructureChanged();
}
}
@Override @Override
public int getRowCount() { public int getRowCount() {
return rows.size(); return rows.size() - start;
} }
@Override @Override
...@@ -294,7 +351,7 @@ public abstract class CommonSearchDialog extends JDialog { ...@@ -294,7 +351,7 @@ public abstract class CommonSearchDialog extends JDialog {
@Override @Override
public Object getValueAt(int rowIndex, int columnIndex) { public Object getValueAt(int rowIndex, int columnIndex) {
return rows.get(rowIndex); return rows.get(rowIndex + start);
} }
} }
......
...@@ -53,17 +53,17 @@ public class SearchDialog extends CommonSearchDialog { ...@@ -53,17 +53,17 @@ public class SearchDialog extends CommonSearchDialog {
searchField.requestFocus(); searchField.requestFocus();
} }
private synchronized void performSearch() { @Override
protected synchronized void performSearch() {
resultsModel.clear(); resultsModel.clear();
String text = searchField.getText(); String text = searchField.getText();
if (text == null || text.isEmpty() || options.isEmpty()) { if (text == null || text.isEmpty() || options.isEmpty()) {
resultsTable.updateTable();
return; return;
} }
try {
cache.setLastSearch(text); cache.setLastSearch(text);
TextSearchIndex index = cache.getTextIndex(); TextSearchIndex index = cache.getTextIndex();
if (index == null) { if (index == null) {
resultsTable.updateTable();
return; return;
} }
boolean caseInsensitive = caseChBox.isSelected(); boolean caseInsensitive = caseChBox.isSelected();
...@@ -81,7 +81,9 @@ public class SearchDialog extends CommonSearchDialog { ...@@ -81,7 +81,9 @@ public class SearchDialog extends CommonSearchDialog {
} }
highlightText = text; highlightText = text;
highlightTextCaseInsensitive = caseInsensitive; highlightTextCaseInsensitive = caseInsensitive;
resultsTable.updateTable(); } finally {
super.performSearch();
}
} }
private class SearchFieldListener implements DocumentListener, ActionListener { private class SearchFieldListener implements DocumentListener, ActionListener {
...@@ -92,7 +94,8 @@ public class SearchDialog extends CommonSearchDialog { ...@@ -92,7 +94,8 @@ public class SearchDialog extends CommonSearchDialog {
if (timer != null) { if (timer != null) {
timer.restart(); timer.restart();
} else { } else {
timer = new Timer(300, this); timer = new Timer(400, this);
timer.setRepeats(false);
timer.start(); timer.start();
} }
} }
......
...@@ -37,7 +37,8 @@ public class UsageDialog extends CommonSearchDialog { ...@@ -37,7 +37,8 @@ public class UsageDialog extends CommonSearchDialog {
// no op // no op
} }
private synchronized void performSearch() { @Override
protected synchronized void performSearch() {
resultsModel.clear(); resultsModel.clear();
CodeUsageInfo usageInfo = cache.getUsageInfo(); CodeUsageInfo usageInfo = cache.getUsageInfo();
...@@ -47,7 +48,7 @@ public class UsageDialog extends CommonSearchDialog { ...@@ -47,7 +48,7 @@ public class UsageDialog extends CommonSearchDialog {
resultsModel.addAll(usageInfo.getUsageList(node)); resultsModel.addAll(usageInfo.getUsageList(node));
// TODO: highlight only needed node usage // TODO: highlight only needed node usage
highlightText = null; highlightText = null;
resultsTable.updateTable(); super.performSearch();
} }
private void initUI() { private void initUI() {
......
...@@ -106,7 +106,7 @@ public class TextSearchIndex { ...@@ -106,7 +106,7 @@ public class TextSearchIndex {
while (pos != -1) { while (pos != -1) {
pos = searchNext(list, text, javaClass, code, pos); pos = searchNext(list, text, javaClass, code, pos);
} }
if (list.size() > CommonSearchDialog.MAX_RESULTS_COUNT) { if (list.size() > CommonSearchDialog.RESULTS_PER_PAGE) {
return; return;
} }
} }
......
...@@ -51,6 +51,9 @@ search_dialog.field=Field ...@@ -51,6 +51,9 @@ search_dialog.field=Field
search_dialog.code=Code search_dialog.code=Code
search_dialog.options=Search options \: search_dialog.options=Search options \:
search_dialog.ignorecase=Case insensitive search_dialog.ignorecase=Case insensitive
search_dialog.next_page=Show next page
search_dialog.prev_page=Show previous page
search_dialog.info_label=Showing results %d to %d of %d
usage_dialog.title=Usage search usage_dialog.title=Usage search
usage_dialog.label=Usage for: usage_dialog.label=Usage for:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment