sclass TableSearcher { JTable table; JTextField tfInput; JComponent searchPanel, panel; F2 rowTester; L rowIndices; SingleComponentPanel scpRightOfSearchPanel = scp(); L lastFiltered, lastOriginal; S input() { ret gtt(tfInput); } void clearSearchField { setText(tfInput, ""); } } static TableSearcher tableWithSearcher2(JTable t, O... _) { new TableSearcher s; bool precise = true; s.table = t; s.tfInput = jtextfield(); s.rowTester = func(S pat, Map row) -> bool { anyValueContainsIgnoreCase(row, pat) }; onUpdate(s.tfInput, new Runnable { public void run() { S pat = s.input(); L> data = rawTableData(t); if (eq(s.lastFiltered, data)) data = s.lastOriginal; //print("Searching " + n(l(data), "entry")); new L data2; new L rowIndices; for i over data: { Map map = data.get(i); if (isTrue(callF(s.rowTester, pat, map))) { data2.add(map); rowIndices.add(i); } } //print("Found " + n(l(data2), "entry")); s.lastFiltered = data2; s.lastOriginal = data; dataToTable(t, data2); if (precise) s.lastFiltered = rawTableData(t); s.rowIndices = rowIndices; } }); s.searchPanel = centerAndEast(withLabel(" Search:", s.tfInput), s.scpRightOfSearchPanel); JComponent top = s.searchPanel; s.panel = boolOptPar(_, 'withMargin) ? northAndCenterWithMargin(top, t) : northAndCenter(top, t); ret s; }