|
1 | 1 | package club.bytecode.the.jda.gui.search; |
2 | 2 |
|
3 | | -import club.bytecode.the.jda.FileContainer; |
4 | 3 | import club.bytecode.the.jda.JDA; |
| 4 | +import club.bytecode.the.jda.gui.components.SortedUniqueListModel; |
5 | 5 | import club.bytecode.the.jda.gui.fileviewer.ViewerFile; |
6 | 6 | import club.bytecode.the.jda.settings.Settings; |
7 | 7 | import net.miginfocom.swing.MigLayout; |
8 | | -import org.mapleir.stdlib.util.Pair; |
9 | 8 |
|
10 | 9 | import javax.swing.*; |
| 10 | +import javax.swing.event.DocumentEvent; |
| 11 | +import javax.swing.event.DocumentListener; |
11 | 12 | import java.awt.*; |
| 13 | +import java.awt.event.KeyEvent; |
| 14 | +import java.awt.event.KeyListener; |
12 | 15 | import java.awt.event.MouseAdapter; |
13 | 16 | import java.awt.event.MouseEvent; |
| 17 | +import java.util.Iterator; |
14 | 18 | import java.util.List; |
15 | 19 |
|
16 | 20 | public class SearchDialog extends JDialog { |
| 21 | + private final List<ViewerFile> searchResults; |
| 22 | + private final JList<ViewerFile> list; |
| 23 | + private final JTextArea searchBox; |
| 24 | + |
| 25 | + private String oldFilter = ""; |
| 26 | + |
17 | 27 | public SearchDialog(String needle, List<ViewerFile> matches) { |
18 | 28 | super(new JFrame(), "Search Results", true); |
| 29 | + searchResults = matches; |
19 | 30 | Container pane = getContentPane(); |
20 | 31 | pane.setPreferredSize(new Dimension(850, 400)); |
21 | 32 | pane.setLayout(new MigLayout("fill")); |
22 | 33 | pane.add(new JLabel(needle + " found in:"), "pushx, growx, wrap"); |
23 | | - JList<Pair<FileContainer, String>> list = new JList(matches.toArray()); |
| 34 | + list = new JList<>(createSortedListModel()); |
24 | 35 | list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); |
25 | 36 | list.setLayoutOrientation(JList.VERTICAL); |
| 37 | + |
26 | 38 | list.addMouseListener(new MouseAdapter() { |
27 | 39 | public void mouseClicked(MouseEvent evt) { |
28 | 40 | JList list = (JList)evt.getSource(); |
29 | 41 | if (evt.getClickCount() == 2) { |
30 | 42 | int index = list.locationToIndex(evt.getPoint()); |
31 | | - ViewerFile vf = matches.get(index); |
32 | | - JDA.viewer.navigator.openClassFileToWorkSpace(vf); |
| 43 | + openResult(index); |
| 44 | + } |
| 45 | + } |
| 46 | + }); |
| 47 | + |
| 48 | + searchBox = new JTextArea(); |
| 49 | + searchBox.setRows(1); |
| 50 | + searchBox.addKeyListener(new KeyListener() { |
| 51 | + @Override |
| 52 | + public void keyTyped(KeyEvent e) { |
| 53 | + } |
| 54 | + |
| 55 | + @Override |
| 56 | + public void keyPressed(KeyEvent e) { |
| 57 | + if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
| 58 | + e.consume(); |
| 59 | + list.requestFocus(); |
33 | 60 | } |
34 | 61 | } |
| 62 | + |
| 63 | + @Override |
| 64 | + public void keyReleased(KeyEvent e) { |
| 65 | + } |
| 66 | + }); |
| 67 | + |
| 68 | + searchBox.getDocument().addDocumentListener(new DocumentListener(){ |
| 69 | + @Override public void insertUpdate(DocumentEvent e) { filter(); } |
| 70 | + @Override public void removeUpdate(DocumentEvent e) { filter(); } |
| 71 | + @Override public void changedUpdate(DocumentEvent e) {} |
| 72 | + private void filter() { |
| 73 | + String filter = searchBox.getText(); |
| 74 | + updateFilter((SortedUniqueListModel<ViewerFile>) list.getModel(), filter); |
| 75 | + oldFilter = filter; |
| 76 | + } |
| 77 | + }); |
| 78 | + |
| 79 | + list.addKeyListener(new KeyListener() { |
| 80 | + @Override |
| 81 | + public void keyTyped(KeyEvent e) { |
| 82 | + if (e.getKeyChar() == '\n') e.consume(); |
| 83 | + else focusSearch(e); |
| 84 | + } |
| 85 | + |
| 86 | + @Override |
| 87 | + public void keyPressed(KeyEvent e) { |
| 88 | + if (e.getKeyCode() == KeyEvent.VK_ENTER) openResult(list.getSelectedIndex()); |
| 89 | + else focusSearch(e); |
| 90 | + } |
| 91 | + |
| 92 | + @Override |
| 93 | + public void keyReleased(KeyEvent e) { |
| 94 | + if (e.getKeyCode() == KeyEvent.VK_ENTER) e.consume(); |
| 95 | + else focusSearch(e); |
| 96 | + } |
35 | 97 | }); |
| 98 | + |
36 | 99 | list.setFont(Settings.getCodeFont()); |
37 | 100 | JScrollPane listScroller = new JScrollPane(list); |
38 | | - pane.add(listScroller, "grow, push"); |
| 101 | + |
| 102 | + pane.add(listScroller, "grow, push, wrap"); |
| 103 | + pane.add(searchBox, "grow"); |
39 | 104 | pack(); |
40 | 105 | } |
| 106 | + |
| 107 | + public void openResult(int index) { |
| 108 | + ViewerFile vf = searchResults.get(index); |
| 109 | + JDA.viewer.navigator.openClassFileToWorkSpace(vf); |
| 110 | + } |
| 111 | + |
| 112 | + public void focusSearch(KeyEvent e) { |
| 113 | + searchBox.setText(""); |
| 114 | + searchBox.requestFocus(); |
| 115 | + forwardKeyEvent(searchBox, e); |
| 116 | + } |
| 117 | + |
| 118 | + private void forwardKeyEvent(Component receiver, KeyEvent e) { |
| 119 | + receiver.dispatchEvent(new KeyEvent(receiver, e.getID(), e.getWhen(), e.getModifiers(), e.getKeyCode(), e.getKeyChar())); |
| 120 | + } |
| 121 | + |
| 122 | + private ListModel<ViewerFile> createSortedListModel() { |
| 123 | + SortedUniqueListModel<ViewerFile> model = new SortedUniqueListModel<>(); |
| 124 | + model.addAll(searchResults); |
| 125 | + return model; |
| 126 | + } |
| 127 | + |
| 128 | + public void updateFilter(SortedUniqueListModel<ViewerFile> model, String filter) { |
| 129 | + if (oldFilter.equals(filter)) |
| 130 | + return; |
| 131 | + |
| 132 | + if (filter.isEmpty()) { |
| 133 | + model.deferUpdates(); |
| 134 | + model.clear(); |
| 135 | + model.addAll(searchResults); |
| 136 | + model.commitUpdates(); |
| 137 | + return; |
| 138 | + } |
| 139 | + |
| 140 | + model.deferUpdates(); // make sure to commit me |
| 141 | + String filterLower = filter.toLowerCase(); |
| 142 | + String oldFilterLower = oldFilter.toLowerCase(); |
| 143 | + if (oldFilterLower.contains(filterLower)) { |
| 144 | + for (ViewerFile vf : searchResults) { |
| 145 | + String s = vf.toString().toLowerCase(); |
| 146 | + if (s.contains(filterLower)) { |
| 147 | + model.add(vf); |
| 148 | + } |
| 149 | + } |
| 150 | + } else if (filterLower.contains(oldFilterLower)) { |
| 151 | + for (Iterator<ViewerFile> it = model.iterator(); it.hasNext(); ) { |
| 152 | + ViewerFile vf = it.next(); // copy because we remove as we iterate. inefficient |
| 153 | + if (!vf.toString().toLowerCase().contains(filterLower)) { |
| 154 | + it.remove(); |
| 155 | + } |
| 156 | + } |
| 157 | + } else for (ViewerFile vf : searchResults) { |
| 158 | + if (!vf.toString().toLowerCase().contains(filter)) { |
| 159 | + model.removeElement(vf); |
| 160 | + } else { |
| 161 | + model.add(vf); |
| 162 | + } |
| 163 | + } |
| 164 | + model.commitUpdates(); |
| 165 | + } |
41 | 166 | } |
0 commit comments