7 import javax.swing.JFrame;
8 import javax.swing.JOptionPane;
10 import com.formdev.flatlaf.extras.FlatDesktop;
12 import jalview.api.AlignmentViewPanel;
13 import jalview.bin.Console;
14 import jalview.datamodel.AlignmentI;
15 import jalview.datamodel.SequenceI;
16 import jalview.gui.AlignFrame;
17 import jalview.gui.Desktop;
18 import jalview.io.BackupFiles;
19 import jalview.project.Jalview2XML;
20 import jalview.util.MessageManager;
21 import jalview.util.Platform;
23 public class QuitHandler
25 public static enum QResponse
27 QUIT, CANCEL_QUIT, FORCE_QUIT
30 public static void setQuitHandler()
32 FlatDesktop.setQuitHandler(response -> {
33 QResponse qresponse = getQuitResponse();
37 response.performQuit();
40 response.cancelQuit();
43 response.performQuit();
46 response.cancelQuit();
51 private static QResponse gotQuitResponse = QResponse.CANCEL_QUIT;
53 private static QResponse returnResponse(QResponse qresponse)
55 gotQuitResponse = qresponse;
59 public static QResponse gotQuitResponse()
61 return gotQuitResponse;
64 public static QResponse getQuitResponse()
66 return getQuitResponse(true);
69 public static QResponse getQuitResponse(boolean ui)
71 if (gotQuitResponse() != QResponse.CANCEL_QUIT)
73 return returnResponse(getQuitResponse());
76 boolean interactive = ui && !Platform.isHeadless();
77 // confirm quit if needed and wanted
78 boolean confirmQuit = true;
82 Console.debug("Non interactive quit -- not confirming");
85 else if (Jalview2XML.allSavedUpToDate())
87 Console.debug("Nothing changed -- not confirming quit");
92 confirmQuit = jalview.bin.Cache
93 .getDefault(jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
94 Console.debug("Jalview property '"
95 + jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT
96 + "' is/defaults to " + confirmQuit + " -- "
97 + (confirmQuit ? "" : "not ") + "confirming quit");
100 int answer = JOptionPane.OK_OPTION;
102 // if going to confirm, do it before the save in progress check to give
103 // the save time to finish!
108 MessageManager.getString("label.quit_jalview"))
110 .append(MessageManager
111 .getString("label.unsaved_changes"))
113 MessageManager.getString("action.quit"),
114 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
117 if (answer == JOptionPane.CANCEL_OPTION)
119 Console.debug("QuitHandler: Quit action cancelled by user");
120 return returnResponse(QResponse.CANCEL_QUIT);
123 // check for saves in progress
124 int waitForSave = 1000; // MAKE THIS BETTER
125 AlignFrame[] afArray = Desktop.getAlignFrames();
126 if (afArray == null || afArray.length == 0)
133 for (int i = 0; i < afArray.length; i++)
135 AlignFrame af = afArray[i];
136 List<AlignmentViewPanel> avpList = (List<AlignmentViewPanel>) af
138 for (AlignmentViewPanel avp : avpList)
140 AlignmentI a = avp.getAlignment();
141 List<SequenceI> sList = a.getSequences();
142 for (SequenceI s : sList)
144 size += s.getLength();
149 Console.debug("Set waitForSave to " + waitForSave);
151 int waitIncrement = 3000;
152 long startTime = new Date().getTime();
153 boolean saving = BackupFiles.hasSavesInProgress();
156 boolean waiting = (new Date().getTime() - startTime) < waitForSave;
157 while (saving && waiting)
159 saving = !waitForSave(waitIncrement);
160 waiting = (new Date().getTime() - startTime) < waitForSave;
163 if (saving) // still saving after a wait
165 StringBuilder messageSB = new StringBuilder(
166 MessageManager.getString("label.save_in_progress"));
167 messageSB.append(":");
169 for (File file : BackupFiles.savesInProgressFiles())
171 messageSB.append("\n- ");
172 messageSB.append(file.getName());
177 messageSB.append("\n");
178 messageSB.append(MessageManager.getString("label.unknown"));
180 int waitLonger = interactive ? JOptionPane.YES_OPTION
181 : JOptionPane.NO_OPTION;
182 while (saving && waitLonger == JOptionPane.YES_OPTION)
184 waitLonger = waitForceQuitCancelQuitOptionDialog(
185 messageSB.toString(),
186 MessageManager.getString("action.wait"));
187 if (waitLonger == JOptionPane.YES_OPTION) // wait
190 saving = !waitForSave(waitIncrement);
192 else if (waitLonger == JOptionPane.NO_OPTION) // force quit
195 return returnResponse(QResponse.FORCE_QUIT); // shouldn't reach this
197 else if (waitLonger == JOptionPane.CANCEL_OPTION) // cancel quit
199 return returnResponse(QResponse.CANCEL_QUIT);
203 Console.debug("**** Shouldn't have got here!");
209 // not cancelled and not saving
210 return returnResponse(QResponse.QUIT);
213 public static int frameOnTop(String label, String actionString,
214 int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE)
216 return frameOnTop(new JFrame(), label, actionString, JOPTIONPANE_OPTION,
217 JOPTIONPANE_MESSAGETYPE);
220 public static int frameOnTop(JFrame dialogParent, String label,
221 String actionString, int JOPTIONPANE_OPTION,
222 int JOPTIONPANE_MESSAGETYPE)
224 // ensure Jalview window is brought to front for Quit confirmation
225 // window to be visible
227 // this method of raising the Jalview window is broken in java
228 // jalviewDesktop.setVisible(true);
229 // jalviewDesktop.toFront();
231 // a better hack which works instead
233 dialogParent.setAlwaysOnTop(true);
235 int answer = JOptionPane.showConfirmDialog(dialogParent, label,
236 actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE);
238 dialogParent.setAlwaysOnTop(false);
239 dialogParent.dispose();
244 private static int waitForceQuitCancelQuitOptionDialog(Object message,
247 JFrame dialogParent = new JFrame();
248 dialogParent.setAlwaysOnTop(true);
249 String wait = MessageManager.getString("action.wait");
250 Object[] options = { wait,
251 MessageManager.getString("action.force_quit"),
252 MessageManager.getString("action.cancel_quit") };
254 int answer = JOptionPane.showOptionDialog(dialogParent, message, title,
255 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
256 null, options, wait);
261 private static boolean waitForSave(long t)
266 Console.debug("Wait for save to complete: " + t + "ms");
273 ret = !BackupFiles.hasSavesInProgress();
277 "Save completed whilst waiting (" + c + "/" + t + "ms)");
280 if (c % 1000 < i) // just gone over another second
282 Console.debug("...waiting (" + c + "/" + t + "ms]");
285 } catch (InterruptedException e)
287 Console.debug("Wait for save interrupted");
289 Console.debug("Save has " + (ret ? "" : "not ") + "completed");