JAL-1988 JAL-3772 Removed 'Wait' button from waitDialog, no iterations for GUI. Added...
authorBen Soares <b.soares@dundee.ac.uk>
Fri, 28 Oct 2022 23:16:20 +0000 (00:16 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Fri, 28 Oct 2022 23:16:20 +0000 (00:16 +0100)
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/gui/Desktop.java
src/jalview/gui/JvOptionPane.java
src/jalview/jbgui/QuitHandler.java

index 1f57096..a406f33 100644 (file)
@@ -32,11 +32,13 @@ action.load_project = Load Project
 action.save_project = Save Project
 action.save_project_as = Save Project as...
 action.quit = Quit
-action.force_quit = Force Quit
+action.force_quit = Force quit
 label.quit_jalview = Are you sure you want to quit Jalview?
+label.wait_for_save = Wait for save
 label.unsaved_changes = There are unsaved changes.
 label.save_in_progress = Some files are still saving:
 label.unknown = Unknown
+label.quit_after_saving = Jalview will quit after saving.
 label.all_saved = All files saved.
 label.quitting_bye = Quitting, bye!
 action.wait = Wait
index d1b6b4e..b50226a 100644 (file)
@@ -34,9 +34,11 @@ action.save_project_as = Guardar proyecto como...
 action.quit = Salir
 action.force_quit = Forzar la salida
 label.quit_jalview = ¿Estás seguro de que quieres salir de Jalview?
+label.wait_for_save = Esperar a guardar
 label.unsaved_changes = Hay cambios sin guardar.
 label.save_in_progress = Algunos archivos aún se están guardando:
 label.unknown = desconocido
+label.quit_after_saving = Jalview se cerrará después de guardar.
 label.all_saved = Todos los archivos guardados.
 label.quitting_bye = Saliendo ¡chao!
 action.wait = Espere
index 13253c3..72c9106 100644 (file)
@@ -1396,11 +1396,7 @@ public class Desktop extends jalview.jbgui.GDesktop
         instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
         // instance.dispose();
       }
-      jalview.bin.Console.debug("**** BEFORE quit");
-      jalview.bin.Console.debug("**** QuitHandler.gotQuitResponse="
-              + QuitHandler.gotQuitResponse());
       instance.quit();
-      jalview.bin.Console.debug("**** AFTER quit");
 
       return QuitHandler.gotQuitResponse();
     };
index 02bca5a..10dbfcf 100644 (file)
@@ -22,6 +22,7 @@
 package jalview.gui;
 
 import java.awt.Component;
+import java.awt.Container;
 import java.awt.Dialog.ModalityType;
 import java.awt.HeadlessException;
 import java.awt.Window;
@@ -781,6 +782,14 @@ public class JvOptionPane extends JOptionPane
           int messageType, Icon icon, Object[] options, Object initialValue,
           boolean modal)
   {
+    showDialog(message, title, optionType, messageType, icon, options,
+            initialValue, modal, null);
+  }
+
+  public void showDialog(Object message, String title, int optionType,
+          int messageType, Icon icon, Object[] options, Object initialValue,
+          boolean modal, JButton[] buttons)
+  {
     if (!isInteractiveMode())
     {
       handleResponse(getMockResponse());
@@ -804,9 +813,92 @@ public class JvOptionPane extends JOptionPane
 
     if (modal)
     {
+      boolean useButtons = false;
+      Object initialValueButton = null;
+      NOTNULL: if (buttons != null)
+      {
+        if (buttons.length != options.length)
+        {
+          jalview.bin.Console.error(
+                  "Supplied buttons array not the same length as supplied options array.");
+          break NOTNULL;
+        }
+        int[] buttonActions = { JOptionPane.YES_OPTION,
+            JOptionPane.NO_OPTION, JOptionPane.CANCEL_OPTION };
+        for (int i = 0; i < options.length; i++)
+        {
+          Object o = options[i];
+          jalview.bin.Console.debug(
+                  "Setting button " + i + " to '" + o.toString() + "'");
+          JButton jb = buttons[i];
+
+          if (o.equals(initialValue))
+            initialValueButton = jb;
+
+          int buttonAction = buttonActions[i];
+          Callable action = callbacks.get(buttonAction);
+          jb.setText((String) o);
+          jb.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+
+              Object obj = e.getSource();
+              Object joptionpaneObject = getAncestorClass(obj,
+                      JOptionPane.class);
+              if (joptionpaneObject == null
+                      || !(joptionpaneObject instanceof JOptionPane))
+              {
+                jalview.bin.Console.debug(
+                        "Could not find JOptionPane ancestor of event object "
+                                + obj);
+                return;
+              }
+              JOptionPane joptionpane = (JOptionPane) joptionpaneObject;
+              joptionpane.setValue(buttonAction);
+              if (action != null)
+                Executors.newSingleThreadExecutor().submit(action);
+              // joptionpane.transferFocusBackward();
+              joptionpane.transferFocusBackward();
+              joptionpane.setVisible(false);
+              // put focus and raise parent window if possible, unless cancel
+              // button pressed
+              boolean raiseParent = (parentComponent != null);
+              if (buttonAction == JOptionPane.CANCEL_OPTION)
+                raiseParent = false;
+              if (optionType == JOptionPane.YES_NO_OPTION
+                      && buttonAction == JOptionPane.NO_OPTION)
+                raiseParent = false;
+              if (raiseParent)
+              {
+                parentComponent.requestFocus();
+                if (parentComponent instanceof JInternalFrame)
+                {
+                  JInternalFrame jif = (JInternalFrame) parentComponent;
+                  jif.show();
+                  jif.moveToFront();
+                  jif.grabFocus();
+                }
+                else if (parentComponent instanceof Window)
+                {
+                  Window w = (Window) parentComponent;
+                  w.toFront();
+                  w.requestFocus();
+                }
+              }
+              joptionpane.setVisible(false);
+            }
+          });
+
+        }
+        useButtons = true;
+      }
       // use a JOptionPane as usual
       int response = JOptionPane.showOptionDialog(parentComponent, message,
-              title, optionType, messageType, icon, options, initialValue);
+              title, optionType, messageType, icon,
+              useButtons ? buttons : options,
+              useButtons ? initialValueButton : initialValue);
 
       /*
        * In Java, the response is returned to this thread and handled here;
@@ -830,8 +922,9 @@ public class JvOptionPane extends JOptionPane
        * a non-modal JDialog for the confirmation without blocking the GUI.
        */
 
