Reputation: 8988
I am using a standard AppKit NSPersistentDocument document base application and would like a document's window to remember its location and open in the same position it was last closed in.
Note that setting the autosavename in IB on the Window will result in all documents opening in the same position. I want a document to remember its position based on the documents filename.
I have subclassed NSPersistentDocument and currently set the autosave name in the windowControllerDidLoadNib:
function. This almost works fine, except that if I open and close the same document repeatedly without closing the App then each time its window's height is increased a small amount (26 pixels), almost like its doing the cascade thing. However if I close the App completely and reopen it then the document remembers its previous position exactly. Am I doing something wrong or is this a bug. Is there some cleanup I should be doing perhaps to ensure that the window is not being resized each time its re-opened.
// NSPersistentDocument subclass
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
LOG(@"windowControllerDidLoadNib called...");
[super windowControllerDidLoadNib:aController];
if ([self autoSaveName] != nil) {
[aController setWindowFrameAutosaveName:[self autoSaveName]];
}
[aController setShouldCascadeWindows:NO];
}
- (NSString*)autoSaveName
{
return [[self fileURL] lastPathComponent];
}
If I add the following code to add 22 pixels to its height
- (NSRect)windowPositionPreference {
LOG(@"printUserDefaults called");
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *autosaveNameKey = [NSString stringWithFormat:@"NSWindow Frame %@", [self autoSaveName]];
NSString *frameString = [defaults objectForKey:autosaveNameKey];
NSArray *array = [frameString componentsSeparatedByString:@" "];
CGFloat x = [[array objectAtIndex:0] floatValue];
CGFloat y = [[array objectAtIndex:1] floatValue];
CGFloat width = [[array objectAtIndex:2] floatValue];
CGFloat height = [[array objectAtIndex:3] floatValue];
NSRect rect = CGRectMake(x, y, width, height+22);
FLOG(@" window frame = %fx, %fy, %fw, %fh", x, y, width, height);
return rect;
}
and then set the frame like so in - (void)windowControllerDidLoadNib:(NSWindowController *)aController
NSRect rect = [self windowPositionPreference];
[aController.window setFrame:rect display:YES];
The position seems to be retained exactly. Surely autosavename is just meant to work.
Upvotes: 1
Views: 210
Reputation: 8988
The above was still not working but after some messing about I gave up on using autosavename because of the automatic cascading that seems to be impossible to disable.
Now I just keep my own preferences and set the window frame using the code below. So far it seems to be working perfectly and I have not had to create my own subclasses of NSWindowController or NSWindow.
// Methods in subclassed NSPersistentDocument
- (void)windowControllerDidLoadNib:(NSWindowController *)aController {
[aController setShouldCascadeWindows:NO];
_mainWindow = aController.window;
[self restoreSavedWindowPosition];
}
- (void)close {
[self saveWindowPosition];
[super close];
}
- (void)saveWindowPosition {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *autosaveNameKey = [NSString stringWithFormat:@"OSWindow Frame %@", [self autoSaveName]];
[defaults setObject:[self stringFromFrame] forKey:autosaveNameKey];
}
- (void)restoreSavedWindowPosition {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *autosaveNameKey = [NSString stringWithFormat:@"OSWindow Frame %@", [self autoSaveName]];
NSString *frameString = [defaults objectForKey:autosaveNameKey];
// Do nothing if it has not been set
if (frameString) {
[_mainWindow setFrame:[self rectFromString:frameString] display:YES animate:YES];
}
else {
// Set the default for new docs
NSRect rect = CGRectMake(70, 350, 1000, 760);
[_mainWindow setFrame:rect display:YES animate:YES];
}
return;
}
// Use the filename as the preferences key
- (NSString*)autoSaveName {
return [[self fileURL] lastPathComponent];
}
- (NSString *)stringFromFrame {
NSRect rect = _mainWindow.frame;
rect.origin.y = rect.origin.y + 26;
rect.size.height = rect.size.height - 26;
return [self stringFromRect:rect];
}
- (NSString *)stringFromRect:(NSRect)rect {
return [NSString stringWithFormat:@"%f %f %f %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height];
}
- (NSRect)rectFromString:(NSString*)string {
NSRect rect;
NSArray *array = [string componentsSeparatedByString:@" "];
rect.origin.x = [[array objectAtIndex:0] floatValue];
rect.origin.y = [[array objectAtIndex:1] floatValue];
rect.size.width = [[array objectAtIndex:2] floatValue];
rect.size.height = [[array objectAtIndex:3] floatValue];
return rect;
}
Upvotes: 1