![]() |
API 0.9.5
|
00001 /* 00002 * CPDocument.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 00025 00026 /* 00027 @global 00028 @group CPSaveOperationType 00029 */ 00030 CPSaveOperation = 0; 00031 /* 00032 @global 00033 @group CPSaveOperationType 00034 */ 00035 CPSaveAsOperation = 1; 00036 /* 00037 @global 00038 @group CPSaveOperationType 00039 */ 00040 CPSaveToOperation = 2; 00041 /* 00042 @global 00043 @group CPSaveOperationType 00044 */ 00045 CPAutosaveOperation = 3; 00046 00047 /* 00048 @global 00049 @group CPDocumentChangeType 00050 */ 00051 CPChangeDone = 0; 00052 /* 00053 @global 00054 @group CPDocumentChangeType 00055 */ 00056 CPChangeUndone = 1; 00057 /* 00058 @global 00059 @group CPDocumentChangeType 00060 */ 00061 CPChangeCleared = 2; 00062 /* 00063 @global 00064 @group CPDocumentChangeType 00065 */ 00066 CPChangeReadOtherContents = 3; 00067 /* 00068 @global 00069 @group CPDocumentChangeType 00070 */ 00071 CPChangeAutosaved = 4; 00072 00073 CPDocumentWillSaveNotification = @"CPDocumentWillSaveNotification"; 00074 CPDocumentDidSaveNotification = @"CPDocumentDidSaveNotification"; 00075 CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification"; 00076 00077 var CPDocumentUntitledCount = 0; 00078 00088 @implementation CPDocument : CPResponder 00089 { 00090 CPWindow _window; // For outlet purposes. 00091 CPView _view; // For outlet purposes 00092 CPDictionary _viewControllersForWindowControllers; 00093 00094 CPURL _fileURL; 00095 CPString _fileType; 00096 CPArray _windowControllers; 00097 unsigned _untitledDocumentIndex; 00098 00099 BOOL _hasUndoManager; 00100 CPUndoManager _undoManager; 00101 00102 int _changeCount; 00103 00104 CPURLConnection _readConnection; 00105 CPURLRequest _writeRequest; 00106 00107 CPAlert _canCloseAlert; 00108 } 00109 00114 - (id)init 00115 { 00116 self = [super init]; 00117 00118 if (self) 00119 { 00120 _windowControllers = []; 00121 _viewControllersForWindowControllers = [CPDictionary dictionary]; 00122 00123 _hasUndoManager = YES; 00124 _changeCount = 0; 00125 00126 [self setNextResponder:CPApp]; 00127 } 00128 00129 return self; 00130 } 00131 00138 - (id)initWithType:(CPString)aType error:({CPError})anError 00139 { 00140 self = [self init]; 00141 00142 if (self) 00143 [self setFileType:aType]; 00144 00145 return self; 00146 } 00147 00159 - (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo 00160 { 00161 self = [self init]; 00162 00163 if (self) 00164 { 00165 [self setFileURL:anAbsoluteURL]; 00166 [self setFileType:aType]; 00167 00168 [self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo]; 00169 } 00170 00171 return self; 00172 } 00173 00184 - (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo 00185 { 00186 self = [self init]; 00187 00188 if (self) 00189 { 00190 [self setFileURL:anAbsoluteURL]; 00191 [self setFileType:aType]; 00192 00193 [self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo]; 00194 } 00195 00196 return self; 00197 } 00198 00207 - (CPData)dataOfType:(CPString)aType error:({CPError})anError 00208 { 00209 [CPException raise:CPUnsupportedMethodException 00210 reason:"dataOfType:error: must be overridden by the document subclass."]; 00211 } 00212 00222 - (void)readFromData:(CPData)aData ofType:(CPString)aType error:(CPError)anError 00223 { 00224 [CPException raise:CPUnsupportedMethodException 00225 reason:"readFromData:ofType: must be overridden by the document subclass."]; 00226 } 00227 00228 - (void)viewControllerWillLoadCib:(CPViewController)aViewController 00229 { 00230 } 00231 00232 - (void)viewControllerDidLoadCib:(CPViewController)aViewController 00233 { 00234 } 00235 00236 - (CPWindowController)firstEligibleExistingWindowController 00237 { 00238 return nil; 00239 } 00240 00241 // Creating and managing window controllers 00245 - (void)makeWindowControllers 00246 { 00247 [self makeViewAndWindowControllers]; 00248 } 00249 00250 - (void)makeViewAndWindowControllers 00251 { 00252 var viewCibName = [self viewCibName], 00253 viewController = nil, 00254 windowController = nil; 00255 00256 // Create our view controller if we have a cib for it. 00257 if ([viewCibName length]) 00258 viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self]; 00259 00260 // If we have a view controller, check if we have a free window for it. 00261 if (viewController) 00262 windowController = [self firstEligibleExistingWindowController]; 00263 00264 // If not, create one. 00265 if (!windowController) 00266 { 00267 var windowCibName = [self windowCibName]; 00268 00269 // From a cib if we have one. 00270 if ([windowCibName length]) 00271 windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self]; 00272 00273 // If not you get a standard window capable of displaying multiple documents and view 00274 else if (viewController) 00275 { 00276 var view = [viewController view], 00277 viewFrame = [view frame]; 00278 00279 viewFrame.origin = CGPointMake(50, 50); 00280 00281 var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask]; 00282 00283 windowController = [[CPWindowController alloc] initWithWindow:theWindow]; 00284 } 00285 } 00286 00287 if (windowController && viewController) 00288 [windowController setSupportsMultipleDocuments:YES]; 00289 00290 if (windowController) 00291 [self addWindowController:windowController]; 00292 00293 if (viewController) 00294 [self addViewController:viewController forWindowController:windowController]; 00295 } 00296 00300 - (CPArray)windowControllers 00301 { 00302 return _windowControllers; 00303 } 00304 00310 - (void)addWindowController:(CPWindowController)aWindowController 00311 { 00312 [_windowControllers addObject:aWindowController]; 00313 00314 if ([aWindowController document] !== self) 00315 [aWindowController setDocument:self]; 00316 } 00317 00323 - (void)removeWindowController:(CPWindowController)aWindowController 00324 { 00325 if (aWindowController) 00326 [_windowControllers removeObject:aWindowController]; 00327 00328 if ([aWindowController document] === self) 00329 [aWindowController setDocument:nil]; 00330 } 00331 00332 - (CPView)view 00333 { 00334 return _view; 00335 } 00336 00337 - (CPArray)viewControllers 00338 { 00339 return [_viewControllersForWindowControllers allValues]; 00340 } 00341 00342 - (void)addViewController:(CPViewController)aViewController forWindowController:(CPWindowController)aWindowController 00343 { 00344 // FIXME: exception if we don't own the window controller? 00345 [_viewControllersForWindowControllers setObject:aViewController forKey:[aWindowController UID]]; 00346 00347 if ([aWindowController document] === self) 00348 [aWindowController setViewController:aViewController]; 00349 } 00350 00351 - (void)removeViewController:(CPViewController)aViewController 00352 { 00353 [_viewControllersForWindowControllers removeObject:aViewController]; 00354 } 00355 00356 - (CPViewController)viewControllerForWindowController:(CPWindowController)aWindowController 00357 { 00358 return [_viewControllersForWindowControllers objectForKey:[aWindowController UID]]; 00359 } 00360 00361 // Managing Document Windows 00365 - (void)showWindows 00366 { 00367 [_windowControllers makeObjectsPerformSelector:@selector(setDocument:) withObject:self]; 00368 [_windowControllers makeObjectsPerformSelector:@selector(showWindow:) withObject:self]; 00369 } 00370 00374 - (CPString)displayName 00375 { 00376 if (_fileURL) 00377 return [_fileURL lastPathComponent]; 00378 00379 if (!_untitledDocumentIndex) 00380 _untitledDocumentIndex = ++CPDocumentUntitledCount; 00381 00382 if (_untitledDocumentIndex == 1) 00383 return @"Untitled"; 00384 00385 return @"Untitled " + _untitledDocumentIndex; 00386 } 00387 00388 - (CPString)viewCibName 00389 { 00390 return nil; 00391 } 00392 00396 - (CPString)windowCibName 00397 { 00398 return nil; 00399 } 00400 00405 - (void)windowControllerDidLoadCib:(CPWindowController)aWindowController 00406 { 00407 } 00408 00413 - (void)windowControllerWillLoadCib:(CPWindowController)aWindowController 00414 { 00415 } 00416 00417 // Reading from and Writing to URLs 00426 - (void)readFromURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo 00427 { 00428 [_readConnection cancel]; 00429 00430 // FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors. 00431 _readConnection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:anAbsoluteURL] delegate:self]; 00432 00433 _readConnection.session = _CPReadSessionMake(aType, aDelegate, aDidReadSelector, aContextInfo); 00434 } 00435 00439 - (CPURL)fileURL 00440 { 00441 return _fileURL; 00442 } 00443 00448 - (void)setFileURL:(CPURL)aFileURL 00449 { 00450 if (_fileURL === aFileURL) 00451 return; 00452 00453 _fileURL = aFileURL; 00454 00455 [_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)]; 00456 } 00457 00468 - (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo 00469 { 00470 var data = [self dataOfType:[self fileType] error:nil], 00471 oldChangeCount = _changeCount; 00472 00473 _writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL]; 00474 00475 // FIXME: THIS IS WRONG! We need a way to decide 00476 if ([CPPlatform isBrowser]) 00477 [_writeRequest setHTTPMethod:@"POST"]; 00478 else 00479 [_writeRequest setHTTPMethod:@"PUT"]; 00480 00481 [_writeRequest setHTTPBody:[data rawString]]; 00482 00483 [_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"]; 00484 00485 if (aSaveOperation === CPSaveOperation) 00486 [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"]; 00487 00488 if (aSaveOperation !== CPSaveToOperation) 00489 [self updateChangeCount:CPChangeCleared]; 00490 00491 // FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors. 00492 var connection = [CPURLConnection connectionWithRequest:_writeRequest delegate:self]; 00493 00494 connection.session = _CPSaveSessionMake(anAbsoluteURL, aSaveOperation, oldChangeCount, aDelegate, aDidSaveSelector, aContextInfo, connection); 00495 } 00496 00497 /* 00498 Implemented as a delegate method for CPURLConnection 00499 @ignore 00500 */ 00501 - (void)connection:(CPURLConnection)aConnection didReceiveResponse:(CPURLResponse)aResponse 00502 { 00503 // If we got this far and it wasn't an HTTP request, then everything is fine. 00504 if (![aResponse isKindOfClass:[CPHTTPURLResponse class]]) 00505 return; 00506 00507 var statusCode = [aResponse statusCode]; 00508 00509 // Nothing to do if everything is hunky dory. 00510 if (statusCode === 200) 00511 return; 00512 00513 var session = aConnection.session; 00514 00515 if (aConnection == _readConnection) 00516 { 00517 [aConnection cancel]; 00518 00519 alert("There was an error retrieving the document."); 00520 00521 objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo); 00522 } 00523 else 00524 { 00525 // 409: Conflict, in Cappuccino, overwrite protection for documents. 00526 if (statusCode == 409) 00527 { 00528 [aConnection cancel]; 00529 00530 if (confirm("There already exists a file with that name, would you like to overwrite it?")) 00531 { 00532 [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"]; 00533 00534 [aConnection start]; 00535 } 00536 else 00537 { 00538 if (session.saveOperation != CPSaveToOperation) 00539 { 00540 _changeCount += session.changeCount; 00541 [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; 00542 } 00543 00544 _writeRequest = nil; 00545 00546 objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo); 00547 [self _sendDocumentSavedNotification:NO]; 00548 } 00549 } 00550 } 00551 } 00552 00553 /* 00554 Implemented as a delegate method for CPURLConnection 00555 @ignore 00556 */ 00557 - (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData 00558 { 00559 var session = aConnection.session; 00560 00561 // READ 00562 if (aConnection == _readConnection) 00563 { 00564 [self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil]; 00565 00566 objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo); 00567 } 00568 else 00569 { 00570 if (session.saveOperation != CPSaveToOperation) 00571 [self setFileURL:session.absoluteURL]; 00572 00573 _writeRequest = nil; 00574 00575 objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo); 00576 [self _sendDocumentSavedNotification:YES]; 00577 } 00578 } 00579 00580 /* 00581 Implemented as a delegate method for CPURLConnection 00582 @ignore 00583 */ 00584 - (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError 00585 { 00586 var session = aConnection.session; 00587 00588 if (_readConnection == aConnection) 00589 objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo); 00590 00591 else 00592 { 00593 if (session.saveOperation != CPSaveToOperation) 00594 { 00595 _changeCount += session.changeCount; 00596 [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; 00597 } 00598 00599 _writeRequest = nil; 00600 00601 alert("There was an error saving the document."); 00602 00603 objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo); 00604 [self _sendDocumentSavedNotification:NO]; 00605 } 00606 } 00607 00608 /* 00609 Implemented as a delegate method for CPURLConnection 00610 @ignore 00611 */ 00612 - (void)connectionDidFinishLoading:(CPURLConnection)aConnection 00613 { 00614 if (_readConnection == aConnection) 00615 _readConnection = nil; 00616 } 00617 00618 // Managing Document Status 00622 - (BOOL)isDocumentEdited 00623 { 00624 return _changeCount != 0; 00625 } 00626 00631 - (void)updateChangeCount:(CPDocumentChangeType)aChangeType 00632 { 00633 if (aChangeType == CPChangeDone) 00634 ++_changeCount; 00635 else if (aChangeType == CPChangeUndone) 00636 --_changeCount; 00637 else if (aChangeType == CPChangeCleared) 00638 _changeCount = 0; 00639 /*else if (aChangeType == CPCHangeReadOtherContents) 00640 00641 else if (aChangeType == CPChangeAutosaved)*/ 00642 00643 [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; 00644 } 00645 00646 // Managing File Types 00651 - (void)setFileType:(CPString)aType 00652 { 00653 _fileType = aType; 00654 } 00655 00659 - (CPString)fileType 00660 { 00661 return _fileType; 00662 } 00663 00664 // Working with Undo Manager 00669 - (BOOL)hasUndoManager 00670 { 00671 return _hasUndoManager; 00672 } 00673 00678 - (void)setHasUndoManager:(BOOL)aFlag 00679 { 00680 if (_hasUndoManager == aFlag) 00681 return; 00682 00683 _hasUndoManager = aFlag; 00684 00685 if (!_hasUndoManager) 00686 [self setUndoManager:nil]; 00687 } 00688 00689 /* @ignore */ 00690 - (void)_undoManagerWillCloseGroup:(CPNotification)aNotification 00691 { 00692 var undoManager = [aNotification object]; 00693 00694 if ([undoManager isUndoing] || [undoManager isRedoing]) 00695 return; 00696 00697 [self updateChangeCount:CPChangeDone]; 00698 } 00699 00700 /* @ignore */ 00701 - (void)_undoManagerDidUndoChange:(CPNotification)aNotification 00702 { 00703 [self updateChangeCount:CPChangeUndone]; 00704 } 00705 00706 /* @ignore */ 00707 - (void)_undoManagerDidRedoChange:(CPNotification)aNotification 00708 { 00709 [self updateChangeCount:CPChangeDone]; 00710 } 00711 00712 /* 00713 Sets the document's undo manager. This method will add the 00714 undo manager as an observer to the notification center. 00715 @param anUndoManager the new undo manager for the document 00716 */ 00717 - (void)setUndoManager:(CPUndoManager)anUndoManager 00718 { 00719 var defaultCenter = [CPNotificationCenter defaultCenter]; 00720 00721 if (_undoManager) 00722 { 00723 [defaultCenter removeObserver:self 00724 name:CPUndoManagerDidUndoChangeNotification 00725 object:_undoManager]; 00726 00727 [defaultCenter removeObserver:self 00728 name:CPUndoManagerDidRedoChangeNotification 00729 object:_undoManager]; 00730 00731 [defaultCenter removeObserver:self 00732 name:CPUndoManagerWillCloseUndoGroupNotification 00733 object:_undoManager]; 00734 } 00735 00736 _undoManager = anUndoManager; 00737 00738 if (_undoManager) 00739 { 00740 00741 [defaultCenter addObserver:self 00742 selector:@selector(_undoManagerDidUndoChange:) 00743 name:CPUndoManagerDidUndoChangeNotification 00744 object:_undoManager]; 00745 00746 [defaultCenter addObserver:self 00747 selector:@selector(_undoManagerDidRedoChange:) 00748 name:CPUndoManagerDidRedoChangeNotification 00749 object:_undoManager]; 00750 00751 [defaultCenter addObserver:self 00752 selector:@selector(_undoManagerWillCloseGroup:) 00753 name:CPUndoManagerWillCloseUndoGroupNotification 00754 object:_undoManager]; 00755 } 00756 } 00757 00764 - (CPUndoManager)undoManager 00765 { 00766 if (_hasUndoManager && !_undoManager) 00767 [self setUndoManager:[[CPUndoManager alloc] init]]; 00768 00769 return _undoManager; 00770 } 00771 00772 /* 00773 Implemented as a delegate of a CPWindow 00774 @ignore 00775 */ 00776 - (CPUndoManager)windowWillReturnUndoManager:(CPWindow)aWindow 00777 { 00778 return [self undoManager]; 00779 } 00780 00781 // Handling User Actions 00788 - (void)saveDocument:(id)aSender 00789 { 00790 [self saveDocumentWithDelegate:nil didSaveSelector:nil contextInfo:nil]; 00791 } 00792 00793 - (void)saveDocumentWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo 00794 { 00795 if (_fileURL) 00796 { 00797 [[CPNotificationCenter defaultCenter] 00798 postNotificationName:CPDocumentWillSaveNotification 00799 object:self]; 00800 00801 [self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; 00802 } 00803 else 00804 [self _saveDocumentAsWithDelegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; 00805 } 00806 00811 - (void)saveDocumentAs:(id)aSender 00812 { 00813 [self _saveDocumentAsWithDelegate:nil didSaveSelector:nil contextInfo:nil]; 00814 } 00815 00816 - (void)_saveDocumentAsWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo 00817 { 00818 var savePanel = [CPSavePanel savePanel], 00819 response = [savePanel runModal]; 00820 00821 if (!response) 00822 return; 00823 00824 var saveURL = [savePanel URL]; 00825 00826 [[CPNotificationCenter defaultCenter] 00827 postNotificationName:CPDocumentWillSaveNotification 00828 object:self]; 00829 00830 [self saveToURL:saveURL ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; 00831 } 00832 00833 /* 00834 @ignore 00835 */ 00836 - (void)_sendDocumentSavedNotification:(BOOL)didSave 00837 { 00838 if (didSave) 00839 [[CPNotificationCenter defaultCenter] 00840 postNotificationName:CPDocumentDidSaveNotification 00841 object:self]; 00842 else 00843 [[CPNotificationCenter defaultCenter] 00844 postNotificationName:CPDocumentDidFailToSaveNotification 00845 object:self]; 00846 } 00847 00848 @end 00849 00850 @implementation CPDocument (ClosingDocuments) 00851 00852 - (void)close 00853 { 00854 [_windowControllers makeObjectsPerformSelector:@selector(removeDocumentAndCloseIfNecessary:) withObject:self]; 00855 [[CPDocumentController sharedDocumentController] removeDocument:self]; 00856 } 00857 00858 - (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info 00859 { 00860 if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound)) 00861 [self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}]; 00862 00863 else if ([delegate respondsToSelector:selector]) 00864 objj_msgSend(delegate, selector, self, YES, info); 00865 } 00866 00867 - (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context 00868 { 00869 if (aDocument === self && shouldClose) 00870 [self close]; 00871 00872 objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context); 00873 } 00874 00875 - (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context 00876 { 00877 if (![self isDocumentEdited]) 00878 return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context); 00879 00880 _canCloseAlert = [[CPAlert alloc] init]; 00881 00882 [_canCloseAlert setDelegate:self]; 00883 [_canCloseAlert setAlertStyle:CPWarningAlertStyle]; 00884 [_canCloseAlert setTitle:@"Unsaved Document"]; 00885 [_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([self displayName] || [self fileName]) + "\"?"]; 00886 00887 [_canCloseAlert addButtonWithTitle:@"Save"]; 00888 [_canCloseAlert addButtonWithTitle:@"Cancel"]; 00889 [_canCloseAlert addButtonWithTitle:@"Don't Save"]; 00890 00891 _canCloseAlert._context = {delegate:aDelegate, selector:aSelector, context:context}; 00892 00893 [_canCloseAlert runModal]; 00894 } 00895 00896 - (void)alertDidEnd:(CPAlert)alert returnCode:(int)returnCode 00897 { 00898 if (alert !== _canCloseAlert) 00899 return; 00900 00901 var delegate = alert._context.delegate, 00902 selector = alert._context.selector, 00903 context = alert._context.context; 00904 00905 if (returnCode === 0) 00906 [self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context]; 00907 else 00908 objj_msgSend(delegate, selector, self, returnCode === 2, context); 00909 00910 _canCloseAlert = nil; 00911 } 00912 00913 @end 00914 00915 var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo) 00916 { 00917 return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo }; 00918 } 00919 00920 var _CPSaveSessionMake = function(anAbsoluteURL, aSaveOperation, aChangeCount, aDelegate, aDidSaveSelector, aContextInfo, aConnection) 00921 { 00922 return { absoluteURL:anAbsoluteURL, saveOperation:aSaveOperation, changeCount:aChangeCount, delegate:aDelegate, didSaveSelector:aDidSaveSelector, contextInfo:aContextInfo, connection:aConnection }; 00923 }