Implement NSDocument autosaving.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@27288 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Wolfgang Lux 2008-12-14 16:39:15 +00:00
parent c3b2fa7059
commit 91f3b7674b
5 changed files with 287 additions and 11 deletions

View file

@ -1,8 +1,24 @@
2008-12-14 Wolfgang Lux <wlux@uni-muenster.de>
2008-12-14 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSDocumentFrameworkPrivate.h:
* Source/NSApplication.m(-finishLaunching):
* Source/NSDocumentController.m (-setAutosavingDelay:,
-reopenDocumentForURL:withContentsOfURL:error:, -_autosaveDirectory,
-autosaveDocuments:, -reopenAutosavedDocuments,
-recordAutosavedDocument:):
* Source/NSDocument.m (-initForURL:withContentsOfURL:ofType:error,
-writeWithBackupToFile:ofType:saveOperation:,
-writeSafelyToURL:ofType:forSaveOperation:error:,
-revertDocumentToSaved:, close, -setAutosavedContentsFileURL:,
-autosaveDocumentsWithDelegate:didAutosaveSelector:contextInfo:,
-_removeAutosavedContentsFile):
Implement document autosaving.
2008-12-14 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSSavePanel.m (-browserDidScroll:): Perform column
validation whenever the browser is scrolled, since only the
contents of the visible columns is validated.
contents of the visible columns is validated.
2008-12-13 Fred Kiefer <FredKiefer@gmx.de>

View file

