Created
December 9, 2010 17:53
-
-
Save dasto/735057 to your computer and use it in GitHub Desktop.
proposal for overhaul of cappuccinos document architecture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@implementation CPOverhauledDocument : CPDocument | |
{ | |
id _documentPersistenceAgent; | |
Object _persistenceOperationInfo; | |
} | |
/* | |
-> this might be the right place to obtain _documentPersistenceAgent based on document type | |
-> uses the base class to determine the right class | |
*/ | |
- (void)setFileType:(CPString)aType | |
{ | |
[super setFileType:aType]; | |
_documentPersistenceAgent = [[[CPDocumentPersistenceAgent persistenceAgentClassForFileType:aType] alloc] initWithDocument:self]; | |
} | |
/* | |
-> sending CPDocumentWillSaveNotification has moved to "saveToURL:..." | |
*/ | |
- (void)saveDocumentWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo | |
{ | |
if (_fileURL) | |
{ | |
//[[CPNotificationCenter defaultCenter] | |
// postNotificationName:CPDocumentWillSaveNotification | |
// object:self]; | |
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; | |
} | |
else | |
[self _saveDocumentAsWithDelegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; | |
} | |
/* | |
-> instead of using a fixed save panel, retrieve it from _documentPersistenceAgent | |
-> fixed missing delegate message in CPDocument when savePanel is aborted | |
-> sending CPDocumentWillSaveNotification has moved to "saveToURL:..." | |
*/ | |
- (void)_saveDocumentAsWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo | |
{ | |
//var savePanel = [CPSavePanel savePanel], | |
var savePanel = [_documentPersistenceAgent savePanel], | |
response = [savePanel runModal]; | |
if (!response) | |
{ | |
objj_msgSend(delegate, didSaveSelector, self, NO, contextInfo); | |
return; | |
} | |
//if (!response) | |
// return; | |
var saveURL = [savePanel URL]; | |
//[[CPNotificationCenter defaultCenter] | |
// postNotificationName:CPDocumentWillSaveNotification | |
// object:self]; | |
[self saveToURL:saveURL ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; | |
} | |
/* | |
-> instead of executing the persistence operation itself delegate to _documentPersistenceAgent! | |
-> only allow one persistence operation at a time! (maybe not strictly necessary) | |
-> do not update change count in advance, instead cache the current value and update after the operation has succeeded! | |
-> sending CPDocumentWillSaveNotification has moved here (but only if it definitely gets executed) | |
*/ | |
- (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aType forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo | |
{ | |
if(_persistenceOperationInfo) | |
objj_msgSend(aDelegate, aDidSaveSelector, self, NO, aContextInfo); | |
else | |
{ | |
_persistenceOperationInfo = { operationURL:anAbsoluteURL, delegate:aDelegate, finishSelector:aDidSaveSelector, context:aContextInfo, operationType:aSaveOperation, operationChangeCount:_changeCount }; | |
[self _sendDocumentWillSaveNotification]; | |
[_documentPersistenceAgent saveDocumentToURL:anAbsoluteURL ofType:aType forSaveOperation:aSaveOperation]; | |
} | |
/* | |
var data = [self dataOfType:[self fileType] error:nil], | |
oldChangeCount = _changeCount; | |
_writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL]; | |
// FIXME: THIS IS WRONG! We need a way to decide | |
if ([CPPlatform isBrowser]) | |
[_writeRequest setHTTPMethod:@"POST"]; | |
else | |
[_writeRequest setHTTPMethod:@"PUT"]; | |
[_writeRequest setHTTPBody:[data rawString]]; | |
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"]; | |
if (aSaveOperation === CPSaveOperation) | |
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"]; | |
if (aSaveOperation !== CPSaveToOperation) | |
[self updateChangeCount:CPChangeCleared]; | |
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors. | |
var connection = [CPURLConnection connectionWithRequest:_writeRequest delegate:self]; | |
connection.session = _CPSaveSessionMake(anAbsoluteURL, aSaveOperation, oldChangeCount, aDelegate, aDidSaveSelector, aContextInfo, connection); | |
*/ | |
} | |
- (void)_sendDocumentWillSaveNotification | |
{ | |
[[CPNotificationCenter defaultCenter] postNotificationName:CPDocumentWillSaveNotification object:self]; | |
} | |
/* | |
-> new callback for _documentPersistenceAgent | |
-> performs delegate message (formerly buried in CPURLConnection`s delegate methods) | |
-> sets fileURL (formerly buried in CPURLConnection`s delegate methods) | |
-> update change count only if the operation succeeded! (formerly updated in advance and corrected afterwards if operation failed) | |
-> all generic alerts and confirms have been removed (can be implemented in subclasses of CPOverhauledDocument) | |
-> FIXME: currently implemented no "overwrite" functionality | |
*/ | |
- (void)_saveOperationFinishedWithSuccess:(BOOL)aFlag | |
{ | |
var operationType = _persistenceOperationInfo.operationType; | |
if(aFlag && (operationType != CPSaveToOperation)) | |
{ | |
_changeCount -= _persistenceOperationInfo.operationChangeCount; | |
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; | |
if(operationType != CPSaveOperation) | |
[self setFileURL:_persistenceOperationInfo.operationURL]; | |
} | |
[self _sendDocumentSavedNotification:aFlag]; | |
objj_msgSend(_persistenceOperationInfo.delegate, _persistenceOperationInfo.finishSelector, self, aFlag, _persistenceOperationInfo.context); | |
_persistenceOperationInfo = nil; | |
} | |
/* | |
-> instead of executing the persistence operation itself delegate to _documentPersistenceAgent! | |
-> only allow one persistence operation at a time! (maybe not strictly necessary) | |
*/ | |
- (void)readFromURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo | |
{ | |
if(_persistenceOperationInfo) | |
objj_msgSend(aDelegate, aDidReadSelector, self, NO, aContextInfo); | |
else | |
{ | |
_persistenceOperationInfo = { operationURL:anAbsoluteURL, delegate:aDelegate, finishSelector:aDidReadSelector, context:aContextInfo, }; | |
[_documentPersistenceAgent readDocumentFromURL:anAbsoluteURL ofType:aType]; | |
} | |
/* | |
[_readConnection cancel]; | |
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors. | |
_readConnection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:anAbsoluteURL] delegate:self]; | |
_readConnection.session = _CPReadSessionMake(aType, aDelegate, aDidReadSelector, aContextInfo); | |
*/ | |
} | |
/* | |
-> new callback for _documentPersistenceAgent | |
-> performs delegate message formerly buried in CPURLConnection`s delegate methods | |
-> readFromData: is called by _documentPersistenceAgent | |
*/ | |
- (void)_readOperationFinishedWithSuccess:(BOOL)aFlag | |
{ | |
var operationType = _persistenceOperationInfo.operationType; | |
//for read operations the fileURL has been set in advance, so if read does not succeed, reset it to nil... | |
if(aFlag == NO) | |
[self setFileURL:nil]; | |
objj_msgSend(_persistenceOperationInfo.delegate, _persistenceOperationInfo.finishSelector, self, aFlag, _persistenceOperationInfo.context); | |
_persistenceOperationInfo = nil; | |
} | |
@end | |
@implementation CPOverhauledDocumentController : CPDocumentController | |
{ | |
} | |
/* | |
-> instead of using a fixed save panel, retrieve it from CPDocumentPersistenceAgent class for default document type | |
*/ | |
- (void)openDocument:(id)aSender | |
{ | |
var docPersistenceAgentClass = [CPDocumentPersistenceAgent persistenceAgentClassForFileType:[self defaultType]]; | |
var openPanel = [docPersistenceAgentClass openPanelForFileType:[self defaultType]]; | |
//var openPanel = [CPOpenPanel openPanel]; | |
[openPanel runModal]; | |
var URLs = [openPanel URLs], | |
index = 0, | |
count = [URLs count]; | |
for (; index < count; ++index) | |
[self openDocumentWithContentsOfURL:[CPURL URLWithString:URLs[index]] display:YES error:nil]; | |
} | |
@end | |
@implementation CPDocumentPersistenceAgent : CPObject | |
{ | |
CPOverhauledDocument _persistedDocument; | |
} | |
+ (id)persistenceAgentClassForFileType:(CPString)aFileType | |
{ | |
var documentTypes = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPBundleDocumentTypes"]; | |
var documentType, documentTypeEnumerator = [documentTypes objectEnumerator]; | |
while(documentType = [documentTypeEnumerator nextObject]) | |
{ | |
if([documentType objectForKey:@"CPBundleTypeName"] == aFileType) | |
{ | |
var docPersistenceAgentClassName = [documentType objectForKey:@"CPDocumentPersistenceAgentClass"]; | |
return CPClassFromString(docPersistenceAgentClassName); | |
} | |
} | |
[CPException raise:@"CPDocumentPersistenceAgentException" reason:@"no valid 'CPDocumentPersistenceAgentClass' set in Info.plist"] | |
} | |
+ (id)openPanelForFileType:(CPString)aFileType | |
{ | |
[CPException raise:@"CPDocumentPersistenceAgentException" reason:@"'openPanelForFileType' is abstract in CPDocumentPersistenceAgent"] | |
} | |
- (id)savePanel | |
{ | |
[CPException raise:@"CPDocumentPersistenceAgentException" reason:@"'savePanel' is abstract in CPDocumentPersistenceAgent"] | |
} | |
- (id)initWithDocument:(CPDocument)aDocument | |
{ | |
if(self = [self init]) | |
_persistedDocument = aDocument; | |
return self; | |
} | |
- (void)saveDocumentToURL:(CPURL)anAbsoluteURL ofType:(CPString)aType forSaveOperation:(CPSaveOperationType)aSaveOperation | |
{ | |
[CPException raise:@"CPDocumentPersistenceAgentException" reason:@"'saveDocumentToURL:ofType:forSaveOperation:' is abstract in CPDocumentPersistenceAgent"] | |
} | |
- (void)readDocumentFromURL:(CPURL)anAbsoluteURL ofType:(CPString)aType | |
{ | |
[CPException raise:@"CPDocumentPersistenceAgentException" reason:@"'readDocumentFromURL:ofType:' is abstract in CPDocumentPersistenceAgent"] | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment