package jalview.gui; import java.awt.Color; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import javax.swing.JMenu; import javax.swing.JMenuItem; import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.util.MessageManager; import jalview.ws2.WebServiceI; import jalview.ws2.operations.Operation; /** * * @author mmwarowny * */ public class WebServicesMenuBuilder { @FunctionalInterface public static interface SelectedHostChangeListener { public void selectedHostChanged(String opName, Operation op); } List operations = new ArrayList<>(); /** * Mapping of service name to the preferred url this service is hosted at. */ Map selectedHost = new HashMap<>(); public void addOperation(Operation op) { operations.add(op); } public void addAllOperations(Collection operations) { this.operations.addAll(operations); } public void removeOperation(Operation op) { operations.remove(op); } public void clearOperations() { operations.clear(); } public void buildMenu(JMenu atMenu, AlignFrame frame) { Map> oneshotOperations = new HashMap<>(); Map> interactiveOperations = new HashMap<>(); for (Operation op : operations) { var mapping = op.isInteractive() ? interactiveOperations : oneshotOperations; if (!mapping.containsKey(op.getTypeName())) mapping.put(op.getTypeName(), new ArrayList<>()); mapping.get(op.getTypeName()).add(op); } var keysSet = new HashSet<>(oneshotOperations.keySet()); keysSet.addAll(interactiveOperations.keySet()); var keys = new ArrayList<>(keysSet); keys.sort(Comparator. naturalOrder()); for (String opType : keys) { var submenu = new JMenu(opType); var oneshot = oneshotOperations.get(opType); if (oneshot != null) addOneshotOperations(oneshot, submenu, frame); var interactive = interactiveOperations.get(opType); if (interactive != null) { if (oneshot != null) submenu.addSeparator(); addInteractiveOperations(interactive, submenu, frame); } atMenu.add(submenu); } } private void addOneshotOperations(List operations, JMenu submenu, AlignFrame frame) { operations = new ArrayList<>(operations); operations.sort(Comparator . comparing(o -> o.getHostName()) . thenComparing(o -> o.getName())); String lastHost = null; for (final Operation op : operations) { String host = op.getHostName(); if (lastHost != host) { if (lastHost != null) submenu.addSeparator(); var menuItem = new JMenuItem(host); menuItem.setForeground(Color.blue); menuItem.addActionListener(e -> Desktop.showUrl(host)); submenu.add(menuItem); lastHost = host; } submenu.addSeparator(); op.getMenuBuilder().buildMenu(submenu, frame); } } private void addInteractiveOperations(List operations, JMenu submenu, AlignFrame frame) { Map> groupedOperations = new HashMap<>(); for (Operation op : operations) { if (!groupedOperations.containsKey(op.getName())) groupedOperations.put(op.getName(), new ArrayList<>()); groupedOperations.get(op.getName()).add(op); } var keys = new ArrayList<>(groupedOperations.keySet()); keys.sort(Comparator. naturalOrder()); for (String opName : keys) { var ops = groupedOperations.get(opName); var selectedHost = getSelectedHost(opName); Operation selectedOperation = null; for (var op : ops) { if (op.getHostName().equals(selectedHost)) { selectedOperation = op; break; } } if (selectedOperation == null || selectedHost == null) selectedOperation = ops.get(0); { final var hostName = selectedOperation.getHostName(); var hostItem = new JMenuItem(hostName); hostItem.setForeground(Color.blue); hostItem.addActionListener(e -> Desktop.showUrl(hostName)); submenu.add(hostItem); } selectedOperation.getMenuBuilder().buildMenu(submenu, frame); if (ops.size() > 1) { JMenuItem alternatesMenu = new JMenuItem(MessageManager.getString("label.switch_server")); submenu.add(alternatesMenu); alternatesMenu.setToolTipText(JvSwingUtils.wrapTooltip(false, MessageManager.getString("label.choose_jabaws_server"))); for (final Operation op : ops) { if (op == selectedOperation) continue; var hostItem = new JMenuItem(op.getHostName()); hostItem.setForeground(Color.blue); hostItem.addActionListener(e -> { setSelectedHost(op.getName(), op.getHostName()); fireSelectedHostChanged(op.getName(), op); }); submenu.add(hostItem); } } } } public String getSelectedHost(String serviceName) { return selectedHost.getOrDefault(serviceName, null); } public void setSelectedHost(WebServiceI service) { setSelectedHost(service.getName(), service.getHostName()); } public void setSelectedHost(String serviceName, String hostName) { selectedHost.put(serviceName, hostName); } List hostChangeListeners = new CopyOnWriteArrayList<>(); public void addSelectedHostChangeListener(SelectedHostChangeListener l) { hostChangeListeners.add(l); } private void fireSelectedHostChanged(String opName, Operation op) { for (var listener : hostChangeListeners) { listener.selectedHostChanged(opName, op); } } }