JAL-3878 Add javadocs to created classes and reformat code.
[jalview.git] / src / jalview / gui / WebServicesMenuBuilder.java
1 package jalview.gui;
2
3 import java.awt.Color;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.concurrent.CopyOnWriteArrayList;
12
13 import javax.swing.JMenu;
14 import javax.swing.JMenuItem;
15
16 import jalview.gui.AlignFrame;
17 import jalview.gui.Desktop;
18 import jalview.util.MessageManager;
19 import jalview.ws2.WebServiceI;
20 import jalview.ws2.operations.Operation;
21
22 /**
23  * 
24  * @author mmwarowny
25  *
26  */
27 public class WebServicesMenuBuilder
28 {
29   @FunctionalInterface
30   public static interface SelectedHostChangeListener
31   {
32     public void selectedHostChanged(String opName, Operation op);
33   }
34
35   List<Operation> operations = new ArrayList<>();
36
37   /**
38    * Mapping of service name to the preferred url this service is hosted at.
39    */
40   Map<String, String> selectedHost = new HashMap<>();
41
42   public void addOperation(Operation op)
43   {
44     operations.add(op);
45   }
46
47   public void addAllOperations(Collection<Operation> operations)
48   {
49     this.operations.addAll(operations);
50   }
51
52   public void removeOperation(Operation op)
53   {
54     operations.remove(op);
55   }
56
57   public void clearOperations()
58   {
59     operations.clear();
60   }
61
62   public void buildMenu(JMenu atMenu, AlignFrame frame)
63   {
64     Map<String, List<Operation>> oneshotOperations = new HashMap<>();
65     Map<String, List<Operation>> interactiveOperations = new HashMap<>();
66     for (Operation op : operations)
67     {
68       var mapping = op.isInteractive() ? interactiveOperations : oneshotOperations;
69       if (!mapping.containsKey(op.getTypeName()))
70         mapping.put(op.getTypeName(), new ArrayList<>());
71       mapping.get(op.getTypeName()).add(op);
72     }
73     var keysSet = new HashSet<>(oneshotOperations.keySet());
74     keysSet.addAll(interactiveOperations.keySet());
75     var keys = new ArrayList<>(keysSet);
76     keys.sort(Comparator.<String> naturalOrder());
77     for (String opType : keys)
78     {
79       var submenu = new JMenu(opType);
80       var oneshot = oneshotOperations.get(opType);
81       if (oneshot != null)
82         addOneshotOperations(oneshot, submenu, frame);
83       var interactive = interactiveOperations.get(opType);
84       if (interactive != null)
85       {
86         if (oneshot != null)
87           submenu.addSeparator();
88         addInteractiveOperations(interactive, submenu, frame);
89       }
90       atMenu.add(submenu);
91     }
92   }
93
94   private void addOneshotOperations(List<Operation> operations, JMenu submenu,
95       AlignFrame frame)
96   {
97     operations = new ArrayList<>(operations);
98     operations.sort(Comparator
99         .<Operation, String> comparing(o -> o.getHostName())
100         .<String> thenComparing(o -> o.getName()));
101     String lastHost = null;
102     for (final Operation op : operations)
103     {
104       String host = op.getHostName();
105       if (lastHost != host)
106       {
107         if (lastHost != null)
108           submenu.addSeparator();
109         var menuItem = new JMenuItem(host);
110         menuItem.setForeground(Color.blue);
111         menuItem.addActionListener(e -> Desktop.showUrl(host));
112         submenu.add(menuItem);
113         lastHost = host;
114       }
115       submenu.addSeparator();
116       op.getMenuBuilder().buildMenu(submenu, frame);
117     }
118   }
119
120   private void addInteractiveOperations(List<Operation> operations,
121       JMenu submenu, AlignFrame frame)
122   {
123     Map<String, List<Operation>> groupedOperations = new HashMap<>();
124     for (Operation op : operations)
125     {
126       if (!groupedOperations.containsKey(op.getName()))
127         groupedOperations.put(op.getName(), new ArrayList<>());
128       groupedOperations.get(op.getName()).add(op);
129     }
130     var keys = new ArrayList<>(groupedOperations.keySet());
131     keys.sort(Comparator.<String> naturalOrder());
132     for (String opName : keys)
133     {
134       var ops = groupedOperations.get(opName);
135       var selectedHost = getSelectedHost(opName);
136       Operation selectedOperation = null;
137       for (var op : ops)
138       {
139         if (op.getHostName().equals(selectedHost))
140         {
141           selectedOperation = op;
142           break;
143         }
144       }
145       if (selectedOperation == null || selectedHost == null)
146         selectedOperation = ops.get(0);
147       {
148         final var hostName = selectedOperation.getHostName();
149         var hostItem = new JMenuItem(hostName);
150         hostItem.setForeground(Color.blue);
151         hostItem.addActionListener(e -> Desktop.showUrl(hostName));
152         submenu.add(hostItem);
153       }
154       selectedOperation.getMenuBuilder().buildMenu(submenu, frame);
155       if (ops.size() > 1)
156       {
157         JMenuItem alternatesMenu = new JMenuItem(MessageManager.getString("label.switch_server"));
158         submenu.add(alternatesMenu);
159         alternatesMenu.setToolTipText(JvSwingUtils.wrapTooltip(false,
160             MessageManager.getString("label.choose_jabaws_server")));
161         for (final Operation op : ops)
162         {
163           if (op == selectedOperation)
164             continue;
165           var hostItem = new JMenuItem(op.getHostName());
166           hostItem.setForeground(Color.blue);
167           hostItem.addActionListener(e -> {
168             setSelectedHost(op.getName(), op.getHostName());
169             fireSelectedHostChanged(op.getName(), op);
170           });
171           submenu.add(hostItem);
172         }
173       }
174     }
175   }
176
177   public String getSelectedHost(String serviceName)
178   {
179     return selectedHost.getOrDefault(serviceName, null);
180   }
181
182   public void setSelectedHost(WebServiceI service)
183   {
184     setSelectedHost(service.getName(), service.getHostName());
185   }
186
187   public void setSelectedHost(String serviceName, String hostName)
188   {
189     selectedHost.put(serviceName, hostName);
190   }
191
192   List<SelectedHostChangeListener> hostChangeListeners = new CopyOnWriteArrayList<>();
193
194   public void addSelectedHostChangeListener(SelectedHostChangeListener l)
195   {
196     hostChangeListeners.add(l);
197   }
198
199   private void fireSelectedHostChanged(String opName, Operation op)
200   {
201     for (var listener : hostChangeListeners)
202     {
203       listener.selectedHostChanged(opName, op);
204     }
205   }
206
207 }