JAL-4125 Move confirmation of closing external viewer windows into the quit handler...
authorBen Soares <b.soares@dundee.ac.uk>
Mon, 13 Feb 2023 19:16:08 +0000 (19:16 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Mon, 13 Feb 2023 19:16:08 +0000 (19:16 +0000)
resources/lang/Messages.properties
src/jalview/api/structures/JalviewStructureDisplayI.java
src/jalview/gui/Desktop.java
src/jalview/gui/QuitHandler.java
src/jalview/gui/StructureViewerBase.java

index 9425804..1ad60be 100644 (file)
@@ -37,6 +37,8 @@ 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.confirm_quit_viewer = An external viewer is still open.  Close the external window as well?
+label.confirm_quit_viewers = External viewers are still open.  Close these external windows as well?
 label.unknown = Unknown
 label.quit_after_saving = Jalview will quit after saving.
 label.all_saved = All files saved.
@@ -514,6 +516,7 @@ label.delete_gaps = Delete {0} gaps
 label.sequence_details = Sequence Details
 label.viewer_help = {0} Help
 label.close_viewer = Close Viewer
+label.close_viewers = Close Viewers
 label.confirm_close_viewer = This will close Jalview''s connection to {0}.<br>Do you want to close the {1} window as well?
 label.all = All
 label.sort_by = Sort alignment by
index d0351a8..a1b92df 100644 (file)
@@ -58,6 +58,11 @@ public interface JalviewStructureDisplayI
   void closeViewer(boolean closeExternalViewer);
 
   /**
+   * Check if the external viewer is still running
+   */
+  boolean stillRunning();
+
+  /**
    * 
    * @return true if all background sequence/structure binding threads have
    *         completed for this viewer instance
index 06afe81..dbc99c0 100644 (file)
@@ -102,6 +102,7 @@ import org.stackoverflowusers.file.WindowsShortcut;
 
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
 import jalview.gui.ImageExporter.ImageWriterI;
@@ -1377,6 +1378,8 @@ public class Desktop extends jalview.jbgui.GDesktop
         storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
       }
 
+      // Frames should all close automatically. Keeping external
+      // viewers open should already be decided by user.
       closeAll_actionPerformed(null);
 
       // check for aborted quit
@@ -1551,17 +1554,11 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     // TODO show a progress bar while closing?
     JInternalFrame[] frames = desktop.getAllFrames();
-    boolean quitting = QuitHandler.quitting();
     for (int i = 0; i < frames.length; i++)
     {
       try
       {
         frames[i].setClosed(true);
-        // check for cancelled quit
-        if (quitting && QuitHandler.quitCancelled())
-        {
-          return;
-        }
       } catch (java.beans.PropertyVetoException ex)
       {
       }
@@ -1581,6 +1578,22 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
   }
 
+  public int structureViewersStillRunningCount()
+  {
+    int count = 0;
+    JInternalFrame[] frames = desktop.getAllFrames();
+    for (int i = 0; i < frames.length; i++)
+    {
+      if (frames[i] != null
+              && frames[i] instanceof JalviewStructureDisplayI)
+      {
+        if (((JalviewStructureDisplayI) frames[i]).stillRunning())
+          count++;
+      }
+    }
+    return count;
+  }
+
   @Override
   public void raiseRelated_actionPerformed(ActionEvent e)
   {
index ae12e7d..f9110eb 100644 (file)
@@ -166,6 +166,46 @@ public class QuitHandler
     }
 
     got = gotQuitResponse();
+
+    // check for external viewer frames
+    if (got != QResponse.CANCEL_QUIT)
+    {
+      int count = Desktop.instance.structureViewersStillRunningCount();
+      if (count > 0)
+      {
+        String prompt = MessageManager
+                .formatMessage(count == 1 ? "label.confirm_quit_viewer"
+                        : "label.confirm_quit_viewers");
+        String title = MessageManager.getString(
+                count == 1 ? "label.close_viewer" : "label.close_viewers");
+        String cancelQuitText = MessageManager
+                .getString("action.cancel_quit");
+        String[] buttonsText = { MessageManager.getString("action.yes"),
+            MessageManager.getString("action.no"), cancelQuitText };
+
+        int confirmResponse = JvOptionPane.showOptionDialog(
+                Desktop.instance, prompt, title,
+                JvOptionPane.YES_NO_CANCEL_OPTION,
+                JvOptionPane.WARNING_MESSAGE, null, buttonsText,
+                cancelQuit);
+
+        if (confirmResponse == JvOptionPane.CANCEL_OPTION)
+        {
+          // Cancel Quit
+          QuitHandler.setResponse(QResponse.CANCEL_QUIT);
+        }
+        else
+        {
+          // Close viewers/Leave viewers open
+          StructureViewerBase
+                  .setQuitClose(confirmResponse == JvOptionPane.YES_OPTION);
+        }
+      }
+
+    }
+
+    got = gotQuitResponse();
+
     boolean wait = false;
     if (got == QResponse.CANCEL_QUIT)
     {
index 9a575ff..01a3c2d 100644 (file)
@@ -37,9 +37,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 import java.util.Vector;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
 
 import javax.swing.ButtonGroup;
 import javax.swing.JCheckBoxMenuItem;
@@ -1255,6 +1252,20 @@ public abstract class StructureViewerBase extends GStructureViewer
     return session;
   }
 
+  private static boolean quitClose = false;
+
+  public static void setQuitClose(boolean b)
+  {
+    quitClose = b;
+  }
+
+  @Override
+  public boolean stillRunning()
+  {
+    AAStructureBindingModel binding = getBinding();
+    return binding != null && binding.isViewerRunning();
+  }
+
   /**
    * Close down this instance of Jalview's Chimera viewer, giving the user the
    * option to close the associated Chimera window (process). They may wish to
@@ -1267,19 +1278,29 @@ public abstract class StructureViewerBase extends GStructureViewer
   public void closeViewer(boolean forceClose)
   {
     AAStructureBindingModel binding = getBinding();
-    if (binding != null && binding.isViewerRunning())
+    if (stillRunning())
     {
       if (!forceClose)
       {
         String viewerName = getViewerName();
 
         int confirm = JvOptionPane.CANCEL_OPTION;
-        String prompt = MessageManager
-                .formatMessage("label.confirm_close_viewer", new Object[]
-                { binding.getViewerTitle(viewerName, false), viewerName });
-        prompt = JvSwingUtils.wrapTooltip(true, prompt);
-        String title = MessageManager.getString("label.close_viewer");
-        confirm = showCloseDialog(title, prompt);
+        if (QuitHandler.quitting())
+        {
+          // already asked about closing external windows
+          confirm = quitClose ? JvOptionPane.YES_OPTION
+                  : JvOptionPane.NO_OPTION;
+        }
+        else
+        {
+          String prompt = MessageManager
+                  .formatMessage("label.confirm_close_viewer", new Object[]
+                  { binding.getViewerTitle(viewerName, false),
+                      viewerName });
+          prompt = JvSwingUtils.wrapTooltip(true, prompt);
+          String title = MessageManager.getString("label.close_viewer");
+          confirm = showCloseDialog(title, prompt);
+        }
 
         /*
          * abort closure if user hits escape or Cancel
@@ -1320,54 +1341,11 @@ public abstract class StructureViewerBase extends GStructureViewer
 
   private int showCloseDialog(final String title, final String prompt)
   {
-    confirmResponse = JvOptionPane.CANCEL_OPTION;
-
-    if (QuitHandler.quitting())
-    {
-
-      Callable<Void> yesCall = () -> {
-        Console.debug("YES");
-        confirmResponse = JvOptionPane.YES_OPTION;
-        return null;
-      };
-      Callable<Void> noCall = () -> {
-        Console.debug("NO");
-        confirmResponse = JvOptionPane.NO_OPTION;
-        return null;
-      };
-      Callable<Void> cancelCall = () -> {
-        Console.debug("CANCEL");
-        confirmResponse = JvOptionPane.CANCEL_OPTION;
-        return null;
-      };
-      Callable<Void>[] calls = new Callable[] { yesCall, noCall,
-          cancelCall };
-      String cancelQuit = MessageManager.getString("action.cancel_quit");
-      String[] buttonsText = { MessageManager.getString("action.yes"),
-          MessageManager.getString("action.no"), cancelQuit };
-      JvOptionPane dialog = JvOptionPane.frameDialog(prompt,
-              MessageManager.getString("label.close_viewer"),
-              JvOptionPane.WARNING_MESSAGE, buttonsText, cancelQuit, calls,
-              false);
-      // wait for response
-      ExecutorService executor = dialog.getExecutor();
-      executor.shutdown();
-      try
-      {
-        Console.debug("### executor.awaitTermination() starting");
-        executor.awaitTermination(60, TimeUnit.SECONDS);
-        Console.debug("### executor.awaitTermination() finished");
-      } catch (InterruptedException e)
-      {
-      }
-    }
-    else
-    {
-      confirmResponse = JvOptionPane.showConfirmDialog(this, prompt,
-              MessageManager.getString("label.close_viewer"),
-              JvOptionPane.YES_NO_CANCEL_OPTION,
-              JvOptionPane.WARNING_MESSAGE);
-    }
+    int confirmResponse = JvOptionPane.CANCEL_OPTION;
+    confirmResponse = JvOptionPane.showConfirmDialog(this, prompt,
+            MessageManager.getString("label.close_viewer"),
+            JvOptionPane.YES_NO_CANCEL_OPTION,
+            JvOptionPane.WARNING_MESSAGE);
     return confirmResponse;
   }
 
@@ -1402,5 +1380,4 @@ public abstract class StructureViewerBase extends GStructureViewer
             && viewerActionMenu.isVisible();
   }
 
-  private static int confirmResponse = 0;
 }