abstract sclass DynQuickSearch extends DynCalculatedList { transient S query; transient new RestartableCountdown autoHide; transient S moduleDescForSearch; transient O[] quickSearchParams; transient bool doSearchVerbose; transient int yesPopupOffsetY = -13; start { calculateWhenHidden = true; ownResource(vmBus_onMessage('topInput, voidfunc(S s) { doSearch(s) })); ownResource(vmBus_onMessage('topInputChanged, voidfunc(S s) { if (neq(s, query)) doSearch(s) })); dm_vmBus_onMessage_q hideQuickSearchModules(r dm_hideModule); } void doSearch(S s) enter { if (dm_dontQuickSearch_combined(s)) ret; query = s; O qsm = dm_quickSearchManager(); if (qsm != null && !dm_isMe(qsm)) { results = calc(); dm_call(qsm, 'setResultsForModule, dm_moduleID(), moduleDescForSearch, query, results, quickSearchParams); } else { super.update(); if (doSearchVerbose) print("doSearch: Got " + n2(results, "result") + " for " + query); if (nempty(query) && nempty(results)) { dm_placeModuleUnderAIBar_v2(this, query); dm_autoHide(autoHide); if (dm_yesPopupEnabled() && dm_amFirstQuickSearchModule() && !dm_myYesPopup()) dm_showYesToAcceptPopupAbove_v2(list, imageID := #1101462, height := 247/2, mover := voidfunc(Component c, Component popup) enter { JList list = cast c; Rect r = boundsInParent(c, dm_desktopPane()); if (r == null) ret; Rect item = jlist_itemBounds(list, 0); setLocation(popup, r.x+item.x-popup.getWidth(), r.y+item.y+yesPopupOffsetY); }); } else dm_hideModule(); } } void yes { jlist_doubleClickOnItem(list, 0); } final L calc() { if (empty(query)) ret emptyList(); ret calc_impl(); } abstract LS calc_impl(); void enhanceFrame(Container f) { super.enhanceFrame(f); setClosable(f, false); internalFramePopupMenuItem(f, "Delete", rThread { dm_deleteModuleInBackground(module()) }); } // API void selectFirstEntry() { selectRow(list, 0); } }