-      JDialog dialog = this.createDialog(parentComponent, message, title,
-              optionType, messageType, icon, options, initialValue, modal);
+      JDialog dialog = createDialog(parentComponent, message, title,
+              optionType, messageType, icon, options, initialValue, modal,
+              buttons);
       jalview.bin.Console.debug("About to setVisible(true)");
       dialog.setVisible(true);
       jalview.bin.Console.debug("Just setVisible(true)");
@@ -918,9 +1011,7 @@ public class JvOptionPane extends JOptionPane
             actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE);
 
     dialogParent.setAlwaysOnTop(false);
-    jalview.bin.Console.debug("*********** BEFORE dialogParent.dispose()");
     dialogParent.dispose();
-    jalview.bin.Console.debug("*********** BEFORE dialogParent.dispose()");
 
     return answer;
   }
@@ -939,6 +1030,16 @@ public class JvOptionPane extends JOptionPane
           int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
           Object initialValue, boolean modal)
   {
+    showDialogOnTopAsync(dialogParent, label, actionString,
+            JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE, icon, options,
+            initialValue, modal, null);
+  }
+
+  public void showDialogOnTopAsync(JFrame dialogParent, Object label,
+          String actionString, int JOPTIONPANE_OPTION,
+          int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
+          Object initialValue, boolean modal, JButton[] buttons)
+  {
     // Ensure Jalview window is brought to front (primarily for Quit
     // confirmation window to be visible)
 
@@ -952,7 +1053,8 @@ public class JvOptionPane extends JOptionPane
     parentComponent = dialogParent;
 
     showDialog(label, actionString, JOPTIONPANE_OPTION,
-            JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal);
+            JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal,
+            buttons);
 
     dialogParent.setAlwaysOnTop(false);
     dialogParent.dispose();
@@ -1013,6 +1115,17 @@ public class JvOptionPane extends JOptionPane
           String title, int optionType, int messageType, Icon icon,
           Object[] options, Object initialValue, boolean modal)
   {
+    return createDialog(parentComponent, message, title, optionType,
+            messageType, icon, options, initialValue, modal, null);
+  }
+
+  public JDialog createDialog(Component parentComponent, Object message,
+          String title, int optionType, int messageType, Icon icon,
+          Object[] options, Object initialValue, boolean modal,
+          JButton[] buttons)
+  {
+    JButton[] optionsButtons = null;
+    Object initialValueButton = null;
     JOptionPane joptionpane = new JOptionPane();
     // Make button options
     int[] buttonActions = { JOptionPane.YES_OPTION, JOptionPane.NO_OPTION,
@@ -1035,26 +1148,39 @@ public class JvOptionPane extends JOptionPane
       }
       options = options_default.toArray();
     }
