JAL-3515 Build a WSPreferences page for Slivka services.
authorMMWarowny <mmzwarowny@dundee.ac.uk>
Tue, 4 Feb 2020 11:28:42 +0000 (11:28 +0000)
committerMMWarowny <mmzwarowny@dundee.ac.uk>
Tue, 4 Feb 2020 11:28:42 +0000 (11:28 +0000)
src/jalview/gui/Preferences.java
src/jalview/gui/SlivkaPreferences.java [new file with mode: 0644]
src/jalview/jbgui/GPreferences.java

index a0a7511..c921331 100755 (executable)
@@ -192,6 +192,8 @@ public class Preferences extends GPreferences
 
   private WsPreferences wsPrefs;
 
+  private SlivkaPreferences slivkaPrefs;
+
   private OptionsParam promptEachTimeOpt = new OptionsParam(
           MessageManager.getString("label.prompt_each_time"),
           "Prompt each time");
@@ -212,6 +214,8 @@ public class Preferences extends GPreferences
     frame.setContentPane(this);
     wsPrefs = new WsPreferences();
     wsTab.add(wsPrefs, BorderLayout.CENTER);
+    slivkaTab.add(slivkaPrefs = new SlivkaPreferences(),
+        BorderLayout.CENTER);
     int width = 500, height = 450;
     new jalview.util.Platform();
     if (Platform.isAMac())
@@ -481,7 +485,7 @@ public class Preferences extends GPreferences
     doReset.addActionListener(onReset);
 
     // filter to display only custom urls
