Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
QuitHandler | 52 | 201 | 65 | ||
QuitHandler.QResponse | 62 | 0 | 0 | ||
QuitHandler.Message | 67 | 0 | 0 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
7 | * Jalview is free software: you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation, either version 3 | |
10 | * of the License, or (at your option) any later version. | |
11 | * | |
12 | * Jalview is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty | |
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
15 | * PURPOSE. See the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Jalview. If not, see <http://www.gnu.org/licenses/>. | |
19 | * The Jalview Authors are detailed in the 'AUTHORS' file. | |
20 | */ | |
21 | package jalview.gui; | |
22 | ||
23 | import java.io.File; | |
24 | import java.util.List; | |
25 | import java.util.Locale; | |
26 | import java.util.concurrent.CompletableFuture; | |
27 | import java.util.concurrent.ExecutionException; | |
28 | import java.util.concurrent.ExecutorService; | |
29 | import java.util.concurrent.Executors; | |
30 | import java.util.concurrent.RejectedExecutionException; | |
31 | import java.util.concurrent.TimeUnit; | |
32 | import java.util.concurrent.TimeoutException; | |
33 | ||
34 | import javax.swing.JButton; | |
35 | import javax.swing.JFrame; | |
36 | import javax.swing.JOptionPane; | |
37 | import javax.swing.JTextPane; | |
38 | ||
39 | import com.formdev.flatlaf.extras.FlatDesktop; | |
40 | import com.formdev.flatlaf.extras.FlatDesktop.QuitResponse; | |
41 | ||
42 | import jalview.api.AlignmentViewPanel; | |
43 | import jalview.bin.Cache; | |
44 | import jalview.bin.Console; | |
45 | import jalview.datamodel.AlignmentI; | |
46 | import jalview.datamodel.SequenceI; | |
47 | import jalview.io.BackupFiles; | |
48 | import jalview.project.Jalview2XML; | |
49 | import jalview.util.MessageManager; | |
50 | import jalview.util.Platform; | |
51 | ||
52 | public class QuitHandler | |
53 | { | |
54 | private static final int MIN_WAIT_FOR_SAVE = 1000; | |
55 | ||
56 | private static final int MAX_WAIT_FOR_SAVE = 20000; | |
57 | ||
58 | private static boolean interactive = true; | |
59 | ||
60 | private static QuitResponse flatlafResponse = null; | |
61 | ||
62 | public static enum QResponse | |
63 | { | |
64 | NULL, QUIT, CANCEL_QUIT, FORCE_QUIT | |
65 | }; | |
66 | ||
67 | public static enum Message | |
68 | { | |
69 | UNSAVED_CHANGES, UNSAVED_ALIGNMENTS | |
70 | }; | |
71 | ||
72 | protected static Message message = Message.UNSAVED_CHANGES; | |
73 | ||
74 | 452 | public static void setMessage(Message m) |
75 | { | |
76 | 452 | message = m; |
77 | } | |
78 | ||
79 | private static ExecutorService executor = Executors.newFixedThreadPool(3); | |
80 | ||
81 | 0 | public static void setQuitHandler() |
82 | { | |
83 | 0 | FlatDesktop.setQuitHandler(response -> { |
84 | 0 | flatlafResponse = response; |
85 | 0 | Desktop.instance.desktopQuit(); |
86 | }); | |
87 | } | |
88 | ||
89 | 76 | public static void startForceQuit() |
90 | { | |
91 | 76 | setResponse(QResponse.FORCE_QUIT); |
92 | } | |
93 | ||
94 | private static QResponse gotQuitResponse = QResponse.NULL; | |
95 | ||
96 | 106 | protected static QResponse setResponse(QResponse qresponse) |
97 | { | |
98 | 106 | Console.trace("setResponse(" + qresponse.toString() + ")"); |
99 | 106 | gotQuitResponse = qresponse; |
100 | 106 | if ((qresponse == QResponse.CANCEL_QUIT || qresponse == QResponse.NULL) |
101 | && flatlafResponse != null) | |
102 | { | |
103 | 0 | Console.trace("Running flatLafResponse.cancelQuit()"); |
104 | 0 | flatlafResponse.cancelQuit(); |
105 | } | |
106 | 106 | return qresponse; |
107 | } | |
108 | ||
109 | 124 | public static QResponse gotQuitResponse() |
110 | { | |
111 | 124 | return gotQuitResponse; |
112 | } | |
113 | ||
114 | public static final Runnable defaultCancelQuit = () -> { | |
115 | 1 | Console.trace("QuitHandler: (default) Quit action CANCELLED by user"); |
116 | // reset | |
117 | 1 | setResponse(QResponse.CANCEL_QUIT); |
118 | }; | |
119 | ||
120 | public static final Runnable defaultOkQuit = () -> { | |
121 | 5 | Console.trace("QuitHandler: (default) Quit action CONFIRMED by user"); |
122 | 5 | setResponse(QResponse.QUIT); |
123 | }; | |
124 | ||
125 | public static final Runnable defaultForceQuit = () -> { | |
126 | 0 | Console.trace("QuitHandler: (default) Quit action FORCED by user"); |
127 | // note that shutdown hook will not be run | |
128 | 0 | Runtime.getRuntime().halt(0); |
129 | 0 | setResponse(QResponse.FORCE_QUIT); // this line never reached! |
130 | }; | |
131 | ||
132 | 6 | public static QResponse getQuitResponse(boolean ui) |
133 | { | |
134 | 6 | return getQuitResponse(ui, defaultOkQuit, defaultForceQuit, |
135 | defaultCancelQuit); | |
136 | } | |
137 | ||
138 | 7 | public static QResponse getQuitResponse(boolean ui, Runnable okQuit, |
139 | Runnable forceQuit, Runnable cancelQuit) | |
140 | { | |
141 | 7 | QResponse got = gotQuitResponse(); |
142 | 7 | Console.trace("Quit response is '" + got.toString() |
143 | + "' at start of getQuitResponse(...)"); | |
144 | 7 | if (got != QResponse.NULL && got != QResponse.CANCEL_QUIT) |
145 | { | |
146 | // quit has already been selected, continue with calling quit method | |
147 | 0 | Console.trace("Returning already set quit response of '" |
148 | + got.toString() + "' at start of getQuitResponse(...)"); | |
149 | 0 | return got; |
150 | } | |
151 | ||
152 | 7 | interactive = ui && !Platform.isHeadless(); |
153 | // confirm quit if needed and wanted | |
154 | 7 | boolean confirmQuit = true; |
155 | ||
156 | 7 | if (!interactive) |
157 | { | |
158 | 1 | Console.debug("Non interactive quit -- not confirming"); |
159 | 1 | confirmQuit = false; |
160 | } | |
161 | 6 | else if (Jalview2XML.allSavedUpToDate()) |
162 | { | |
163 | 5 | Console.debug("Nothing changed -- not confirming quit"); |
164 | 5 | confirmQuit = false; |
165 | } | |
166 | else | |
167 | { | |
168 | 1 | confirmQuit = jalview.bin.Cache |
169 | .getDefault(jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true); | |
170 | 1 | Console.trace("Jalview property '" |
171 | + jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT + "' is " | |
172 | 1 | + confirmQuit + " -- " + (confirmQuit ? "" : "not ") |
173 | + "confirming quit"); | |
174 | } | |
175 | ||
176 | 7 | got = confirmQuit ? QResponse.NULL : QResponse.QUIT; |
177 | 7 | setResponse(got); |
178 | ||
179 | 7 | Console.trace("confirmQuit is '" + confirmQuit |
180 | + "', setting quit response to " + got); | |
181 | ||
182 | 7 | if (confirmQuit) |
183 | { | |
184 | 1 | String messageString = MessageManager |
185 | 1 | .getString(message == Message.UNSAVED_ALIGNMENTS |
186 | ? "label.unsaved_alignments" | |
187 | : "label.unsaved_changes"); | |
188 | 1 | setQuitDialog(JvOptionPane.newOptionDialog() |
189 | .setResponseHandler(JOptionPane.YES_OPTION, defaultOkQuit) | |
190 | .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit)); | |
191 | 1 | JvOptionPane qd = getQuitDialog(); |
192 | 1 | qd.showDialogOnTopAsync( |
193 | new StringBuilder( | |
194 | MessageManager.getString("label.quit_jalview")) | |
195 | .append("\n").append(messageString).toString(), | |
196 | MessageManager.getString("action.quit"), | |
197 | JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, | |
198 | new Object[] | |
199 | { MessageManager.getString("action.quit"), | |
200 | MessageManager.getString("action.cancel") }, | |
201 | MessageManager.getString("action.quit"), true); | |
202 | ||
203 | 1 | Console.trace("Waiting for response handler to run action"); |
204 | 1 | qd.waitForHandlerToFinish(); |
205 | } | |
206 | ||
207 | 7 | got = gotQuitResponse(); |
208 | 7 | Console.trace("Quit response is '" + got.toString() |
209 | + "' after response handler"); | |
210 | ||
211 | // check for external viewer frames | |
212 | 7 | if (got != QResponse.CANCEL_QUIT) |
213 | { | |
214 | 6 | int count = Desktop.instance.structureViewersStillRunningCount(); |
215 | 6 | if (count > 0) |
216 | { | |
217 | 0 | String alwaysCloseExternalViewers = Cache |
218 | .getDefault("ALWAYS_CLOSE_EXTERNAL_VIEWERS", "ask"); | |
219 | 0 | String prompt = MessageManager |
220 | 0 | .formatMessage(count == 1 ? "label.confirm_quit_viewer" |
221 | : "label.confirm_quit_viewers"); | |
222 | 0 | String title = MessageManager.getString( |
223 | 0 | count == 1 ? "label.close_viewer" : "label.close_viewers"); |
224 | 0 | String cancelQuitText = MessageManager |
225 | .getString("action.cancel_quit"); | |
226 | 0 | String[] buttonsText = { MessageManager.getString("action.yes"), |
227 | MessageManager.getString("action.no"), cancelQuitText }; | |
228 | ||
229 | 0 | int confirmResponse = -1; |
230 | 0 | if (alwaysCloseExternalViewers == null || "ask".equals( |
231 | alwaysCloseExternalViewers.toLowerCase(Locale.ROOT))) | |
232 | { | |
233 | 0 | confirmResponse = JvOptionPane.showOptionDialog(Desktop.instance, |
234 | prompt, title, JvOptionPane.YES_NO_CANCEL_OPTION, | |
235 | JvOptionPane.WARNING_MESSAGE, null, buttonsText, | |
236 | cancelQuit); | |
237 | } | |
238 | else | |
239 | { | |
240 | 0 | confirmResponse = Cache |
241 | .getDefault("ALWAYS_CLOSE_EXTERNAL_VIEWERS", false) | |
242 | ? JvOptionPane.YES_OPTION | |
243 | : JvOptionPane.NO_OPTION; | |
244 | } | |
245 | ||
246 | 0 | if (confirmResponse == JvOptionPane.CANCEL_OPTION) |
247 | { | |
248 | // Cancel Quit | |
249 | 0 | QuitHandler.setResponse(QResponse.CANCEL_QUIT); |
250 | } | |
251 | else | |
252 | { | |
253 | // Close viewers/Leave viewers open | |
254 | 0 | StructureViewerBase |
255 | .setQuitClose(confirmResponse == JvOptionPane.YES_OPTION); | |
256 | } | |
257 | } | |
258 | ||
259 | } | |
260 | ||
261 | 7 | got = gotQuitResponse(); |
262 | ||
263 | 7 | Console.trace("Quit response is '" + got.toString() |
264 | + "' after external structure viewer check"); | |
265 | ||
266 | 7 | if (got == QResponse.CANCEL_QUIT) |
267 | { | |
268 | // reset | |
269 | 1 | Console.debug("Cancelling quit. Resetting response to NULL"); |
270 | 1 | setResponse(QResponse.NULL); |
271 | // but return cancel | |
272 | 1 | return QResponse.CANCEL_QUIT; |
273 | } | |
274 | 6 | else if (got == QResponse.QUIT) |
275 | { | |
276 | 6 | Console.debug("Quit response is '" + got.toString() |
277 | + "' before waiting for save"); | |
278 | 6 | if (Cache.getDefault("WAIT_FOR_SAVE", true) |
279 | && BackupFiles.hasSavesInProgress()) | |
280 | { | |
281 | 2 | waitQuit(interactive, okQuit, forceQuit, cancelQuit); |
282 | } | |
283 | 6 | Console.debug("Quit response is '" + got.toString() |
284 | + "' after waiting for save"); | |
285 | } | |
286 | ||
287 | 6 | Runnable next = null; |
288 | 6 | got = gotQuitResponse(); |
289 | 6 | Console.debug("Quit response is '" + got.toString() |
290 | + "' before setting next"); | |
291 | 6 | switch (gotQuitResponse()) |
292 | { | |
293 | 5 | case QUIT: |
294 | 5 | next = okQuit; |
295 | 5 | break; |
296 | 1 | case FORCE_QUIT: // not actually an option at this stage |
297 | 1 | next = forceQuit; |
298 | 1 | break; |
299 | 0 | default: |
300 | 0 | next = cancelQuit; |
301 | 0 | break; |
302 | } | |
303 | 6 | Console.debug( |
304 | "Quit response is '" + got.toString() + "' after setting next"); | |
305 | 6 | Console.debug("Next is '" + next + "'"); |
306 | 6 | try |
307 | { | |
308 | 6 | executor.submit(next).get(); |
309 | 6 | Console.debug(next + " is submitted"); |
310 | 6 | got = gotQuitResponse(); |
311 | 6 | Console.debug("Quit response is '" + got.toString() |
312 | + "' after submitting next"); | |
313 | } catch (RejectedExecutionException e) | |
314 | { | |
315 | // QuitHander.abortQuit() probably called | |
316 | // CANCEL_QUIT test will reset QuitHandler | |
317 | 0 | Console.info("Quit aborted!"); |
318 | 0 | got = QResponse.NULL; |
319 | 0 | setResponse(QResponse.NULL); |
320 | } catch (InterruptedException | ExecutionException e) | |
321 | { | |
322 | 0 | jalview.bin.Console |
323 | .debug("Exception during quit handling (final choice)", e); | |
324 | } | |
325 | 6 | Console.debug("Setting response to '" + got.toString() |
326 | + "' after submitting next"); | |
327 | 6 | setResponse(got); |
328 | ||
329 | 6 | Console.debug("Checking if quit was cancelled"); |
330 | 6 | if (quitCancelled()) |
331 | { | |
332 | // reset if cancelled | |
333 | 0 | Console.debug("Quit cancelled"); |
334 | 0 | setResponse(QResponse.NULL); |
335 | 0 | Console.debug("Set response to " + QResponse.NULL.toString() |
336 | + ". Returning " + QResponse.CANCEL_QUIT); | |
337 | 0 | return QResponse.CANCEL_QUIT; |
338 | } | |
339 | 6 | got = gotQuitResponse(); |
340 | 6 | Console.debug("Returning " + got.toString()); |
341 | 6 | return got; |
342 | } | |
343 | ||
344 | 2 | private static QResponse waitQuit(boolean interactive, Runnable okQuit, |
345 | Runnable forceQuit, Runnable cancelQuit) | |
346 | { | |
347 | // check for saves in progress | |
348 | 2 | if (!BackupFiles.hasSavesInProgress()) |
349 | 0 | return QResponse.QUIT; |
350 | ||
351 | 2 | int size = 0; |
352 | 2 | AlignFrame[] afArray = Desktop.getDesktopAlignFrames(); |
353 | 2 | if (!(afArray == null || afArray.length == 0)) |
354 | { | |
355 | 4 | for (int i = 0; i < afArray.length; i++) |
356 | { | |
357 | 2 | AlignFrame af = afArray[i]; |
358 | 2 | List<? extends AlignmentViewPanel> avpList = af.getAlignPanels(); |
359 | 2 | for (AlignmentViewPanel avp : avpList) |
360 | { | |
361 | 2 | AlignmentI a = avp.getAlignment(); |
362 | 2 | List<SequenceI> sList = a.getSequences(); |
363 | 2 | for (SequenceI s : sList) |
364 | { | |
365 | 30 | size += s.getLength(); |
366 | } | |
367 | } | |
368 | } | |
369 | } | |
370 | 2 | int waitTime = Math.min(MAX_WAIT_FOR_SAVE, |
371 | Math.max(MIN_WAIT_FOR_SAVE, size / 2)); | |
372 | 2 | Console.debug("Set waitForSave to " + waitTime); |
373 | ||
374 | 2 | int iteration = 0; |
375 | 2 | boolean doIterations = true; // note iterations not used in the gui now, |
376 | // only one pass without the "Wait" button | |
377 | 6 | while (doIterations && BackupFiles.hasSavesInProgress() |
378 | 4 | && iteration++ < (interactive ? 100 : 5)) |
379 | { | |
380 | // future that returns a Boolean when all files are saved | |
381 | 4 | CompletableFuture<Boolean> filesAllSaved = new CompletableFuture<>(); |
382 | ||
383 | // callback as each file finishes saving | |
384 | 4 | for (CompletableFuture<Boolean> cf : BackupFiles |
385 | .savesInProgressCompletableFutures(false)) | |
386 | { | |
387 | // if this is the last one then complete filesAllSaved | |
388 | 4 | cf.whenComplete((ret, e) -> { |
389 | 4 | if (!BackupFiles.hasSavesInProgress()) |
390 | { | |
391 | 2 | filesAllSaved.complete(true); |
392 | } | |
393 | }); | |
394 | } | |
395 | 4 | try |
396 | { | |
397 | 4 | filesAllSaved.get(waitTime, TimeUnit.MILLISECONDS); |
398 | } catch (InterruptedException | ExecutionException e1) | |
399 | { | |
400 | 0 | Console.debug( |
401 | "Exception whilst waiting for files to save before quit", | |
402 | e1); | |
403 | } catch (TimeoutException e2) | |
404 | { | |
405 | // this Exception to be expected | |
406 | } | |
407 | ||
408 | 4 | if (interactive && BackupFiles.hasSavesInProgress()) |
409 | { | |
410 | 3 | boolean showForceQuit = iteration > 0; // iteration > 1 to not show |
411 | // force quit the first time | |
412 | 3 | JFrame parent = new JFrame(); |
413 | 3 | JButton[] buttons = { new JButton(), new JButton() }; |
414 | 3 | JvOptionPane waitDialog = JvOptionPane.newOptionDialog(); |
415 | 3 | JTextPane messagePane = new JTextPane(); |
416 | 3 | messagePane.setBackground(waitDialog.getBackground()); |
417 | 3 | messagePane.setBorder(null); |
418 | 3 | messagePane.setText(waitingForSaveMessage()); |
419 | // callback as each file finishes saving | |
420 | 3 | for (CompletableFuture<Boolean> cf : BackupFiles |
421 | .savesInProgressCompletableFutures(false)) | |
422 | { | |
423 | 3 | cf.whenComplete((ret, e) -> { |
424 | 3 | if (BackupFiles.hasSavesInProgress()) |
425 | { | |
426 | // update the list of saving files as they save too | |
427 | 1 | messagePane.setText(waitingForSaveMessage()); |
428 | } | |
429 | else | |
430 | { | |
431 | 2 | if (!(quitCancelled())) |
432 | { | |
433 | 3 | for (int i = 0; i < buttons.length; i++) |
434 | { | |
435 | 2 | Console.debug("DISABLING BUTTON " + buttons[i].getText()); |
436 | 2 | buttons[i].setEnabled(false); |
437 | 2 | buttons[i].setVisible(false); |
438 | } | |
439 | // if this is the last one then close the dialog | |
440 | 1 | messagePane.setText(new StringBuilder() |
441 | .append(MessageManager.getString("label.all_saved")) | |
442 | .append("\n") | |
443 | .append(MessageManager | |
444 | .getString("label.quitting_bye")) | |
445 | .toString()); | |
446 | 1 | messagePane.setEditable(false); |
447 | 1 | try |
448 | { | |
449 | 1 | Thread.sleep(1500); |
450 | } catch (InterruptedException e1) | |
451 | { | |
452 | } | |
453 | 1 | parent.dispose(); |
454 | } | |
455 | } | |
456 | }); | |
457 | } | |
458 | ||
459 | 3 | String[] options; |
460 | 3 | int dialogType = -1; |
461 | 3 | if (showForceQuit) |
462 | { | |
463 | 3 | options = new String[2]; |
464 | 3 | options[0] = MessageManager.getString("action.force_quit"); |
465 | 3 | options[1] = MessageManager.getString("action.cancel_quit"); |
466 | 3 | dialogType = JOptionPane.YES_NO_OPTION; |
467 | 3 | waitDialog.setResponseHandler(JOptionPane.YES_OPTION, forceQuit) |
468 | .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit); | |
469 | } | |
470 | else | |
471 | { | |
472 | 0 | options = new String[1]; |
473 | 0 | options[0] = MessageManager.getString("action.cancel_quit"); |
474 | 0 | dialogType = JOptionPane.YES_OPTION; |
475 | 0 | waitDialog.setResponseHandler(JOptionPane.YES_OPTION, cancelQuit); |
476 | } | |
477 | 3 | waitDialog.showDialogOnTopAsync(parent, messagePane, |
478 | MessageManager.getString("label.wait_for_save"), dialogType, | |
479 | JOptionPane.WARNING_MESSAGE, null, options, | |
480 | MessageManager.getString("action.cancel_quit"), true, | |
481 | buttons); | |
482 | ||
483 | 3 | parent.dispose(); |
484 | 3 | final QResponse thisWaitResponse = gotQuitResponse(); |
485 | 3 | switch (thisWaitResponse) |
486 | { | |
487 | 2 | case QUIT: // wait -- do another iteration |
488 | 2 | break; |
489 | 1 | case FORCE_QUIT: |
490 | 1 | doIterations = false; |
491 | 1 | break; |
492 | 0 | case CANCEL_QUIT: |
493 | 0 | doIterations = false; |
494 | 0 | break; |
495 | 0 | case NULL: // already cancelled |
496 | 0 | doIterations = false; |
497 | 0 | break; |
498 | 0 | default: |
499 | } | |
500 | } // end if interactive | |
501 | ||
502 | } // end while wait iteration loop | |
503 | 2 | return gotQuitResponse(); |
504 | }; | |
505 | ||
506 | 4 | private static String waitingForSaveMessage() |
507 | { | |
508 | 4 | StringBuilder messageSB = new StringBuilder(); |
509 | ||
510 | 4 | messageSB.append(MessageManager.getString("label.save_in_progress")); |
511 | 4 | List<File> files = BackupFiles.savesInProgressFiles(false); |
512 | 4 | boolean any = files.size() > 0; |
513 | 4 | if (any) |
514 | { | |
515 | 4 | for (File file : files) |
516 | { | |
517 | 4 | messageSB.append("\n\u2022 ").append(file.getName()); |
518 | } | |
519 | } | |
520 | else | |
521 | { | |
522 | 0 | messageSB.append(MessageManager.getString("label.unknown")); |
523 | } | |
524 | 4 | messageSB.append("\n\n") |
525 | .append(MessageManager.getString("label.quit_after_saving")); | |
526 | 4 | return messageSB.toString(); |
527 | } | |
528 | ||
529 | 0 | public static void abortQuit() |
530 | { | |
531 | 0 | setResponse(QResponse.NULL); |
532 | // executor.shutdownNow(); | |
533 | } | |
534 | ||
535 | private static JvOptionPane quitDialog = null; | |
536 | ||
537 | 1 | private static void setQuitDialog(JvOptionPane qd) |
538 | { | |
539 | 1 | quitDialog = qd; |
540 | } | |
541 | ||
542 | 1 | private static JvOptionPane getQuitDialog() |
543 | { | |
544 | 1 | return quitDialog; |
545 | } | |
546 | ||
547 | 8 | public static boolean quitCancelled() |
548 | { | |
549 | 8 | return QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT |
550 | || QuitHandler.gotQuitResponse() == QResponse.NULL; | |
551 | } | |
552 | ||
553 | 0 | public static boolean quitting() |
554 | { | |
555 | 0 | return QuitHandler.gotQuitResponse() == QResponse.QUIT |
556 | || QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT; | |
557 | } | |
558 | } |