From: Mateusz Warowny Date: Thu, 18 Nov 2021 21:20:58 +0000 (+0100) Subject: JAL-3878 Add ws menu builder and attach to the align frame. X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=3d0f308b73908cb602f66f353385d22bf3a06698;p=jalview.git JAL-3878 Add ws menu builder and attach to the align frame. --- diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 6f3a7e3..b872e80 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -115,7 +115,11 @@ import jalview.ws.params.ArgumentI; import jalview.ws.params.ParamDatastoreI; import jalview.ws.params.WsParamSetI; import jalview.ws.seqfetcher.DbSourceProxy; -import jalview.ws.slivkaws.SlivkaWSDiscoverer; +import jalview.ws2.slivka.SlivkaWSDiscoverer; +import jalview.ws2.WebServiceDiscovererI; +import jalview.ws2.gui.WebServicesMenuBuilder; +import jalview.ws2.operations.Operation; + import java.io.IOException; import java.util.HashSet; import java.util.Set; @@ -909,13 +913,19 @@ public class AlignFrame extends GAlignFrame buildWebServicesMenu(); } + private void servicesChanged(WebServiceDiscovererI discoverer, + List operations) + { + buildWebServicesMenu(); + } + /* Set up intrinsic listeners for dynamically generated GUI bits. */ private void addServiceListeners() { if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - WSDiscovererI discoverer = SlivkaWSDiscoverer.getInstance(); - discoverer.addServiceChangeListener(this); + WebServiceDiscovererI discoverer = SlivkaWSDiscoverer.getInstance(); + discoverer.addOperationsChangeListener(this::servicesChanged); } if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { @@ -932,7 +942,7 @@ public class AlignFrame extends GAlignFrame @Override public void internalFrameClosed(InternalFrameEvent e) { System.out.println("deregistering discoverer listener"); - SlivkaWSDiscoverer.getInstance().removeServiceChangeListener(AlignFrame.this); + SlivkaWSDiscoverer.getInstance().removeOperationsChangeListener(AlignFrame.this::servicesChanged); Jws2Discoverer.getInstance().removeServiceChangeListener(AlignFrame.this); Desktop.getInstance().removeJalviewPropertyChangeListener("services", legacyListener); closeMenuItem_actionPerformed(true); @@ -4711,6 +4721,34 @@ public class AlignFrame extends GAlignFrame } } + private void buildWebServicesMenu(WebServiceDiscovererI discoverer, JMenu menu) + { + if (discoverer.hasServices()) + { + var builder = new WebServicesMenuBuilder(); + builder.addSelectedHostChangeListener((name, op) -> { + Cache.log.info("Rebuilding menu on host change"); + menu.removeAll(); + builder.buildMenu(menu, this); + }); + builder.addAllOperations(discoverer.getOperations()); + menu.removeAll(); + builder.buildMenu(menu, this); + } + if (discoverer.isRunning()) + { + JMenuItem item = new JMenuItem("Service discovery in progress."); + item.setEnabled(false); + menu.add(item); + } + else if (!discoverer.hasServices()) + { + JMenuItem item = new JMenuItem("No services available."); + item.setEnabled(false); + menu.add(item); + } + } + /** * construct any groupURL type service menu entries. * diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 88c94f6..db9931b 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -2736,7 +2736,7 @@ public class Desktop extends GDesktop } if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - tasks.add(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance().startDiscoverer()); + tasks.add(jalview.ws2.slivka.SlivkaWSDiscoverer.getInstance().startDiscoverer()); } if (blocking) { diff --git a/src/jalview/gui/SlivkaPreferences.java b/src/jalview/gui/SlivkaPreferences.java index 6c365b9..31ab5dd 100644 --- a/src/jalview/gui/SlivkaPreferences.java +++ b/src/jalview/gui/SlivkaPreferences.java @@ -3,7 +3,8 @@ package jalview.gui; import jalview.bin.Cache; import jalview.util.MessageManager; import jalview.ws.WSDiscovererI; -import jalview.ws.slivkaws.SlivkaWSDiscoverer; +import jalview.ws2.slivka.SlivkaWSDiscoverer; +import jalview.ws2.WebServiceDiscovererI; import java.awt.BorderLayout; import java.awt.Color; @@ -42,7 +43,7 @@ public class SlivkaPreferences extends JPanel setPreferredSize(new Dimension(500, 450)); } - WSDiscovererI discoverer; + WebServiceDiscovererI discoverer; private final ArrayList urls = new ArrayList<>(); @@ -97,16 +98,16 @@ public class SlivkaPreferences extends JPanel hasFocus, row, column); switch ((Integer) value) { - case WSDiscovererI.STATUS_NO_SERVICES: + case WebServiceDiscovererI.STATUS_NO_SERVICES: setForeground(Color.ORANGE); break; - case WSDiscovererI.STATUS_OK: + case WebServiceDiscovererI.STATUS_OK: setForeground(Color.GREEN); break; - case WSDiscovererI.STATUS_INVALID: + case WebServiceDiscovererI.STATUS_INVALID: setForeground(Color.RED); break; - case WSDiscovererI.STATUS_UNKNOWN: + case WebServiceDiscovererI.STATUS_UNKNOWN: default: setForeground(Color.LIGHT_GRAY); } @@ -141,7 +142,7 @@ public class SlivkaPreferences extends JPanel { String input = (String) JvOptionPane .showInternalInputDialog( - this, + this, MessageManager.getString("label.url:"), UIManager.getString("OptionPane.inputDialogTitle", MessageManager.getLocale()), JOptionPane.QUESTION_MESSAGE, @@ -173,9 +174,9 @@ public class SlivkaPreferences extends JPanel if (input != null) { urls.add(input); - statuses.add(discoverer.getServerStatusFor(input)); + statuses.add(discoverer.getStatusForUrl(input)); urlTableModel.fireTableRowsInserted(urls.size(), urls.size()); - discoverer.setServiceUrls(urls); + discoverer.setUrls(urls); } }; @@ -187,9 +188,9 @@ public class SlivkaPreferences extends JPanel if (input != null) { urls.set(i, input); - statuses.set(i, discoverer.getServerStatusFor(input)); + statuses.set(i, discoverer.getStatusForUrl(input)); urlTableModel.fireTableRowsUpdated(i, i); - discoverer.setServiceUrls(urls); + discoverer.setUrls(urls); } } }; @@ -201,7 +202,7 @@ public class SlivkaPreferences extends JPanel urls.remove(i); statuses.remove(i); urlTableModel.fireTableRowsDeleted(i, i); - discoverer.setServiceUrls(urls); + discoverer.setUrls(urls); } }; @@ -210,7 +211,7 @@ public class SlivkaPreferences extends JPanel if (i > 0) { moveTableRow(i, i - 1); - discoverer.setServiceUrls(urls); + discoverer.setUrls(urls); } }; @@ -219,7 +220,7 @@ public class SlivkaPreferences extends JPanel if (i >= 0 && i < urls.size() - 1) { moveTableRow(i, i + 1); - discoverer.setServiceUrls(urls); + discoverer.setUrls(urls); } }; @@ -324,13 +325,13 @@ public class SlivkaPreferences extends JPanel }; private ActionListener resetServicesAction = (ActionEvent e) -> { - discoverer.setServiceUrls(null); + discoverer.setUrls(null); urls.clear(); statuses.clear(); - urls.addAll(discoverer.getServiceUrls()); + urls.addAll(discoverer.getUrls()); for (String url : urls) { - statuses.add(discoverer.getServerStatusFor(url)); + statuses.add(discoverer.getStatusForUrl(url)); } urlTableModel.fireTableDataChanged(); }; @@ -359,10 +360,10 @@ public class SlivkaPreferences extends JPanel { // Initial URLs loading discoverer = SlivkaWSDiscoverer.getInstance(); - urls.addAll(discoverer.getServiceUrls()); + urls.addAll(discoverer.getUrls()); for (String url : urls) { - statuses.add(discoverer.getServerStatusFor(url)); + statuses.add(discoverer.getStatusForUrl(url)); } } } diff --git a/src/jalview/ws2/WebServiceDiscovererI.java b/src/jalview/ws2/WebServiceDiscovererI.java index 0932a87..30cc22e 100644 --- a/src/jalview/ws2/WebServiceDiscovererI.java +++ b/src/jalview/ws2/WebServiceDiscovererI.java @@ -120,7 +120,7 @@ public interface WebServiceDiscovererI * @param list */ public void operationsChanged(WebServiceDiscovererI discoverer, - List list); + List operations); } List serviceListeners = new CopyOnWriteArrayList<>(); @@ -143,7 +143,7 @@ public interface WebServiceDiscovererI * @param listener * listener to be removed */ - public default void removeServiceChangeListener( + public default void removeOperationsChangeListener( OperationsChangeListener listener) { serviceListeners.remove(listener); diff --git a/src/jalview/ws2/gui/WebServicesMenuBuilder.java b/src/jalview/ws2/gui/WebServicesMenuBuilder.java new file mode 100644 index 0000000..3a2f3c6 --- /dev/null +++ b/src/jalview/ws2/gui/WebServicesMenuBuilder.java @@ -0,0 +1,208 @@ +package jalview.ws2.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.gui.JvSwingUtils; +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) + { + JMenu alternatesMenu = new JMenu(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); + }); + alternatesMenu.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); + } + } + +}