-    final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<TableModel, Object>()
+    final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<>()
     {
       @Override
       public boolean include(
diff --git a/src/jalview/gui/SlivkaPreferences.java b/src/jalview/gui/SlivkaPreferences.java
new file mode 100644 (file)
index 0000000..4df4bf6
--- /dev/null
@@ -0,0 +1,358 @@
+package jalview.gui;
+
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.UIManager;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+
+@SuppressWarnings("serial")
+public class SlivkaPreferences extends JPanel
+{
+  {
+    setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+    setPreferredSize(new Dimension(500, 450));
+  }
+
+  WSDiscovererI discoverer;
+
+  private final ArrayList<String> urls = new ArrayList<>();
+
+  private final ArrayList<Integer> statuses = new ArrayList<>();
+
+  private final AbstractTableModel urlTableModel = new AbstractTableModel()
+  {
+    final String[] columnNames = { "Service URL", "Status" };
+
+    @Override
+    public String getColumnName(int col)
+    {
+      return columnNames[col];
+    }
+
+    @Override
+    public Object getValueAt(int rowIndex, int columnIndex)
+    {
+      switch (columnIndex)
+      {
+      case 0:
+        return urls.get(rowIndex);
+      case 1:
+        return statuses.get(rowIndex);
+      default:
+        throw new NoSuchElementException();
+      }
+    }
+
+    @Override
+    public int getRowCount()
+    {
+      return urls.size();
+    }
+
+    @Override
+    public int getColumnCount()
+    {
+      return 2;
+    }
+  };
+
+  private class WSStatusCellRenderer extends DefaultTableCellRenderer
+  {
+    @Override
+    public Component getTableCellRendererComponent(JTable table,
+        Object value, boolean isSelected, boolean hasFocus, int row,
+        int column)
+    {
+      setHorizontalAlignment(CENTER);
+      super.getTableCellRendererComponent(table, "\u25CF", isSelected,
+          hasFocus, row, column);
+      switch ((Integer) value)
+      {
+      case WSDiscovererI.STATUS_NO_SERVICES:
+        setForeground(Color.ORANGE);
+        break;
+      case WSDiscovererI.STATUS_OK:
+        setForeground(Color.GREEN);
+        break;
+      case WSDiscovererI.STATUS_INVALID:
+        setForeground(Color.RED);
+        break;
+      case WSDiscovererI.STATUS_UNKNOWN:
+      default:
+        setForeground(Color.LIGHT_GRAY);
+      }
+      return this;
+    }
+  }
+
+  private JTable urlListTable = new JTable(urlTableModel);
+  {
+    urlListTable.getColumnModel().getColumn(1).setMaxWidth(60);
+    urlListTable.getColumnModel().getColumn(1)
+        .setCellRenderer(new WSStatusCellRenderer());
+  }
+
+  // URL control panel buttons
+  JButton newWsUrl = new JButton(
+      MessageManager.getString("label.new_service_url"));
+
+  JButton editWsUrl = new JButton(
+      MessageManager.getString("label.edit_service_url"));
+
+  JButton deleteWsUrl = new JButton(
+      MessageManager.getString("label.delete_service_url"));
+
+  JButton moveUrlUp = new JButton(
+      MessageManager.getString("action.move_up"));
+
+  JButton moveUrlDown = new JButton(
+      MessageManager.getString("action.move_down"));
+
+  private String showEditUrlDialog(String oldUrl)
+  {
+    String input = (String) JOptionPane
+        .showInternalInputDialog(
+            this, 
+            MessageManager.getString("label.url:"),
+            UIManager.getString("OptionPane.inputDialogTitle", MessageManager.getLocale()),
+            JOptionPane.QUESTION_MESSAGE,
+            null,
+            null,
+            oldUrl);
+    if (input == null)
+    {
+      return null;
+    }
+    try
+    {
+      new URL(input);
+    } catch (MalformedURLException ex)
+    {
+      JOptionPane.showMessageDialog(this,
+          MessageManager.getString("label.invalid_url"), "Warning",
+          JOptionPane.WARNING_MESSAGE);
+      return null;
+    }
+    return input;
+  }
+
+  // Button Action Listeners
+  private ActionListener newUrlAction = (ActionEvent e) -> {
+    final String input = showEditUrlDialog("");
+    if (input != null)
+    {
+      urls.add(input);
+      statuses.add(discoverer.getServerStatusFor(input));
+      urlTableModel.fireTableRowsInserted(urls.size(), urls.size());
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private ActionListener editUrlAction = (ActionEvent e) -> {
+    final int i = urlListTable.getSelectedRow();
+    if (i >= 0)
+    {
+      final String input = showEditUrlDialog(urls.get(i));
+      if (input != null)
+      {
+        urls.set(i, input);
+        statuses.set(i, discoverer.getServerStatusFor(input));
+        urlTableModel.fireTableRowsUpdated(i, i);
+        discoverer.setServiceUrls(urls);
+      }
+    }
+  };
+
+  private ActionListener deleteUrlAction = (ActionEvent e) -> {
+    final int i = urlListTable.getSelectedRow();
+    if (i >= 0)
+    {
+      urls.remove(i);
+      statuses.remove(i);
+      urlTableModel.fireTableRowsDeleted(i, i);
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private ActionListener moveUrlUpAction = (ActionEvent e) -> {
+    int i = urlListTable.getSelectedRow();
+    if (i > 0)
+    {
+      moveTableRow(i, i - 1);
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private ActionListener moveUrlDownAction = (ActionEvent e) -> {
+    int i = urlListTable.getSelectedRow();
+    if (i >= 0 && i < urls.size() - 1)
+    {
+      moveTableRow(i, i + 1);
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private MouseListener tableClickListener = new MouseAdapter()
+  {
+    final ActionEvent actionEvent = new ActionEvent(urlListTable,
+        ActionEvent.ACTION_PERFORMED, "edit");
+
+    @Override
+    public void mouseClicked(MouseEvent e)
+    {
+      if (e.getClickCount() > 1)
+      {
+        editUrlAction.actionPerformed(actionEvent);
+      }
+    }
+  };
+
+  // Setting up URL list Pane
+  {
+    Font font = new Font("Verdana", Font.PLAIN, 10);
+    JPanel urlPaneContainer = new JPanel(new BorderLayout(5, 5));
+    urlPaneContainer.setBorder(BorderFactory.createCompoundBorder(
+        BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
+            "Slivka Web Services"),
+        BorderFactory.createEmptyBorder(10, 5, 5, 5)));
+
+    newWsUrl.setFont(font);
+    editWsUrl.setFont(font);
+    deleteWsUrl.setFont(font);
+    moveUrlUp.setFont(font);
+    moveUrlDown.setFont(font);
+    JPanel editContainer = new JPanel();
+    editContainer.add(newWsUrl);
+    editContainer.add(editWsUrl);
+    editContainer.add(deleteWsUrl);
+    urlPaneContainer.add(editContainer, BorderLayout.PAGE_END);
+
+    JPanel moveContainer = new JPanel();
+    moveContainer
+        .setLayout(new BoxLayout(moveContainer, BoxLayout.PAGE_AXIS));
+    moveContainer.add(moveUrlUp);
+    moveContainer.add(Box.createRigidArea(new Dimension(0, 5)));
+    moveContainer.add(moveUrlDown);
+    urlPaneContainer.add(moveContainer, BorderLayout.LINE_START);
+
+    urlPaneContainer.add(new JScrollPane(urlListTable),
+        BorderLayout.CENTER);
+    this.add(urlPaneContainer);
+
+    // Connecting action listeners
+    urlListTable.addMouseListener(tableClickListener);
+    newWsUrl.addActionListener(newUrlAction);
+    editWsUrl.addActionListener(editUrlAction);
+    deleteWsUrl.addActionListener(deleteUrlAction);
+    moveUrlUp.addActionListener(moveUrlUpAction);
+    moveUrlDown.addActionListener(moveUrlDownAction);
+  }
+
+  private void moveTableRow(int fromIndex, int toIndex)
+  {
+    String url = urls.get(fromIndex);
+    int status = statuses.get(fromIndex);
+    urls.set(fromIndex, urls.get(toIndex));
+    statuses.set(fromIndex, statuses.get(toIndex));
+    urls.set(toIndex, url);
+    statuses.set(toIndex, status);
+    if (urlListTable.getSelectedRow() == fromIndex)
+    {
+      urlListTable.setRowSelectionInterval(toIndex, toIndex);
+    }
+    int firstRow = Math.min(toIndex, fromIndex);
+    int lastRow = Math.max(fromIndex, toIndex);
+    urlTableModel.fireTableRowsUpdated(firstRow, lastRow);
+  }
+
+  // Discoverer reloading buttons
+  JButton refreshServices = new JButton(
+      MessageManager.getString("action.refresh_services"));
+
+  JButton resetServices = new JButton(
+      MessageManager.getString("action.reset_services"));
+
+  JProgressBar progressBar = new JProgressBar();
+
+  // Discoverer buttons action listeners
+  private ActionListener refreshServicesAction = (ActionEvent e) -> {
+    new Thread(() -> {
+      progressBar.setVisible(true);
+      Cache.log.info("Requesting service reload");
+      Desktop.instance.startServiceDiscovery(discoverer, true);
+      Cache.log.info("Reloading done");
+      progressBar.setVisible(false);
+    }).start();
+  };
+
+  private ActionListener resetServicesAction = (ActionEvent e) -> {
+    discoverer.setServiceUrls(null);
+    urls.clear();
+    statuses.clear();
+    urls.addAll(discoverer.getServiceUrls());
+    for (String url : urls)
+    {
+      statuses.add(discoverer.getServerStatusFor(url));
+    }
+    urlTableModel.fireTableDataChanged();
+  };
+
+  {
+    Font font = new Font("Verdana", Font.PLAIN, 11);
+    refreshServices.setFont(font);
+    resetServices.setFont(font);
+    JPanel container = new JPanel();
+    container.add(refreshServices);
+    container.add(resetServices);
+    this.add(container);
+
+    // Connecting action listeners
+    refreshServices.addActionListener(refreshServicesAction);
+    resetServices.addActionListener(resetServicesAction);
+  }
+
+  {
+    progressBar.setVisible(false);
+    progressBar.setIndeterminate(true);
+    add(progressBar);
+  }
+
+  SlivkaPreferences()
+  {
+    // Initial URLs loading
+    discoverer = SlivkaWSDiscoverer.getInstance();
+    urls.addAll(discoverer.getServiceUrls());
+    for (String url : urls)
+    {
+      statuses.add(discoverer.getServerStatusFor(url));
+    }
+  }
+}
index ca11541..34a7c75 100755 (executable)
@@ -314,6 +314,8 @@ public class GPreferences extends JPanel
    */
   protected JPanel wsTab = new JPanel();
 
+  protected JPanel slivkaTab = new JPanel();
+
   /*
    * Backups tab components
    * a lot of these are member variables instead of local variables only so that they
@@ -421,6 +423,8 @@ public class GPreferences extends JPanel
      */
     wsTab.setLayout(new BorderLayout());
     tabbedPane.add(wsTab, MessageManager.getString("label.web_services"));
+    slivkaTab.setLayout(new BorderLayout());
+    tabbedPane.add(slivkaTab, "Slivka Services");
 
     /*
      * Handler to validate a tab before leaving it - currently only for