Hi Scott, First off, you can only do this in DesktopApplicationContext, since BrowserApplicationContext can't reliably prevent the applet from getting destroyed. If you are in DesktopAplpicationContext, then the very short answer is that you return true from Application.shutdown() to prevent the shutdown until the user has answered your question. Then, when they answer your dialog (or sheet), you call DesktopApplicationContext.exit(), and allow the shutdown at that time.
The long answer is that it's kinda tricky to get right. To aid you on your way, I'll blindly paste snippets of the source of my Pivot app that does exactly this - you should be able to gleam what you need from it. I've attached two snippet source files. Let me know if they don't come through. -T On Thu, Oct 22, 2009 at 5:58 PM, Scott Lanham <li...@sael.com.au> wrote: > Hi All, > > I am at the point in my application where during Application.shutdown I > would > like a dialog to popup if they haven't saved their changes. The dialog > would > ask if they want to Save, Not Save, Cancel with the last cancelling the > shutdown. I am uncertain of how to approach this and was hoping someone > could > give me some guidance :-) > > Thanks, > > Scott. >
import org.apache.pivot.collections.ArrayList; import org.apache.pivot.collections.List; import org.apache.pivot.collections.Map; import org.apache.pivot.collections.immutable.ImmutableList; import org.apache.pivot.serialization.JSONSerializer; import org.apache.pivot.util.ListenerList; import org.apache.pivot.util.Resources; import org.apache.pivot.util.Vote; import org.apache.pivot.util.concurrent.Task; import org.apache.pivot.util.concurrent.TaskGroup; import org.apache.pivot.util.concurrent.TaskListener; import org.apache.pivot.web.BasicAuthentication; import org.apache.pivot.web.GetQuery; import org.apache.pivot.web.Query; import org.apache.pivot.wtk.Action; import org.apache.pivot.wtk.Component; import org.apache.pivot.wtk.DesktopApplicationContext; import org.apache.pivot.wtk.Direction; import org.apache.pivot.wtk.Display; import org.apache.pivot.wtk.Keyboard; import org.apache.pivot.wtk.MessageType; import org.apache.pivot.wtk.Prompt; import org.apache.pivot.wtk.Sheet; import org.apache.pivot.wtk.SheetCloseListener; import org.apache.pivot.wtk.SheetStateListener; import org.apache.pivot.wtk.TaskAdapter; import org.apache.pivot.wtk.Window; import org.apache.pivot.wtkx.WTKXSerializer; public class Foo implements Application { // Application state private boolean dirty = false; private boolean halting = false; // Main app window private Window window; ... @Override public boolean shutdown(boolean optional) throws Exception { boolean consumed = false; if (optional && dirty) { // We'll give the user the option of saving before shutting down. consumed = true; // Only perform this work once if (!halting) { halting = true; int ownedWindowCount = window.getOwnedWindowCount(); if (ownedWindowCount > 0) { // Delay until all our owned sheets are closed for (int i = 0; i < ownedWindowCount; i++) { Window ownedWindow = window.getOwnedWindow(i); if (ownedWindow instanceof Sheet) { Sheet ownedSheet = (Sheet)ownedWindow; ownedSheet.getSheetStateListeners().add(new SheetStateListener.Adapter() { @Override public void sheetClosed(Sheet sheet) { if (window.getOwnedWindowCount() == 0) { // We're clear to show our confirmation confirmShutdown(); } } }); ownedSheet.close(false); } } } else { // We're clear to show our confirmation immediately confirmShutdown(); } } } return consumed; } /** * Gives the user a "save/discard/cancel" prompt, allowing them to save * their work before shutting the application down. */ private void confirmShutdown() { SaveDiscardCancelTask saveDiscardCancelTask = new SaveDiscardCancelTask(); saveDiscardCancelTask.execute(new TaskAdapter<Choice>(new TaskListener<Choice>() { @Override public void taskExecuted(Task<Choice> task) { switch (task.getResult()) { case SAVE: // Inform the user that the invoice was saved List<String> options = new ArrayList<String>(resources.getString("options.ok")); String message = resources.getString("invoiceSaved"); Prompt prompt = new Prompt(MessageType.WARNING, message, options, null); prompt.setSelectedOption(0); // Shutdown the application when the user has acknowledged our prompt prompt.open(window, new SheetCloseListener() { @Override public void sheetClosed(Sheet sheet) { DesktopApplicationContext.exit(); } }); break; case DISCARD: // Clear the dirty bit to allow the shutdown to go through dirty = false; // Shutdown immediately DesktopApplicationContext.exit(); break; case CANCEL: halting = false; break; } } @Override public void executeFailed(Task<Choice> task) { task.getFault().printStackTrace(); } })); } ... }
import org.apache.pivot.collections.List; import org.apache.pivot.serialization.JSONSerializer; import org.apache.pivot.util.concurrent.Task; import org.apache.pivot.util.concurrent.TaskExecutionException; import org.apache.pivot.util.concurrent.TaskListener; import org.apache.pivot.wtk.Action; import org.apache.pivot.wtk.ApplicationContext; import org.apache.pivot.wtk.Label; import org.apache.pivot.wtk.MessageType; import org.apache.pivot.wtk.Prompt; import org.apache.pivot.wtk.Sheet; import org.apache.pivot.wtk.SheetCloseListener; import org.apache.pivot.wtk.Window; /** * Task that alerts the user that there are unsaved changes and * gives them the choice of saving, discarding their changes, or * cancelling what they were about to do. This task's result is the user's * choice. * <p> * If the user chooses to save, this task will automatically save their changes * for them and will not complete until the save is complete. If the save * faults, this task will propagate the fault. * <p> * If the user chooses to discard or cancel, this task takes no extra action * other than returning the user's choice. */ public class SaveDiscardCancelTask extends Task<SaveDiscardCancelTask.Choice> { /** * The user's choice. */ public enum Choice { SAVE, DISCARD, CANCEL; } private Choice choice; private Exception fault; @Override public synchronized Choice execute() throws TaskExecutionException { // Reset our variables choice = null; fault = null; ApplicationContext.queueCallback(new Runnable() { public void run() { try { String message = "Save Changes?"; List<?> options = JSONSerializer.parseList("['Save', 'Discard', 'Cancel']"); Label body = new Label("You have unsaved changes. " + "Do you want to save your changes?"); body.getStyles().put("wrapText", true); final Prompt prompt = new Prompt(MessageType.WARNING, message, options, body); prompt.setSelectedOption(0); Window owner = Foo.getWindow(); prompt.open(owner, new SheetCloseListener() { @Override public void sheetClosed(Sheet sheet) { boolean notify = true; if (prompt.getResult()) { int selectedOption = prompt.getSelectedOption(); if (selectedOption == 0) { // Save notify = false; SaveAction saveAction = (SaveAction) Action.getNamedActions().get("save"); saveAction.perform(new TaskListener<Void>() { @Override public void taskExecuted(Task<Void> task) { choice = Choice.SAVE; synchronized(SaveDiscardCancelTask.this) { SaveDiscardCancelTask.this.notify(); } } @Override public void executeFailed(Task<Void> task) { fault = task.getFault(); synchronized(SaveDiscardCancelTask.this) { SaveDiscardCancelTask.this.notify(); } } }); } else if (selectedOption == 1) { // Discard choice = Choice.DISCARD; } else { // Explicit cancel choice = Choice.CANCEL; } } else { // Implicit cancel choice = Choice.CANCEL; } if (notify) { synchronized(SaveDiscardCancelTask.this) { SaveDiscardCancelTask.this.notify(); } } } }); } catch (Exception ex) { fault = ex; synchronized(SaveDiscardCancelTask.this) { SaveDiscardCancelTask.this.notify(); } } } }); try { wait(); } catch (InterruptedException ex) { throw new TaskExecutionException(ex); } if (fault != null) { throw new TaskExecutionException(fault); } return choice; } }