98 CPArray _windowControllers;
99 unsigned _untitledDocumentIndex;
101 BOOL _hasUndoManager;
122 _windowControllers = [];
123 _viewControllersForWindowControllers = @{};
125 _hasUndoManager = YES;
161 - (id)initWithContentsOfURL:(
CPURL)anAbsoluteURL ofType:(
CPString)aType delegate:(
id)aDelegate didReadSelector:(
SEL)aDidReadSelector contextInfo:(
id)aContextInfo
186 - (id)initForURL:(
CPURL)anAbsoluteURL withContentsOfURL:(
CPURL)absoluteContentsURL ofType:(
CPString)aType delegate:(
id)aDelegate didReadSelector:(
SEL)aDidReadSelector contextInfo:(
id)aContextInfo
212 reason:"dataOfType:error: must be overridden by the document subclass."];
227 reason:"readFromData:ofType: must be overridden by the document subclass."];
242 - (void)makeWindowControllers
247 - (void)makeViewAndWindowControllers
251 viewController = nil,
252 windowController = nil;
255 if ([viewCibName length])
259 if ([windowCibName length])
263 else if (viewController)
265 var view = [viewController view],
266 viewFrame = [view frame];
268 viewFrame.origin = CGPointMake(50, 50);
275 if (windowController && viewController)
276 [windowController setSupportsMultipleDocuments:YES];
278 if (windowController)
288 - (CPArray)windowControllers
290 return _windowControllers;
300 [_windowControllers addObject:aWindowController];
302 if ([aWindowController document] !==
self)
313 if (aWindowController)
314 [_windowControllers removeObject:aWindowController];
316 if ([aWindowController document] ===
self)
325 - (CPArray)viewControllers
327 return [_viewControllersForWindowControllers allValues];
333 [_viewControllersForWindowControllers setObject:aViewController forKey:[aWindowController
UID]];
335 if ([aWindowController document] ===
self)
341 [_viewControllersForWindowControllers removeObject:aViewController];
346 return [_viewControllersForWindowControllers objectForKey:[aWindowController
UID]];
355 [_windowControllers makeObjectsPerformSelector:@selector(setDocument:) withObject:self];
356 [_windowControllers makeObjectsPerformSelector:@selector(showWindow:) withObject:self];
365 return [_fileURL lastPathComponent];
367 if (!_untitledDocumentIndex)
370 if (_untitledDocumentIndex == 1)
373 return @"Untitled " + _untitledDocumentIndex;
414 - (void)readFromURL:(
CPURL)anAbsoluteURL ofType:(
CPString)aType delegate:(
id)aDelegate didReadSelector:(
SEL)aDidReadSelector contextInfo:(
id)aContextInfo
416 [_readConnection cancel];
421 _readConnection.session = _CPReadSessionMake(aType, aDelegate, aDidReadSelector, aContextInfo);
438 if (_fileURL === aFileURL)
443 [_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
456 - (void)saveToURL:(
CPURL)anAbsoluteURL ofType:(
CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(
id)aDelegate didSaveSelector:(
SEL)aDidSaveSelector contextInfo:(
id)aContextInfo
459 oldChangeCount = _changeCount;
465 [_writeRequest setHTTPMethod:@"POST"];
467 [_writeRequest setHTTPMethod:@"PUT"];
469 [_writeRequest setHTTPBody:[data rawString]];
471 [_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
474 [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
482 connection.session = _CPSaveSessionMake(anAbsoluteURL, aSaveOperation, oldChangeCount, aDelegate, aDidSaveSelector, aContextInfo, connection);
495 var statusCode = [aResponse statusCode];
498 if (statusCode === 200)
501 var session = aConnection.session;
503 if (aConnection == _readConnection)
507 alert(
"There was an error retrieving the document.");
509 objj_msgSend(session.delegate, session.didReadSelector,
self, NO, session.contextInfo);
514 if (statusCode == 409)
518 if (confirm(
"There already exists a file with that name, would you like to overwrite it?"))
520 [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
528 _changeCount += session.changeCount;
529 [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[
self isDocumentEdited]];
534 objj_msgSend(session.delegate, session.didSaveSelector,
self, NO, session.contextInfo);
535 [
self _sendDocumentSavedNotification:NO];
547 var session = aConnection.session;
550 if (aConnection == _readConnection)
554 objj_msgSend(session.delegate, session.didReadSelector,
self, YES, session.contextInfo);
563 objj_msgSend(session.delegate, session.didSaveSelector,
self, YES, session.contextInfo);
564 [
self _sendDocumentSavedNotification:YES];
574 var session = aConnection.session;
576 if (_readConnection == aConnection)
577 objj_msgSend(session.delegate, session.didReadSelector,
self, NO, session.contextInfo);
583 _changeCount += session.changeCount;
584 [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[
self isDocumentEdited]];
589 alert(
"There was an error saving the document.");
591 objj_msgSend(session.delegate, session.didSaveSelector,
self, NO, session.contextInfo);
592 [
self _sendDocumentSavedNotification:NO];
602 if (_readConnection == aConnection)
603 _readConnection = nil;
610 - (BOOL)isDocumentEdited
612 return _changeCount != 0;
619 - (void)updateChangeCount:(CPDocumentChangeType)aChangeType
631 [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[
self isDocumentEdited]];
657 - (BOOL)hasUndoManager
659 return _hasUndoManager;
666 - (void)setHasUndoManager:(BOOL)aFlag
668 if (_hasUndoManager == aFlag)
671 _hasUndoManager = aFlag;
673 if (!_hasUndoManager)
680 var undoManager = [aNotification
object];
682 if ([undoManager isUndoing] || [undoManager isRedoing])
685 [
self updateChangeCount:CPChangeDone];
691 [
self updateChangeCount:CPChangeUndone];
697 [
self updateChangeCount:CPChangeDone];
711 [defaultCenter removeObserver:self
712 name:CPUndoManagerDidUndoChangeNotification
713 object:_undoManager];
715 [defaultCenter removeObserver:self
716 name:CPUndoManagerDidRedoChangeNotification
717 object:_undoManager];
719 [defaultCenter removeObserver:self
720 name:CPUndoManagerWillCloseUndoGroupNotification
721 object:_undoManager];
724 _undoManager = anUndoManager;
729 [defaultCenter addObserver:self
730 selector:@selector(_undoManagerDidUndoChange:)
731 name:CPUndoManagerDidUndoChangeNotification
732 object:_undoManager];
734 [defaultCenter addObserver:self
735 selector:@selector(_undoManagerDidRedoChange:)
736 name:CPUndoManagerDidRedoChangeNotification
737 object:_undoManager];
739 [defaultCenter addObserver:self
740 selector:@selector(_undoManagerWillCloseGroup:)
741 name:CPUndoManagerWillCloseUndoGroupNotification
742 object:_undoManager];
754 if (_hasUndoManager && !_undoManager)
776 - (void)saveDocument:(
id)aSender
781 - (void)saveDocumentWithDelegate:(
id)delegate didSaveSelector:(
SEL)didSaveSelector contextInfo:(Object)contextInfo
789 [
self saveToURL:_fileURL
ofType:[
self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
792 [
self _saveDocumentAsWithDelegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
799 - (void)saveDocumentAs:(
id)aSender
801 [
self _saveDocumentAsWithDelegate:nil didSaveSelector:nil contextInfo:nil];
804 - (void)_saveDocumentAsWithDelegate:(
id)delegate didSaveSelector:(
SEL)didSaveSelector contextInfo:(Object)contextInfo
807 response = [savePanel runModal];
812 var saveURL = [savePanel URL];
818 [
self saveToURL:saveURL ofType:[
self fileType] forSaveOperation:CPSaveAsOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
824 - (void)_sendDocumentSavedNotification:(BOOL)didSave
842 [_windowControllers makeObjectsPerformSelector:@selector(removeDocumentAndCloseIfNecessary:) withObject:self];
846 - (void)shouldCloseWindowController:(
CPWindowController)controller delegate:(
id)delegate shouldCloseSelector:(
SEL)selector contextInfo:(Object)info
848 if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !==
CPNotFound))
849 [
self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
851 else if ([
delegate respondsToSelector:selector])
852 objj_msgSend(
delegate, selector,
self, YES, info);
855 - (void)_document:(
CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
857 if (aDocument ===
self && shouldClose)
860 objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
863 - (void)canCloseDocumentWithDelegate:(
id)aDelegate shouldCloseSelector:(
SEL)aSelector contextInfo:(Object)context
865 if (![
self isDocumentEdited])
866 return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector,
self, YES, context);
870 [_canCloseAlert setDelegate:self];
871 [_canCloseAlert setAlertStyle:CPWarningAlertStyle];
872 [_canCloseAlert setTitle:@"Unsaved Document"];
873 [_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([
self displayName] || [
self fileName]) + "\"?"];
875 [_canCloseAlert addButtonWithTitle:@"Save"];
876 [_canCloseAlert addButtonWithTitle:@"Cancel"];
877 [_canCloseAlert addButtonWithTitle:@"Don't Save"];
879 _canCloseAlert._context = {
delegate:aDelegate, selector:aSelector, context:context};
881 [_canCloseAlert runModal];
884 - (void)alertDidEnd:(
CPAlert)alert returnCode:(
int)returnCode
886 if (alert !== _canCloseAlert)
889 var
delegate = alert._context.delegate,
890 selector = alert._context.selector,
891 context = alert._context.context;
893 if (returnCode === 0)
896 objj_msgSend(
delegate, selector,
self, returnCode === 2, context);
898 _canCloseAlert = nil;
903 var _CPReadSessionMake =
function(aType, aDelegate, aDidReadSelector, aContextInfo)
905 return { fileType:aType,
delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
908 var _CPSaveSessionMake =
function(anAbsoluteURL, aSaveOperation, aChangeCount, aDelegate, aDidSaveSelector, aContextInfo, aConnection)
910 return { absoluteURL:anAbsoluteURL, saveOperation:aSaveOperation, changeCount:aChangeCount,
delegate:aDelegate, didSaveSelector:aDidSaveSelector, contextInfo:aContextInfo, connection:aConnection };