// Note: renderUIUrl etc are called in Swing thread // TODO: improve AutoComboBox and put it back in persistable srecord noeq UIURLSystem(transient Enterable owner, transient SimpleLiveValue uiURL) extends MetaWithChangeListeners { settable bool showHomeButton = true; settable int maxHistoryEntries = 100; settable bool showGoButton; // key: ui URL transient Map uiMap = syncCIMap(); // these are additionally displayed at the top of the list // first URL will be shown as "Home" button (if home button is enabled) LS preferredURLs = syncList(); LS history = syncLinkedList(); LS forwardHistory = syncLinkedList(); sclass Entry { S url; S toolTip; IF0 makeComponent; *(S *url, IF0 *makeComponent) {} *(S *url, S *toolTip, IF0 *makeComponent) {} } settable transient SingleComponentPanel scp; transient JComboBox comboBox; transient JButton btnHome, btnBack, btnForward; transient simplyCached JComponent urlBar() { //comboBox = autoComboBox(url(), cloneKeys(uiMap)); comboBox = jcombobox(urlsForComboBox()); //centerComboBox(comboBox); comboBox.setRenderer( new CenteredComboBoxRenderer( new ListCellRendererWithToolTip(url -> toolTipForURL(url), (ListCellRenderer) comboBox.getRenderer()))); //comboBoxDynamicToolTip(comboBox, url -> toolTipForURL(url)); onSelectedItem( bindComboBoxToLiveValue(comboBox, uiURL), url -> showUIURL(url) ); Runnable cbAction = comboBoxAction(comboBox, url -> showUIURL(url)); JPanel rightButtons = jlineWithSpacing(5, ); JPanel leftButtons = jlineWithSpacing(5); if (showGoButton) rightButtons.add(jbutton("Go", cbAction)); JComponent panel = withLabel("Show", centerAndEastWithMargin( comboBox, rightButtons)); btnBack = jimageButtonScaledToWidth(16, #1103102, l0 goBack); add(rightButtons, btnBack); btnForward = jimageButtonScaledToWidth(16, #1103103, l0 goForward); add(rightButtons, btnForward); if (showHomeButton) { S homeURL = homeURL(); btnHome = jimageButtonScaledToWidth(16, #1103101, homeURL != null ? "Go to " + homeURL : "Go to home URL", l0 goHome); add(rightButtons, btnHome); } uiURL.onChangeAndNow(l0 updateButtons); if (!emptyContainer(leftButtons)) panel = westAndCenterWithMargin(leftButtons, panel); ret panel; } void updateButtons { swing { S homeURL = homeURL(); setEnabled(btnHome, homeURL != null && !eq(homeURL, url())); S backURL = last(history); setEnabled(btnBack, backURL != null); setToolTip(btnBack, backURL == null ? "Go back" : "Go back to " + backURL); S forwardURL = first(forwardHistory); printVars("updateButtons", +forwardURL); setEnabled(btnForward, forwardURL != null); setToolTip(btnForward, forwardURL == null ? "Go forward" : "Go forward to " + forwardURL); } change(); } JComponent renderUIUrl aka renderUIURL aka uiGet(S url) { try { temp tempEnter(owner); var entry = uiMap.get(url); if (entry == null) ret jCenteredLabel("URL not found: " + url); var component = entry.makeComponent!; ret component; } catch print e { ret jErrorView(e); } } bool hasURL(S url) { ret uiMap.containsKey(url); } void showUIURL(S url) swing { if (!eqic(url(), url)) { addToHistory(url()); showUIURL_dontAddToHistory(url); } } void addToHistory(S url) { printVars("addToHistory", +url); if (empty(url) || eqic(last(history), url)) ret; removeAllIC_useIterator(history, url); history.add(url); if (l(history) > maxHistoryEntries) removeFirst(history); forwardHistory.clear(); updateButtons(); } void showUIURL_dontAddToHistory(S url) { temp tempEnter(owner); setURL(trim(url)); go(); } void go { setComponent(scp, renderUIUrl(url())); } S url() { ret uiURL!; } void setURL(S url) { assertURLValid(url); uiURL.set(url); } swappable void assertURLValid(S url) { if (!uiMap.containsKey(url)) fail("UIURL not found: " + url); } selfType put(WithToolTip url, IF0 maker) { ret put(url!, url.toolTip(), maker); } selfType put(S url, S toolTip default null, IF0 maker) { uiMap.put(url, new Entry(url, toolTip, maker)); setComboBoxItems(comboBox, urlsForComboBox()); this; } S toolTipForURL(S url) { var e = uiMap.get(url); ret e?.toolTip; } LS urlsForComboBox() { var sorted = cloneKeys(uiMap); ret concatLists(listSetIntersection(preferredURLs, sorted), sorted); } void addPreferredUIURL(S uiURL) { addIfNotContained(preferredURLs, uiURL); } S homeURL() { ret first(preferredURLs); } void goHome { showUIURL(homeURL()); } void goBack swing { S url = popLast(history); if (url != null) { S currentURL = url(); if (nempty(currentURL)) forwardHistory.add(0, currentURL); printVars("goBack", +url, +currentURL, +forwardHistory); updateButtons(); showUIURL_dontAddToHistory(url); } } void goForward swing { S url = popFirst(forwardHistory); if (url != null) { S currentURL = url(); if (nempty(currentURL)) history.add(currentURL); printVars("goForward", +url, +currentURL, +history); updateButtons(); showUIURL_dontAddToHistory(url); } } }