6 import javax.swing.JFrame;
7 import javax.swing.JOptionPane;
9 import com.formdev.flatlaf.extras.FlatDesktop;
11 import jalview.bin.Console;
12 import jalview.io.BackupFiles;
13 import jalview.util.MessageManager;
14 import jalview.util.Platform;
16 public class QuitHandler
18 public static enum QResponse
20 QUIT, CANCEL_QUIT, FORCE_QUIT
23 public static void setQuitHandler()
25 FlatDesktop.setQuitHandler(response -> {
26 QResponse qresponse = getQuitResponse();
30 response.performQuit();
33 response.cancelQuit();
36 response.performQuit();
39 response.cancelQuit();
44 private static QResponse gotQuitResponse = QResponse.CANCEL_QUIT;
46 private static QResponse returnResponse(QResponse qresponse)
48 gotQuitResponse = qresponse;
52 public static QResponse gotQuitResponse()
54 return gotQuitResponse;
57 public static QResponse getQuitResponse()
59 return getQuitResponse(true);
62 public static QResponse getQuitResponse(boolean ui)
64 if (gotQuitResponse() != QResponse.CANCEL_QUIT)
66 return returnResponse(getQuitResponse());
69 boolean interactive = ui && !Platform.isHeadless();
70 // confirm quit if needed and wanted
71 boolean confirmQuit = true;
75 Console.debug("Non interactive quit -- not confirming");
79 else if (undostack is empty) {
80 Console.debug("Nothing changed -- not confirming quit");
86 confirmQuit = jalview.bin.Cache
87 .getDefault(jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
88 Console.debug("Jalview property '"
89 + jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT
90 + "' is/defaults to " + confirmQuit + " -- "
91 + (confirmQuit ? "" : "not ") + "confirming quit");
94 int answer = JOptionPane.OK_OPTION;
96 // if going to confirm, do it before the save in progress check to give
97 // the save time to finish!
100 answer = frameOnTop(MessageManager.getString("label.quit_jalview"),
101 MessageManager.getString("action.quit"),
102 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
105 if (answer == JOptionPane.CANCEL_OPTION)
107 Console.debug("QuitHandler: Quit action cancelled by user");
108 return returnResponse(QResponse.CANCEL_QUIT);
111 // check for saves in progress
112 int waitForSave = 5000; // MAKE THIS BETTER
113 int waitIncrement = 2000;
114 long startTime = new Date().getTime();
115 boolean saving = BackupFiles.hasSavesInProgress();
118 boolean waiting = (new Date().getTime() - startTime) < waitForSave;
119 while (saving && waiting)
121 saving = !waitForSave(waitIncrement);
122 waiting = (new Date().getTime() - startTime) < waitForSave;
125 if (saving) // still saving after a wait
127 StringBuilder messageSB = new StringBuilder(
128 MessageManager.getString("label.save_in_progress"));
129 for (File file : BackupFiles.savesInProgressFiles())
131 messageSB.append("\n");
132 messageSB.append(file.getName());
134 int waitLonger = interactive ? JOptionPane.YES_OPTION
135 : JOptionPane.NO_OPTION;
136 while (saving && waitLonger == JOptionPane.YES_OPTION)
138 waitLonger = waitForceQuitCancelQuitOptionDialog(
139 messageSB.toString(),
140 MessageManager.getString("action.wait"));
141 if (waitLonger == JOptionPane.YES_OPTION) // wait
143 Console.debug("*** YES answer=" + waitLonger);
145 saving = !waitForSave(waitIncrement);
147 else if (waitLonger == JOptionPane.NO_OPTION) // force quit
149 Console.debug("*** NO answer=" + waitLonger);
151 return returnResponse(QResponse.FORCE_QUIT); // shouldn't reach this
153 else if (waitLonger == JOptionPane.CANCEL_OPTION) // cancel quit
155 Console.debug("*** CANCEL answer=" + waitLonger);
156 return returnResponse(QResponse.CANCEL_QUIT);
160 Console.debug("**** Shouldn't have got here!");
166 // not cancelled and not saving
167 return returnResponse(QResponse.QUIT);
170 public static int frameOnTop(String label, String actionString,
171 int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE)
173 return frameOnTop(new JFrame(), label, actionString, JOPTIONPANE_OPTION,
174 JOPTIONPANE_MESSAGETYPE);
177 public static int frameOnTop(JFrame dialogParent, String label,
178 String actionString, int JOPTIONPANE_OPTION,
179 int JOPTIONPANE_MESSAGETYPE)
181 // ensure Jalview window is brought to front for Quit confirmation
182 // window to be visible
184 // this method of raising the Jalview window is broken in java
185 // jalviewDesktop.setVisible(true);
186 // jalviewDesktop.toFront();
188 // a better hack which works instead
190 dialogParent.setAlwaysOnTop(true);
192 int answer = JOptionPane.showConfirmDialog(dialogParent, label,
193 actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE);
195 dialogParent.setAlwaysOnTop(false);
196 dialogParent.dispose();
201 private static int waitForceQuitCancelQuitOptionDialog(Object message,
204 JFrame dialogParent = new JFrame();
205 dialogParent.setAlwaysOnTop(true);
206 String wait = MessageManager.getString("action.wait");
207 Object[] options = { wait,
208 MessageManager.getString("action.force_quit"),
209 MessageManager.getString("action.cancel_quit") };
211 int answer = JOptionPane.showOptionDialog(dialogParent, message, title,
212 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
213 null, options, wait);
218 private static boolean waitForSave(long t)
223 Console.debug("Wait for save to complete: " + t + "ms");
230 ret = !BackupFiles.hasSavesInProgress();
234 "Save completed whilst waiting (" + c + "/" + t + "ms)");
237 if (c % 1000 < i) // just gone over another second
239 Console.debug("...waiting (" + c + "/" + t + "ms]");
242 } catch (InterruptedException e)
244 Console.debug("Wait for save interrupted");
246 Console.debug("Save has " + (ret ? "" : "not ") + "completed");