0

I want to use windowShouldClose: in my NSWindowController subclass to pop up a sheet asking if the user wants to save changes before closing with Save, Cancel, and Don't Save buttons.

The issue I'm running in to is that beginSheetModalForWindow:... uses a delegate instead of a return value.

I can return NO in windowShouldClose:, but then when I send [self close] to the controller in the panel's delegate nothing happens.

Can somebody explain to me how to do this or point me in the direction of some sample code?

Monolo
  • 18,205
  • 17
  • 69
  • 103
Redwood
  • 66,744
  • 41
  • 126
  • 187

2 Answers2

2

The basic solution is to put a boolean flag on the window that states whether or not the window has warned about unsaved changes. Before calling [self close], set this flag to true.

Finally, in the windowShouldClose method, return the value of the flag.

Ecton
  • 10,702
  • 2
  • 35
  • 44
2

This is the code I ended up using.

windowShouldCloseAfterSaveSheet_ is an instance variable in my controller class.

Remember to set the window outlet for the controller in IB.

- (BOOL)windowShouldClose:(id)window {    
  if (windowShouldCloseAfterSaveSheet_) {
    // User has already gone through save sheet and choosen to close the window
    windowShouldCloseAfterSaveSheet_ = NO; // Reset value just in case
    return YES;
  }

  if ([properties_ settingsChanged]) {
    NSAlert *saveAlert = [[NSAlert alloc] init];
    [saveAlert addButtonWithTitle:@"OK"];
    [saveAlert addButtonWithTitle:@"Cancel"];
    [saveAlert addButtonWithTitle:@"Don't Save"];
    [saveAlert setMessageText:@"Save changes to preferences?"];
    [saveAlert setInformativeText:@"If you don't save the changes, they will be lost"];
    [saveAlert beginSheetModalForWindow:window
                                modalDelegate:self
                               didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) 
                                  contextInfo:nil];

    return NO;
  }

  // Settings haven't been changed.
  return YES;
}

// This is the method that gets called when a user selected a choice from the
// do you want to save preferences sheet.
- (void)alertDidEnd:(NSAlert *)alert 
         returnCode:(int)returnCode
        contextInfo:(void *)contextInfo {
  switch (returnCode) {
    case NSAlertFirstButtonReturn:
      // Save button
      if (![properties_ saveToFile]) {
        NSAlert *saveFailedAlert = [NSAlert alertWithMessageText:@"Save Failed"
                                                   defaultButton:@"OK"
                                                 alternateButton:nil
                                                     otherButton:nil
                                       informativeTextWithFormat:@"Failed to save preferences to disk"];
        [saveFailedAlert runModal];
      }
      [[alert window] orderOut:self];
      windowShouldCloseAfterSaveSheet_ = YES;
      [[self window] performClose:self];
      break;
    case NSAlertSecondButtonReturn:
      // Cancel button
      // Do nothing
      break;
    case NSAlertThirdButtonReturn:
      // Don't Save button
      [[alert window] orderOut:self];
      windowShouldCloseAfterSaveSheet_ = YES;
      [[self window] performClose:self];
      break;
    default:
      NSAssert1(NO, @"Unknown button return: %i", returnCode);
      break;
  }
}
Redwood
  • 66,744
  • 41
  • 126
  • 187