JAL-3878 Wire web services logic to UI elements.
[jalview.git] / src / jalview / gui / SlivkaPreferences.java
1 package jalview.gui;
2
3 import jalview.bin.Cache;
4 import jalview.util.MessageManager;
5 import jalview.ws.WSDiscovererI;
6 import jalview.ws2.slivka.SlivkaWSDiscoverer;
7 import jalview.ws2.WebServiceDiscoverer;
8
9 import java.awt.BorderLayout;
10 import java.awt.Color;
11 import java.awt.Component;
12 import java.awt.Dimension;
13 import java.awt.Font;
14 import java.awt.event.ActionEvent;
15 import java.awt.event.ActionListener;
16 import java.awt.event.MouseAdapter;
17 import java.awt.event.MouseEvent;
18 import java.awt.event.MouseListener;
19 import java.net.MalformedURLException;
20 import java.net.URL;
21 import java.util.ArrayList;
22 import java.util.NoSuchElementException;
23
24 import javax.swing.BorderFactory;
25 import javax.swing.Box;
26 import javax.swing.BoxLayout;
27 import javax.swing.JButton;
28 import javax.swing.JOptionPane;
29 import javax.swing.JPanel;
30 import javax.swing.JProgressBar;
31 import javax.swing.JScrollPane;
32 import javax.swing.JTable;
33 import javax.swing.SwingUtilities;
34 import javax.swing.UIManager;
35 import javax.swing.table.AbstractTableModel;
36 import javax.swing.table.DefaultTableCellRenderer;
37
38 @SuppressWarnings("serial")
39 public class SlivkaPreferences extends JPanel
40 {
41   {
42     setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
43     setPreferredSize(new Dimension(500, 450));
44   }
45
46   WebServiceDiscoverer discoverer;
47
48   private final ArrayList<String> urls = new ArrayList<>();
49
50   private final ArrayList<Integer> statuses = new ArrayList<>();
51
52   private final AbstractTableModel urlTableModel = new AbstractTableModel()
53   {
54     final String[] columnNames = { "Service URL", "Status" };
55
56     @Override
57     public String getColumnName(int col)
58     {
59       return columnNames[col];
60     }
61
62     @Override
63     public Object getValueAt(int rowIndex, int columnIndex)
64     {
65       switch (columnIndex)
66       {
67       case 0:
68         return urls.get(rowIndex);
69       case 1:
70         return statuses.get(rowIndex);
71       default:
72         throw new NoSuchElementException();
73       }
74     }
75
76     @Override
77     public int getRowCount()
78     {
79       return urls.size();
80     }
81
82     @Override
83     public int getColumnCount()
84     {
85       return 2;
86     }
87   };
88
89   private class WSStatusCellRenderer extends DefaultTableCellRenderer
90   {
91     @Override
92     public Component getTableCellRendererComponent(JTable table,
93         Object value, boolean isSelected, boolean hasFocus, int row,
94         int column)
95     {
96       setHorizontalAlignment(CENTER);
97       super.getTableCellRendererComponent(table, "\u25CF", isSelected,
98           hasFocus, row, column);
99       switch ((Integer) value)
100       {
101       case WSDiscovererI.STATUS_NO_SERVICES:
102         setForeground(Color.ORANGE);
103         break;
104       case WSDiscovererI.STATUS_OK:
105         setForeground(Color.GREEN);
106         break;
107       case WSDiscovererI.STATUS_INVALID:
108         setForeground(Color.RED);
109         break;
110       case WSDiscovererI.STATUS_UNKNOWN:
111       default:
112         setForeground(Color.LIGHT_GRAY);
113       }
114       return this;
115     }
116   }
117
118   private JTable urlListTable = new JTable(urlTableModel);
119   {
120     urlListTable.getColumnModel().getColumn(1).setMaxWidth(60);
121     urlListTable.getColumnModel().getColumn(1)
122         .setCellRenderer(new WSStatusCellRenderer());
123   }
124
125   // URL control panel buttons
126   JButton newWsUrl = new JButton(
127       MessageManager.getString("label.new_service_url"));
128
129   JButton editWsUrl = new JButton(
130       MessageManager.getString("label.edit_service_url"));
131
132   JButton deleteWsUrl = new JButton(
133       MessageManager.getString("label.delete_service_url"));
134
135   JButton moveUrlUp = new JButton(
136       MessageManager.getString("action.move_up"));
137
138   JButton moveUrlDown = new JButton(
139       MessageManager.getString("action.move_down"));
140
141   private String showEditUrlDialog(String oldUrl)
142   {
143     String input = (String) JvOptionPane
144         .showInternalInputDialog(
145             this,
146             MessageManager.getString("label.url:"),
147             UIManager.getString("OptionPane.inputDialogTitle", MessageManager.getLocale()),
148             JOptionPane.QUESTION_MESSAGE,
149             null,
150             null,
151             oldUrl);
152     if (input == null)
153     {
154       return null;
155     }
156     try
157     {
158       new URL(input);
159     } catch (MalformedURLException ex)
160     {
161       JvOptionPane.showInternalMessageDialog(this,
162           MessageManager.getString("label.invalid_url"),
163           UIManager.getString("OptionPane.messageDialogTitle",
164               MessageManager.getLocale()),
165           JOptionPane.WARNING_MESSAGE);
166       return null;
167     }
168     return input;
169   }
170
171   // Button Action Listeners
172   private ActionListener newUrlAction = (ActionEvent e) -> {
173     final String input = showEditUrlDialog("");
174     if (input != null)
175     {
176       urls.add(input);
177       statuses.add(discoverer.getStatusForUrl(input));
178       urlTableModel.fireTableRowsInserted(urls.size(), urls.size());
179       discoverer.setUrls(urls);
180     }
181   };
182
183   private ActionListener editUrlAction = (ActionEvent e) -> {
184     final int i = urlListTable.getSelectedRow();
185     if (i >= 0)
186     {
187       final String input = showEditUrlDialog(urls.get(i));
188       if (input != null)
189       {
190         urls.set(i, input);
191         statuses.set(i, discoverer.getStatusForUrl(input));
192         urlTableModel.fireTableRowsUpdated(i, i);
193         discoverer.setUrls(urls);
194       }
195     }
196   };
197
198   private ActionListener deleteUrlAction = (ActionEvent e) -> {
199     final int i = urlListTable.getSelectedRow();
200     if (i >= 0)
201     {
202       urls.remove(i);
203       statuses.remove(i);
204       urlTableModel.fireTableRowsDeleted(i, i);
205       discoverer.setUrls(urls);
206     }
207   };
208
209   private ActionListener moveUrlUpAction = (ActionEvent e) -> {
210     final int i = urlListTable.getSelectedRow();
211     if (i > 0)
212     {
213       moveTableRow(i, i - 1);
214       discoverer.setUrls(urls);
215     }
216   };
217
218   private ActionListener moveUrlDownAction = (ActionEvent e) -> {
219     final int i = urlListTable.getSelectedRow();
220     if (i >= 0 && i < urls.size() - 1)
221     {
222       moveTableRow(i, i + 1);
223       discoverer.setUrls(urls);
224     }
225   };
226
227   private MouseListener tableClickListener = new MouseAdapter()
228   {
229     final ActionEvent actionEvent = new ActionEvent(urlListTable,
230         ActionEvent.ACTION_PERFORMED, "edit");
231
232     @Override
233     public void mouseClicked(MouseEvent e)
234     {
235       if (e.getClickCount() > 1)
236       {
237         editUrlAction.actionPerformed(actionEvent);
238       }
239     }
240   };
241
242   // Setting up URL list Pane
243   {
244     Font font = new Font("Verdana", Font.PLAIN, 10);
245     JPanel urlPaneContainer = new JPanel(new BorderLayout(5, 5));
246     urlPaneContainer.setBorder(BorderFactory.createCompoundBorder(
247         BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
248             "Slivka Web Services"),
249         BorderFactory.createEmptyBorder(10, 5, 5, 5)));
250
251     newWsUrl.setFont(font);
252     editWsUrl.setFont(font);
253     deleteWsUrl.setFont(font);
254     moveUrlUp.setFont(font);
255     moveUrlDown.setFont(font);
256     JPanel editContainer = new JPanel();
257     editContainer.add(newWsUrl);
258     editContainer.add(editWsUrl);
259     editContainer.add(deleteWsUrl);
260     urlPaneContainer.add(editContainer, BorderLayout.PAGE_END);
261
262     JPanel moveContainer = new JPanel();
263     moveContainer
264         .setLayout(new BoxLayout(moveContainer, BoxLayout.PAGE_AXIS));
265     moveContainer.add(moveUrlUp);
266     moveContainer.add(Box.createRigidArea(new Dimension(0, 5)));
267     moveContainer.add(moveUrlDown);
268     urlPaneContainer.add(moveContainer, BorderLayout.LINE_START);
269
270     urlPaneContainer.add(new JScrollPane(urlListTable),
271         BorderLayout.CENTER);
272     this.add(urlPaneContainer);
273
274     // Connecting action listeners
275     urlListTable.addMouseListener(tableClickListener);
276     newWsUrl.addActionListener(newUrlAction);
277     editWsUrl.addActionListener(editUrlAction);
278     deleteWsUrl.addActionListener(deleteUrlAction);
279     moveUrlUp.addActionListener(moveUrlUpAction);
280     moveUrlDown.addActionListener(moveUrlDownAction);
281   }
282
283   private void moveTableRow(int fromIndex, int toIndex)
284   {
285     String url = urls.get(fromIndex);
286     int status = statuses.get(fromIndex);
287     urls.set(fromIndex, urls.get(toIndex));
288     statuses.set(fromIndex, statuses.get(toIndex));
289     urls.set(toIndex, url);
290     statuses.set(toIndex, status);
291     if (urlListTable.getSelectedRow() == fromIndex)
292     {
293       urlListTable.setRowSelectionInterval(toIndex, toIndex);
294     }
295     int firstRow = Math.min(toIndex, fromIndex);
296     int lastRow = Math.max(fromIndex, toIndex);
297     urlTableModel.fireTableRowsUpdated(firstRow, lastRow);
298   }
299
300   // Discoverer reloading buttons
301   JButton refreshServices = new JButton(
302       MessageManager.getString("action.refresh_services"));
303
304   JButton resetServices = new JButton(
305       MessageManager.getString("action.reset_services"));
306
307   JProgressBar progressBar = new JProgressBar();
308
309   // Discoverer buttons action listeners
310   private ActionListener refreshServicesAction = (ActionEvent e) -> {
311     progressBar.setVisible(true);
312     Cache.log.info("Requesting service reload");
313     discoverer.startDiscoverer().handle((_discoverer, exception) -> {
314       if (exception == null)
315       {
316         Cache.log.info("Reloading done");
317       }
318       else
319       {
320         Cache.log.error("Reloading failed", exception);
321       }
322       SwingUtilities.invokeLater(() -> progressBar.setVisible(false));
323       return null;
324     });
325   };
326
327   private ActionListener resetServicesAction = (ActionEvent e) -> {
328     discoverer.setUrls(null);
329     urls.clear();
330     statuses.clear();
331     urls.addAll(discoverer.getUrls());
332     for (String url : urls)
333     {
334       statuses.add(discoverer.getStatusForUrl(url));
335     }
336     urlTableModel.fireTableDataChanged();
337   };
338
339   {
340     Font font = new Font("Verdana", Font.PLAIN, 11);
341     refreshServices.setFont(font);
342     resetServices.setFont(font);
343     JPanel container = new JPanel();
344     container.add(refreshServices);
345     container.add(resetServices);
346     this.add(container);
347
348     // Connecting action listeners
349     refreshServices.addActionListener(refreshServicesAction);
350     resetServices.addActionListener(resetServicesAction);
351   }
352
353   {
354     progressBar.setVisible(false);
355     progressBar.setIndeterminate(true);
356     add(progressBar);
357   }
358
359   SlivkaPreferences()
360   {
361     // Initial URLs loading
362     discoverer = SlivkaWSDiscoverer.getInstance();
363     urls.addAll(discoverer.getUrls());
364     for (String url : urls)
365     {
366       statuses.add(discoverer.getStatusForUrl(url));
367     }
368   }
369 }