cocoa sheet on document-based app - cocoa

I got a dialog instead of sheet.It worked when the app was not document-based.
Now it doesn't work.
- (IBAction) showSheet:(NSWindow*)window
{
// User has asked to see the dialog. Display it.
NSLog(#"%#", self.contragentsSheet);
if (!_contragentsSheet)
[NSBundle loadNibNamed: #"contragentsSheet" owner: self];
[NSApp beginSheet:self.contragentsSheet
modalForWindow: [[NSApp delegate]window]
//modalForWindow: window
modalDelegate: self
didEndSelector: NULL
contextInfo: NULL];
//[contragentSearch becomeFirstResponder];
//NSLog ( #"Sheet is launched");
NSLog(#"%#", [[NSApp delegate]window]);
}

Don't use [[NSApp delegate] window] you need to explicitly tell the method which window you want to display the sheet on. Document based Apps can have many windows and a sheet is attached to one.

Related

cocoa sheet is not modal

I can't figure out why the sheet is not modal and the focus is still on the main window.
- (IBAction) showSheet:(NSWindow*)window
{
// User has asked to see the dialog. Display it.
if (!_clientsDialog)
[NSBundle loadNibNamed: #"clientsDialog" owner: self];
[NSApp beginSheet:self.clientsDialog
modalForWindow: [[NSApp delegate]window]
modalDelegate: self
didEndSelector: NULL
contextInfo: NULL];
}
The following method works for me:
Header File:
- (IBAction)showSheet:(id)sender;
Method file:
- (void)showSheet:(id)sender {
if (! _clientsDialog)
[NSBundle loadNibNamed: #"clientsDialog" owner: self];
[NSApp beginSheet: _clientsDialog
modalForWindow: [[NSApp delegate] window]
modalDelegate: self
didEndSelector: NULL
contextInfo: NULL];
}
IMPORTANT: You need to have a Title Bar on your window. Otherwise Controls won't work.

Modal session requires modal window

I'm trying to open a window like a sheet so that it appears down below the toolbar. I've used the O'Reilly tutorial to do this. However, I can get past this error: Modal session requires modal window.
The window loads as a window if I have "Visible At Launch" checked.
Whether it is checked or not I get the "Modal session requires modal window" error.
I have a Window.xib, ProgressModal.xib.
In the Window implementation file I use:
-(IBAction)loadProgress:(id)sender{
[self progressStatus:progressWindow];
}
- (void)progressStatus:(NSWindow *)window {
[NSApp beginSheet: window
modalForWindow: mainWindow
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
[NSApp runModalForWindow: window];
[NSApp endSheet: window];
[window orderOut: self];
}
- (IBAction)cancelProgressScrollView:(id)sender {
[NSApp stopModal];
}
I may have the ProgressModal.xib setup wrong. I have an NSObject in it that has "Window" as its class. All the connections are made through that.
But again, it loads the window just won't load it as a modal.
Any ideas?
Put the following in the first line of your progressStatus method:
NSLog(#"%#", window);
If you see the log output is null, that's the reason why.
Steps to create a modal sheet using XIB:
Drag a panel to your MainMenu.xib
Add #property (assign) IBOutlet NSPanel *sheetPanel; in your AppDelegate.h file
#synthesize sheetPanel = _sheetPanel; in the AppDelegate.m file
Link a New Referencing Outlet of the panel in the MainMenu.xib created in the step 1 to the sheetPanel property created in step 2.
Using following code to show the modal sheet:
[NSApp beginSheet:_sheetPanel
modalForWindow:_mainWindow
modalDelegate:self
didEndSelector:#selector(didEndSheet:returnCode:contextInfo:)
contextInfo:nil];
As I stated above, I dragged an object over in the progressModal window and made my connections through that. What I should have done was made the File's owner my Window class. Changing that fixed the problem.
I got this from http://www.youtube.com/watch?v=QBkO6TD-fWA
Edit: I assumed you wanted a modal window. If you want a sheet, don't use runModalForWindow: at all.
Try this:
[NSApp beginSheet: window
modalForWindow: mainWindow
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
It's a good idea to define a callback just in case you need it though; e.g.
[NSApp beginSheet: window
modalForWindow: mainWindow
modalDelegate: self
didEndSelector: #selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo: nil];

Cocoa: Displaying an error after NSApp beginSheet results the main window hiding

I have broken this down into a very small project. Using the following code in the application delegate:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
TestingWindowController * testingWindowController = [[TestingWindowController alloc] initWithWindowNibName: #"TestingWindowController"];
// Begin our sheet
[NSApp beginSheet: testingWindowController.window
modalForWindow: self.window
modalDelegate: self
didEndSelector: #selector(windowDidEnd:returnCode:contextInfo:)
contextInfo: NULL];
}
- (void)windowDidEnd:(id)alert returnCode:(NSInteger)returnCode contextInfo:(id) contextInfo
{
// If the user did not accept, then we really don't care what else they did!
if (returnCode != NSOKButton) return;
// We have had an error. Display it.
[[NSApplication sharedApplication] presentError: nil
modalForWindow: self.window
delegate: nil
didPresentSelector: nil
contextInfo: NULL];
}
And the following action tied to button on the windows nib. (Note that the nib's window is also set to not be visible on launch).
- (IBAction) onClose: (id) sender
{
[[NSApplication sharedApplication] endSheet: self.window
returnCode: NSOKButton];
[self.window orderOut: nil];
} // End of onClose
What ends up happening is, once I the onClose runs, all of the windows disappear and I am left with nothing but the error dialog (the main window has disappeared).
Is there something wrong with my code? Why does my main window go away?
NOTE: I know that I am not passing an error to the presentError method. I purposely left this null as I only had a short time to write the sample code. Passing an actual error results in the same behaviour.
Sample project is available here.
Looks like you are still using the old api, try the new one
(deselect Always visible at launch for the UserLoginWindowController window)
- (IBAction)userButtonPressed:(id)sender {
UserLoginWindowController * wc = [UserLoginWindowController new];
// we keep a reference, so the WC doesn't deallocate
self.modalWindowController = wc;
[[self window] beginSheet:[wc window] completionHandler:^(NSModalResponse returnCode) {
self.modalWindowController = nil;
}];
}
in the UserLoginWindowController
- (IBAction)cancelButtonPressed:(id)sender {
[[[self window] sheetParent] endSheet:[self window] returnCode:NSModalResponseCancel];
}
You are using 2 methods to open your window, beginSheet:....., and runModalForWindow:. You only need one of those. If you want a sheet attached to your window, use the first method, if you want a stand alone window, use the second. Likewise, in your onClose method, you should use endSheet:returnCode: if you're closing a sheet (the argument for that method should be testingWindowController.window not self.window) , and stopModalWithCode: if you're closing a modal window, you shouldn't have both.

Access main window from a NSDocument class

I have a NSDocument class, where I'd need to access the main menu window, the one that gets opened when the app start. When I operate in that window from the app all seems to work, but when trying to do the same operations from readFromFileWrapper:ofType:error: the window I access seems to be nil. Why this happens?
EDIT: Some code which deals with this:
- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError
{
if([[NSFileManager alloc] fileExistsAtPath:[NSString stringWithFormat:#"%#/Project.plist",[[self fileURL] path]]]) {
NSLog(#"%#", [[self fileURL] path]);
NSDictionary *project = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:#"%#/Project.plist",[[self fileURL] path]]];
if([[project objectForKey:#"type"] isEqualToString:#"vote"]) {
[self openProject:[[self fileURL] path] type:#"vote"];
return YES;
} else if([[project objectForKey:#"type"] isEqualToString:#"quiz"]) {
[self openProject:[[self fileURL] path] type:#"quiz"];
return YES;
} else {
return NO;
}
} else {
return NO;
}
}
That is my readFromFileWrapper:ofType:error: method. Here is my openProject:type: method:
-(void)openProject:(NSString *)filepath type:(NSString *)type
{
NSLog(#"Opening project # %#",filepath);
NSLog(#"%#", [MainWindow description]);
[projectDesignerView setFrame:[[[[MainWindow contentView] subviews] objectAtIndex:0] frame]];
[projectDesignerToolbar setFrame:[MainWindow frame] display:FALSE];
[[MainWindow contentView] replaceSubview:[[[MainWindow contentView] subviews]objectAtIndex:0] with:projectDesignerView];
[[projectDesignerToolbar toolbar] setShowsBaselineSeparator:YES];
[MainWindow setToolbar:[projectDesignerToolbar toolbar]];
[MainWindow setRepresentedFilename:filepath];
[MainWindow setTitle:[NSString stringWithFormat:#"%# - %#", [[filepath lastPathComponent] stringByDeletingPathExtension], [projectDesignerToolbar title]]];
NSString *path = [[NSBundle mainBundle] pathForResource:#"projectDesigner" ofType:#"html"];
NSURL *url = [NSURL fileURLWithPath:path];
[[projectDesignerWebview mainFrame] loadRequest:[NSURLRequest requestWithURL:url]];
}
NSLog(#"%#", [MainWindow description]); returns nil, when MainWindow should be the Main App Window. I think the problem is that double-clicking on a file reallocs all, and hence is failing.
It's not entirely clear what you're asking. You mention that MainWindow is an outlet in MainMenu.xib but you don't specify what class is defining the outlet.
If this window is designed to have a single main "project" window then you should assign the outlet property in your application delegate.
You can then access this from other classes using something like [(YourAppDelegate*)[NSApp delegate] mainWindow];.
If, however, you are trying to obtain a reference to the window of the current document then it's a little bit more complicated.
The reason that NSDocument does not have a window outlet by default is that it is designed to work with instances of NSWindowController that themselves manage the various windows related to the document. This is so a document can have multiple windows showing different views of the same data, additional palettes related to the document and so on. Each instance of NSWindowController would have its own window nib file and window outlet.
By default, NSDocument creates a single instance of NSWindowController for you if you do not specifically create and assign NSWindowController instances to the document. This is automatic, you don't need to even know the window controller exists.
That means that if you aren't managing your document windows with NSWindowController instances yourself, you can get the window attached to the NSWindowController that is automatically-created by NSDocument like so:
/* Only implement this in an NSDocument instance where the
automatic window controller is being used.
If the document has multiple window controllers, you must
keep track of the main window controller yourself
and return its window
*/
- (NSWindow*)documentWindow
{
if([[self windowControllers] count] == 1)
{
return [[[self windowControllers] firstObject] window];
}
return nil;
}
The normal way to handle this is to add an IBOutlet to your NSDocument subclass, then hook it up to the document window in the .xib file.
In your .h:
#interface MyDocument : NSDocument
#property (nonatomic, assign) IBOutlet NSWindow *docWindow;
#end
In your .m:
#implementation MyDocument : NSDocument
#synthesize docWindow;
#end
Then, the most important part, open up MyDocument.xib (or whatever it's called), and drag a connection from File's Owner (assuming that's your NSDocument subclass, which it is by default) to the main document window, and hook it up to the docWindow outlet.

Cocoa: NSApp beginSheet sets the application delegate?

I am trying to display a custom sheet in my application, but I think I am doing something wrong. While everything seems to be working just fine, I have a rather odd side-effect. (which took hours to figure out). It turns out that everytime I display a sheet in my application, the Application delegate gets set to the instance of the sheet, thus my Controller gets unset as the delegate causing all sorts of problems.
I've created a NIB file which I called FailureSheet.xib. I laid out my interface in IB, and then created a subclass of 'NSWindowController' called 'FailureSheet.m' which I set to the File's Owner. Here is my FailureSheet class:
#import "FailureSheet.h"
#implementation FailureSheet // extends NSWindowController
- (id)init
{
if (self = [super initWithWindowNibName:#"FailureSheet" owner:self])
{
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (IBAction)closeSheetTryAgain:(id)sender
{
[NSApp endSheet:[self window] returnCode:1];
[[self window] orderOut:nil];
}
- (IBAction)closeSheetCancel:(id)sender
{
[NSApp endSheet:[self window] returnCode:0];
[[self window] orderOut:nil];
}
- (IBAction)closeSheetCancelAll:(id)sender
{
[NSApp endSheet:[self window] returnCode:-1];
[[self window] orderOut:nil];
}
#end
Nothing complex going on here. Now this is how I display the FailureSheet in my 'Controller' class:
sheet = [[FailureSheet alloc] init];
[NSApp beginSheet:[sheet window]
modalForWindow:window
modalDelegate:self
didEndSelector:#selector(failureSheetDidEnd:etc:etc:)
contextInfo:nil];
Now if I log what the [NSApp delegate] is before displaying my sheet, it is <Controller-0x012345> which is correct. Then, after running this code and my sheet is up, if I log it again it is <FailureSheet-0xABCDEF>.
Not sure what I'm doing wrong here - Any ideas?
This is one of those "I'm-an-idiot" answers.
Turns out I at some point I accidentally made a connection in my sheet's NIB file between the Application and the File's Owner (FailureSheet) setting it as the delegate. So, everytime it got loaded it overwrote the existing delegate connection I had in my MainMenu NIB file.

Resources