mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 03:11:18 +00:00
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:
parent
c3b2fa7059
commit
91f3b7674b
5 changed files with 287 additions and 11 deletions
20
ChangeLog
20
ChangeLog
|
@ -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>
|
||||
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue