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