API 0.9.5
AppKit/CPDocument.j
Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Defines