From 9b943e6d79fd92f78a61916a6f6eb047ba0a9755 Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Mon, 13 Feb 2023 19:16:08 +0000 Subject: [PATCH] JAL-4125 Move confirmation of closing external viewer windows into the quit handler, and allow all to close or not in closeViewer whilst quitting. --- resources/lang/Messages.properties | 3 + .../api/structures/JalviewStructureDisplayI.java | 5 ++ src/jalview/gui/Desktop.java | 25 ++++-- src/jalview/gui/QuitHandler.java | 40 +++++++++ src/jalview/gui/StructureViewerBase.java | 95 ++++++++------------ 5 files changed, 103 insertions(+), 65 deletions(-) diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 9425804..1ad60be 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -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}.
Do you want to close the {1} window as well? label.all = All label.sort_by = Sort alignment by diff --git a/src/jalview/api/structures/JalviewStructureDisplayI.java b/src/jalview/api/structures/JalviewStructureDisplayI.java index d0351a8..a1b92df 100644 --- a/src/jalview/api/structures/JalviewStructureDisplayI.java +++ b/src/jalview/api/structures/JalviewStructureDisplayI.java @@ -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 diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 06afe81..dbc99c0 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -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) { diff --git a/src/jalview/gui/QuitHandler.java b/src/jalview/gui/QuitHandler.java index ae12e7d..f9110eb 100644 --- a/src/jalview/gui/QuitHandler.java +++ b/src/jalview/gui/QuitHandler.java @@ -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) { diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 9a575ff..01a3c2d 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -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 yesCall = () -> { - Console.debug("YES"); - confirmResponse = JvOptionPane.YES_OPTION; - return null; - }; - Callable noCall = () -> { - Console.debug("NO"); - confirmResponse = JvOptionPane.NO_OPTION; - return null; - }; - Callable cancelCall = () -> { - Console.debug("CANCEL"); - confirmResponse = JvOptionPane.CANCEL_OPTION; - return null; - }; - Callable[] 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; } -- 1.7.10.2