-    ArrayList<JButton> options_btns = new ArrayList<>();
-    Object initialValue_btn = null;
     if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
                           // add them here
     {
-      if (((optionType == JOptionPane.YES_NO_OPTION
-              || optionType == JOptionPane.OK_CANCEL_OPTION)
-              && options.length < 2)
+      if (((optionType == JOptionPane.YES_OPTION
+              || optionType == JOptionPane.NO_OPTION
+              || optionType == JOptionPane.CANCEL_OPTION
+              || optionType == JOptionPane.OK_OPTION
+              || optionType == JOptionPane.DEFAULT_OPTION)
+              && options.length < 1)
+              || ((optionType == JOptionPane.YES_NO_OPTION
+                      || optionType == JOptionPane.OK_CANCEL_OPTION)
+                      && options.length < 2)
               || (optionType == JOptionPane.YES_NO_CANCEL_OPTION
                       && options.length < 3))
       {
         jalview.bin.Console
                 .debug("JvOptionPane: not enough options for dialog type");
       }
+      optionsButtons = new JButton[options.length];
       for (int i = 0; i < options.length && i < 3; i++)
       {
         Object o = options[i];
         int buttonAction = buttonActions[i];
         Callable action = callbacks.get(buttonAction);
-        JButton jb = new JButton();
+        JButton jb;
+        if (buttons != null && buttons.length > i && buttons[i] != null)
+        {
+          jb = buttons[i];
+        }
+        else
+        {
+          jb = new JButton();
+        }
         jb.setText((String) o);
         jb.addActionListener(new ActionListener()
         {
@@ -1095,19 +1221,18 @@ public class JvOptionPane extends JOptionPane
             joptionpane.setVisible(false);
           }
         });
-        options_btns.add(jb);
+        optionsButtons[i] = jb;
         if (o.equals(initialValue))
-          initialValue_btn = jb;
+          initialValueButton = jb;
       }
     }
     joptionpane.setMessage(message);
     joptionpane.setMessageType(messageType);
     joptionpane.setOptionType(optionType);
     joptionpane.setIcon(icon);
-    joptionpane
-            .setOptions(Platform.isJS() ? options : options_btns.toArray());
+    joptionpane.setOptions(Platform.isJS() ? options : optionsButtons);
     joptionpane.setInitialValue(
-            Platform.isJS() ? initialValue : initialValue_btn);
+            Platform.isJS() ? initialValue : initialValueButton);
 
     JDialog dialog = joptionpane.createDialog(parentComponent, title);
     dialog.setModalityType(
@@ -1126,4 +1251,28 @@ public class JvOptionPane extends JOptionPane
 
     return false;
   }
+
+  /**
+   * Get parent JOptionPane if there is one
+   */
+  public static Container getAncestorClass(Object o, Class cl)
+  {
+    Container c;
+    if (o instanceof Container)
+      c = (Container) o;
+    else
+      return null;
+    Container p = c.getParent();
+    if (p == null)
+      return null;
+    if (p.getClass() == cl)
+    {
+      return p;
+    }
+    else if (p instanceof Component)
+    {
+      return getAncestorClass((Component) p, cl);
+    }
+    return null;
+  }
 }