@ -83,6 +83,7 @@
#include "GSGuiPrivate.h"
#include "GNUstepGUI/GSInfoPanel.h"
#include "GNUstepGUI/GSVersion.h"
#include "NSDocumentFrameworkPrivate.h"
/* The -gui thread. See the comment in initialize_gnustep_backend. */
NSThread *GSAppKitThread;
@ -921,6 +922,7 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
unsigned count;
unsigned i;
BOOL hadDuplicates = NO;
BOOL didAutoreopen = NO;
NSImage *image = nil;
appIconFile = [infoDict objectForKey: @"NSIcon"];
@ -1053,9 +1055,16 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
[self activateIgnoringOtherApps: YES];
/* Instantiate the NSDocumentController if we are a doc-based app */
/*
* Instantiate the NSDocumentController if we are a doc-based app
* and eventually reopen all autosaved documents
*/
if ([NSDocumentController isDocumentBasedApplication])
[NSDocumentController sharedDocumentController];
{
didAutoreopen =
[[NSDocumentController sharedDocumentController]
_reopenAutosavedDocuments];
}
/*
* Now check to see if we were launched with arguments asking to
@ -1075,7 +1084,7 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
[_listener application: self printFile: filePath];
[self terminate: self];
}
else if (![defs boolForKey: @"autolaunch"]
else if (!didAutoreopen && ![defs boolForKey: @"autolaunch"]
&& [_delegate respondsToSelector:
@selector(applicationShouldOpenUntitledFile:)]
&& ([_delegate applicationShouldOpenUntitledFile: self])

View file

@ -140,13 +140,17 @@ withContentsOfURL: (NSURL *)url
self = [self initWithType: type error: error];
if (self != nil)
{
[self setFileType: type];
if (forUrl)
[self setFileURL: forUrl];
if ([self readFromURL: url
ofType: type
error: error])
{
if (forUrl != nil)
if (![url isEqual:forUrl])
{
[self setFileURL: forUrl];
[self setAutosavedContentsFileURL: url];
[self updateChangeCount: NSChangeReadOtherContents];
}
}
else
@ -791,6 +795,7 @@ withContentsOfURL: (NSURL *)url
if (saveOp != NSSaveToOperation)
{
[self _removeAutosavedContentsFile];
[self setFileName: fileName];
[self setFileType: fileType];
[self updateChangeCount: NSChangeCleared];
@ -877,8 +882,14 @@ withContentsOfURL: (NSURL *)url
error: error];
// FIXME: Should set the file attributes
if (saveOp != NSSaveToOperation)
if (saveOp == NSAutosaveOperation)
{
[self setAutosavedContentsFileURL: url];
[self updateChangeCount: NSChangeAutosaved];
}
else if (saveOp != NSSaveToOperation)
{
[self _removeAutosavedContentsFile];
[self setFileURL: url];
[self setFileType: type];
[self updateChangeCount: NSChangeCleared];
@ -1486,6 +1497,7 @@ originalContentsURL: (NSURL *)orig
{
[self updateChangeCount: NSChangeCleared];
[[self undoManager] removeAllActions];
[self _removeAutosavedContentsFile];
}
else
{
@ -1515,6 +1527,7 @@ originalContentsURL: (NSURL *)orig
while (count-- > 0)
[array[count] close];
}
[self _removeAutosavedContentsFile];
[[NSDocumentController sharedDocumentController] removeDocument: self];
}
}
@ -1621,14 +1634,40 @@ originalContentsURL: (NSURL *)orig
- (void)setAutosavedContentsFileURL: (NSURL *)url
{
ASSIGN(_autosaved_file_url, url);
[[NSDocumentController sharedDocumentController]
_recordAutosavedDocument: self];
}
- (void)autosaveDocumentWithDelegate: (id)delegate
didAutosaveSelector: (SEL)didAutosaveSelector
contextInfo: (void *)context
{
[self saveToURL: [self autosavedContentsFileURL]
ofType: [self autosavingFileType]
NSURL *url = [self autosavedContentsFileURL];
NSString *type = [self autosavingFileType];
NSArray *exts =
[[NSDocumentController sharedDocumentController]
fileExtensionsFromType: type];
NSString *ext = [exts count] ? (NSString *)[exts objectAtIndex: 0] : @"";
if (url == nil)
{
static NSString *processName = nil;
NSString *path;
if (!processName)
processName = [[[NSProcessInfo processInfo] processName] copy];
path = [[NSDocumentController sharedDocumentController]
_autosaveDirectory: YES];
path = [path stringByAppendingPathComponent:
[NSString stringWithFormat: @"%@-%d",
processName, _document_index]];
path = [path stringByAppendingPathExtension: ext];
url = [NSURL fileURLWithPath: path];
}
[self saveToURL: url
ofType: type
forSaveOperation: NSAutosaveOperation
delegate: delegate
didSaveSelector: didAutosaveSelector
@ -1678,6 +1717,20 @@ originalContentsURL: (NSURL *)orig
}
}
- (void)_removeAutosavedContentsFile
{
NSURL *url = [self autosavedContentsFileURL];
if (url)
{
NSString *path = [[url path] retain];
[self setAutosavedContentsFileURL: nil];
[[NSFileManager defaultManager] removeFileAtPath: path handler: nil];
[path release];
}
}
- (void) _changeWasDone: (NSNotification *)notification
{
/* Prevent a document from appearing unmodified after saving the

View file

@ -32,9 +32,11 @@
#include <Foundation/NSFileManager.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSPathUtilities.h>
#include <Foundation/NSProcessInfo.h>
#include <Foundation/NSString.h>
#include <Foundation/NSURL.h>
#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSTimer.h>
#include "AppKit/NSDocumentController.h"
#include "AppKit/NSOpenPanel.h"
@ -278,7 +280,24 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (void) setAutosavingDelay: (NSTimeInterval)autosavingDelay
{
static NSTimer *autosavingTimer;
if (autosavingTimer)
{
[autosavingTimer invalidate];
DESTROY (autosavingTimer);
}
_autosavingDelay = autosavingDelay;
if (autosavingDelay > 0)
{
autosavingTimer =
[NSTimer scheduledTimerWithTimeInterval: autosavingDelay
target: self
selector: @selector(_autosaveDocuments:)
userInfo: nil
repeats: YES];
RETAIN (autosavingTimer);
}
}
- (id) makeUntitledDocumentOfType: (NSString *)type
@ -572,7 +591,32 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
withContentsOfURL: (NSURL *)contents
error: (NSError **)err
{
// FIXME
if ([contents isFileURL])
{
NSString *type =
[self typeFromFileExtension: [[contents path] pathExtension]];
id document =
[self makeDocumentForURL: url
withContentsOfURL: contents
ofType: type
error: err];
if (document)
{
[self addDocument:document];
if ([self shouldCreateUI])
{
[document makeWindowControllers];
[document showWindows];
}
return YES;
}
}
else
{
// FIXME: set error
*err = nil;
}
return NO;
}
@ -1200,5 +1244,152 @@ static NSString *NSViewerRole = @"Viewer";
return [self _displayNamesForTypes:
[self _editorTypesForClass: documentClass]];
}
static NSMapTable *autosavedDocuments;
static NSString *processName;
- (NSString *) _autosaveDirectory: (BOOL)create
{
NSArray *paths =
NSSearchPathForDirectoriesInDomains (NSLibraryDirectory,
NSUserDomainMask,
YES);
NSString *path = [paths objectAtIndex:0];
path = [path stringByAppendingPathComponent: @"Autosave"];
if (create)
{
BOOL isDir;
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath: path isDirectory: &isDir] == NO)
{
if (![fm createDirectoryAtPath: path attributes: nil])
return nil;
}
else if (isDir == NO)
{
if (![fm removeFileAtPath: path handler: nil] ||
![fm createDirectoryAtPath: path attributes: nil])
return nil;
}
}
return path;
}
- (void) _autosaveDocuments: (NSTimer *)timer
{
id document;
int i, n = [_documents count];
for (i = 0; i < n; i++)
{
document = [_documents objectAtIndex: i];
if ([document autosavingFileType] && [document hasUnautosavedChanges])
{
[document autosaveDocumentWithDelegate: nil
didAutosaveSelector: NULL
contextInfo: NULL];
}
}
}
- (BOOL) _reopenAutosavedDocuments
{
BOOL didOpen = NO;
if (!autosavedDocuments)
{
NSArray *autosaved;
NSString *path;
autosavedDocuments =
NSCreateMapTable (NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks,
1);
if (!processName)
processName = [[[NSProcessInfo processInfo] processName] copy];
path = [self _autosaveDirectory: NO];
path = [path stringByAppendingPathComponent: processName];
path = [path stringByAppendingPathExtension: @"plist"];
autosaved = [NSArray arrayWithContentsOfFile: path];
if (autosaved)
{
int i, n = [autosaved count];
NSFileManager *fm = [NSFileManager defaultManager];
for (i = 0; i < n; i++)
{
NSDictionary *dict = [autosaved objectAtIndex: i];
NSString *location = [dict objectForKey: @"Location"];
NSString *autosavedLoc = [dict objectForKey: @"AutosavedLocation"];
NSURL *url = location ? [NSURL URLWithString: location] : nil;
NSURL *autosavedURL =
autosavedLoc ? [NSURL URLWithString: autosavedLoc] : nil;
if (autosavedURL && [fm fileExistsAtPath: [autosavedURL path]])
{
NSError *err;
if ([self reopenDocumentForURL: url
withContentsOfURL: autosavedURL
error: &err])
didOpen = YES;
}
}
}
}
return didOpen;
}
- (void) _recordAutosavedDocument: (NSDocument *)document
{
BOOL changed = NO;
NSURL *url = [document autosavedContentsFileURL];
if (!autosavedDocuments)
autosavedDocuments =
NSCreateMapTable (NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks,
1);
if (!processName)
processName = [[[NSProcessInfo processInfo] processName] copy];
if (url)
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
if ([document fileURL])
[dict setObject: [document fileURL] forKey: @"Location"];
[dict setObject: url forKey: @"AutosavedLocation"];
NSMapInsert (autosavedDocuments, document, dict);
[dict release];
changed = YES;
}
else if (NSMapGet (autosavedDocuments, document))
{
NSMapRemove (autosavedDocuments, document);
changed = YES;
}
if (changed)
{
NSString *path = [self _autosaveDirectory: YES];
NSArray *autosaved = NSAllMapTableValues (autosavedDocuments);
NSFileManager *fm = [NSFileManager defaultManager];
path = [path stringByAppendingPathComponent: processName];
path = [path stringByAppendingPathExtension: @"plist"];
if ([autosaved count] == 0)
{
[fm removeFileAtPath: path handler: nil];
}
else
{
[autosaved writeToFile: path atomically:YES];
}
}
}
@end

View file

@ -32,6 +32,8 @@
#include <AppKit/NSDocumentController.h>
@class NSTimer;
@interface NSDocumentController (Private)
- (NSArray *)_editorAndViewerTypesForClass:(Class)documentClass;
- (NSArray *)_editorTypesForClass:(Class)fp12;
@ -39,6 +41,10 @@
- (NSString *)_nameForHumanReadableType: (NSString *)type;
- (NSArray *)_displayNamesForTypes: (NSArray *)types;
- (NSArray *)_displayNamesForClass: (Class)documentClass;
- (NSString *)_autosaveDirectory: (BOOL)create;
- (void)_autosaveDocuments: (NSTimer *)timer;
- (BOOL)_reopenAutosavedDocuments;
- (void)_recordAutosavedDocument: (NSDocument *)document;
@end
@ -47,6 +53,7 @@
@interface NSDocument (Private)
- (void)_removeWindowController:(NSWindowController *)controller;
- (NSWindow *)_transferWindowOwnership;
- (void)_removeAutosavedContentsFile;
@end