index ef8ec55..0d73006 100644 (file)
@@ -10,6 +10,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 import javax.swing.JTextPane;
@@ -31,7 +32,7 @@ import jalview.util.Platform;
 
 public class QuitHandler
 {
-  private static final int MIN_WAIT_FOR_SAVE = 5000;
+  private static final int MIN_WAIT_FOR_SAVE = 3000;
 
   private static final int MAX_WAIT_FOR_SAVE = 20000;
 
@@ -247,7 +248,8 @@ public class QuitHandler
     QResponse waitResponse = QResponse.NULL;
 
     int iteration = 0;
-    boolean doIterations = true;
+    boolean doIterations = true; // note iterations not used in the gui now,
+                                 // only one pass without the "Wait" button
     while (doIterations && BackupFiles.hasSavesInProgress()
             && iteration++ < (interactive ? 100 : 5))
     {
@@ -281,24 +283,11 @@ public class QuitHandler
 
       if (interactive && BackupFiles.hasSavesInProgress())
       {
-        boolean allowForceQuit = iteration > 0; // iteration > 1 to not show
-                                                // force quit the first time
+        boolean showForceQuit = iteration > 0; // iteration > 1 to not show
+                                               // force quit the first time
         JFrame parent = new JFrame();
+        JButton[] buttons = { new JButton(), new JButton() };
         JvOptionPane waitDialog = JvOptionPane.newOptionDialog();
-        if (allowForceQuit)
-        {
-          waitDialog
-                  .setResponseHandler(JOptionPane.YES_OPTION, defaultOkQuit)
-                  .setResponseHandler(JOptionPane.NO_OPTION, forceQuit)
-                  .setResponseHandler(JOptionPane.CANCEL_OPTION,
-                          cancelQuit);
-        }
-        else
-        {
-          waitDialog
-                  .setResponseHandler(JOptionPane.YES_OPTION, defaultOkQuit)
-                  .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit);
-        }
         JTextPane messagePane = new JTextPane();
         messagePane.setBackground(waitDialog.getBackground());
         messagePane.setBorder(null);
@@ -309,48 +298,64 @@ public class QuitHandler
         {
           cf.whenComplete((ret, e) -> {
             if (BackupFiles.hasSavesInProgress())
+            {
               // update the list of saving files as they save too
               messagePane.setText(waitingForSaveMessage());
+            }
             else
             {
-              // if this is the last one then close the dialog
-              messagePane.setText(new StringBuilder()
-                      .append(MessageManager.getString("label.all_saved"))
-                      .append("\n").append(MessageManager
-                              .getString("label.quitting_bye"))
-                      .toString());
-              try
-              {
-                Console.debug("WAITING FOR MESSAGE");
-                Thread.sleep(500);
-              } catch (InterruptedException e1)
+              if (!(QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT
+                      || QuitHandler.gotQuitResponse() == QResponse.NULL))
               {
+                for (int i = 0; i < buttons.length; i++)
+                {
+                  Console.debug("DISABLING BUTTON " + buttons[i].getText());
+                  buttons[i].setEnabled(false);
+                  buttons[i].setVisible(false);
+                }
+                // if this is the last one then close the dialog
+                messagePane.setText(new StringBuilder()
+                        .append(MessageManager.getString("label.all_saved"))
+                        .append("\n")
+                        .append(MessageManager
+                                .getString("label.quitting_bye"))
+                        .toString());
+                messagePane.setEditable(false);
+                try
+                {
+                  Thread.sleep(1500);
+                } catch (InterruptedException e1)
+                {
+                }
+                parent.dispose();
               }
-              // like a click on Wait button
-              waitDialog.setValue(JOptionPane.YES_OPTION);
-              parent.dispose();
             }
           });
         }
 
-        String[] options = new String[allowForceQuit ? 3 : 2];
-        if (allowForceQuit)
+        String[] options;
+        int dialogType = -1;
+        if (showForceQuit)
         {
-          options[0] = MessageManager.getString("action.wait");
-          options[1] = MessageManager.getString("action.force_quit");
-          options[2] = MessageManager.getString("action.cancel_quit");
+          options = new String[2];
+          options[0] = MessageManager.getString("action.force_quit");
+          options[1] = MessageManager.getString("action.cancel_quit");
+          dialogType = JOptionPane.YES_NO_OPTION;
+          waitDialog.setResponseHandler(JOptionPane.YES_OPTION, forceQuit)
+                  .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit);
         }
         else
         {
-          options[0] = MessageManager.getString("action.wait");
-          options[1] = MessageManager.getString("action.cancel_quit");
+          options = new String[1];
+          options[0] = MessageManager.getString("action.cancel_quit");
+          dialogType = JOptionPane.YES_OPTION;
+          waitDialog.setResponseHandler(JOptionPane.YES_OPTION, cancelQuit);
         }
         waitDialog.showDialogOnTopAsync(parent, messagePane,
-                MessageManager.getString("action.wait"),
-                allowForceQuit ? JOptionPane.YES_NO_CANCEL_OPTION
-                        : JOptionPane.YES_NO_OPTION,
+                MessageManager.getString("label.wait_for_save"), dialogType,
                 JOptionPane.WARNING_MESSAGE, null, options,
-                MessageManager.getString("action.wait"), true);
+                MessageManager.getString("action.cancel_quit"), true,
+                buttons);
 
         parent.dispose();
         final QResponse thisWaitResponse = gotQuitResponse();
@@ -377,23 +382,6 @@ public class QuitHandler
     return waitResponse;
   };
 
-  private static int waitForceQuitCancelQuitOptionDialog(Object message,
-          String title)
-  {
-    JFrame dialogParent = new JFrame();
-    dialogParent.setAlwaysOnTop(true);
-    String wait = MessageManager.getString("action.wait");
-    Object[] options = { wait,
-        MessageManager.getString("action.force_quit"),
-        MessageManager.getString("action.cancel_quit") };
-
-    int answer = JOptionPane.showOptionDialog(dialogParent, message, title,
-            JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
-            null, options, wait);
-
-    return answer;
-  }
-
   private static String waitingForSaveMessage()
   {
     StringBuilder messageSB = new StringBuilder();
@@ -405,14 +393,15 @@ public class QuitHandler
     {
       for (File file : files)
       {
-        messageSB.append("\n- ").append(file.getName());
+        messageSB.append("\n\u2022 ").append(file.getName());
       }
     }
     else
     {
       messageSB.append(MessageManager.getString("label.unknown"));
     }
+    messageSB.append("\n\n")
+            .append(MessageManager.getString("label.quit_after_saving"));
     return messageSB.toString();
   }
-
 }
\ No newline at end of file