API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPDocument.j
Go to the documentation of this file.
1 /*
2  * CPDocument.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
26 
27 @global CPApp
28 
29 
30 /*
31  @global
32  @group CPSaveOperationType
33 */
34 CPSaveOperation = 0;
35 /*
36  @global
37  @group CPSaveOperationType
38 */
39 CPSaveAsOperation = 1;
40 /*
41  @global
42  @group CPSaveOperationType
43 */
44 CPSaveToOperation = 2;
45 /*
46  @global
47  @group CPSaveOperationType
48 */
49 CPAutosaveOperation = 3;
50 
51 /*
52  @global
53  @group CPDocumentChangeType
54 */
55 CPChangeDone = 0;
56 /*
57  @global
58  @group CPDocumentChangeType
59 */
60 CPChangeUndone = 1;
61 /*
62  @global
63  @group CPDocumentChangeType
64 */
65 CPChangeCleared = 2;
66 /*
67  @global
68  @group CPDocumentChangeType
69 */
70 CPChangeReadOtherContents = 3;
71 /*
72  @global
73  @group CPDocumentChangeType
74 */
75 CPChangeAutosaved = 4;
76 
77 CPDocumentWillSaveNotification = @"CPDocumentWillSaveNotification";
78 CPDocumentDidSaveNotification = @"CPDocumentDidSaveNotification";
79 CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
80 
81 var CPDocumentUntitledCount = 0;
82 
92 @implementation CPDocument : CPResponder
93 {
94  CPWindow _window; // For outlet purposes.
95  CPView _view; // For outlet purposes
96  CPDictionary _viewControllersForWindowControllers;
97 
98  CPURL _fileURL;
99  CPString _fileType;
100  CPArray _windowControllers;
101  unsigned _untitledDocumentIndex;
102 
103  BOOL _hasUndoManager;
104  CPUndoManager _undoManager;
105 
106  int _changeCount;
107 
108  CPURLConnection _readConnection;
109  CPURLRequest _writeRequest;
110 
111  CPAlert _canCloseAlert;
112 }
113 
118 - (id)init
119 {
120  self = [super init];
121 
122  if (self)
123  {
124  _windowControllers = [];
125  _viewControllersForWindowControllers = @{};
126 
127  _hasUndoManager = YES;
128  _changeCount = 0;
129 
130  [self setNextResponder:CPApp];
131  }
132 
133  return self;
134 }
135 
142 - (id)initWithType:(CPString)aType error:(/*{*/CPError/*}*/)anError
143 {
144  self = [self init];
145 
146  if (self)
147  [self setFileType:aType];
148 
149  return self;
150 }
151 
163 - (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
164 {
165  self = [self init];
166 
167  if (self)
168  {
169  [self setFileURL:anAbsoluteURL];
170  [self setFileType:aType];
171 
172  [self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
173  }
174 
175  return self;
176 }
177 
188 - (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
189 {
190  self = [self init];
191 
192  if (self)
193  {
194  [self setFileURL:anAbsoluteURL];
195  [self setFileType:aType];
196 
197  [self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
198  }
199 
200  return self;
201 }
202 
211 - (CPData)dataOfType:(CPString)aType error:(/*{*/CPError/*}*/)anError
212 {
213  [CPException raise:CPUnsupportedMethodException
214  reason:"dataOfType:error: must be overridden by the document subclass."];
215 }
216 
226 - (void)readFromData:(CPData)aData ofType:(CPString)aType error:(CPError)anError
227 {
228  [CPException raise:CPUnsupportedMethodException
229  reason:"readFromData:ofType: must be overridden by the document subclass."];
230 }
231 
232 - (void)viewControllerWillLoadCib:(CPViewController)aViewController
233 {
234 }
235 
236 - (void)viewControllerDidLoadCib:(CPViewController)aViewController
237 {
238 }
239 
240 // Creating and managing window controllers
244 - (void)makeWindowControllers
245 {
246  [self makeViewAndWindowControllers];
247 }
248 
249 - (void)makeViewAndWindowControllers
250 {
251  var viewCibName = [self viewCibName],
252  windowCibName = [self windowCibName],
253  viewController = nil,
254  windowController = nil;
255 
256  // Create our view controller if we have a cib for it.
257  if ([viewCibName length])
258  viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self];
259 
260  // From a cib if we have one.
261  if ([windowCibName length])
262  windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
263 
264  // If not you get a standard window capable of displaying multiple documents and view
265  else if (viewController)
266  {
267  var view = [viewController view],
268  viewFrame = [view frame];
269 
270  viewFrame.origin = CGPointMake(50, 50);
271 
272  var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
273 
274  windowController = [[CPWindowController alloc] initWithWindow:theWindow];
275  }
276 
277  if (windowController && viewController)
278  [windowController setSupportsMultipleDocuments:YES];
279 
280  if (windowController)
281  [self addWindowController:windowController];
282 
283  if (viewController)
284  [self addViewController:viewController forWindowController:windowController];
285 }
286 
290 - (CPArray)windowControllers
291 {
292  return _windowControllers;
293 }
294 
300 - (void)addWindowController:(CPWindowController)aWindowController
301 {
302  [_windowControllers addObject:aWindowController];
303 
304  if ([aWindowController document] !== self)
305  [aWindowController setDocument:self];
306 }
307 
313 - (void)removeWindowController:(CPWindowController)aWindowController
314 {
315  if (aWindowController)
316  [_windowControllers removeObject:aWindowController];
317 
318  if ([aWindowController document] === self)
319  [aWindowController setDocument:nil];
320 }
321 
322 - (CPView)view
323 {
324  return _view;
325 }
326 
327 - (CPArray)viewControllers
328 {
329  return [_viewControllersForWindowControllers allValues];
330 }
331 
332 - (void)addViewController:(CPViewController)aViewController forWindowController:(CPWindowController)aWindowController
333 {
334  // FIXME: exception if we don't own the window controller?
335  [_viewControllersForWindowControllers setObject:aViewController forKey:[aWindowController UID]];
336 
337  if ([aWindowController document] === self)
338  [aWindowController setViewController:aViewController];
339 }
340 
341 - (void)removeViewController:(CPViewController)aViewController
342 {
343  [_viewControllersForWindowControllers removeObject:aViewController];
344 }
345 
346 - (CPViewController)viewControllerForWindowController:(CPWindowController)aWindowController
347 {
348  return [_viewControllersForWindowControllers objectForKey:[aWindowController UID]];
349 }
350 
351 // Managing Document Windows
355 - (void)showWindows
356 {
357  [_windowControllers makeObjectsPerformSelector:@selector(setDocument:) withObject:self];
358  [_windowControllers makeObjectsPerformSelector:@selector(showWindow:) withObject:self];
359 }
360 
364 - (CPString)displayName
365 {
366  if (_fileURL)
367  return [_fileURL lastPathComponent];
368 
369  if (!_untitledDocumentIndex)
370  _untitledDocumentIndex = ++CPDocumentUntitledCount;
371 
372  if (_untitledDocumentIndex == 1)
373  return @"Untitled";
374 
375  return @"Untitled " + _untitledDocumentIndex;
376 }
377 
378 - (CPString)viewCibName
379 {
380  return nil;
381 }
382 
386 - (CPString)windowCibName
387 {
388  return nil;
389 }
390 
395 - (void)windowControllerDidLoadCib:(CPWindowController)aWindowController
396 {
397 }
398 
403 - (void)windowControllerWillLoadCib:(CPWindowController)aWindowController
404 {
405 }
406 
407 // Reading from and Writing to URLs
416 - (void)readFromURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
417 {
418  [_readConnection cancel];
419 
420  // FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
421  _readConnection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:anAbsoluteURL] delegate:self];
422 
423  _readConnection.session = _CPReadSessionMake(aType, aDelegate, aDidReadSelector, aContextInfo);
424 }
425 
429 - (CPURL)fileURL
430 {
431  return _fileURL;
432 }
433 
438 - (void)setFileURL:(CPURL)aFileURL
439 {
440  if (_fileURL === aFileURL)
441  return;
442 
443  _fileURL = aFileURL;
444 
445  [_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
446 }
447 
458 - (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo
459 {
460  var data = [self dataOfType:[self fileType] error:nil],
461  oldChangeCount = _changeCount;
462 
463  _writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL];
464 
465  // FIXME: THIS IS WRONG! We need a way to decide
466  if ([CPPlatform isBrowser])
467  [_writeRequest setHTTPMethod:@"POST"];
468  else
469  [_writeRequest setHTTPMethod:@"PUT"];
470 
471  [_writeRequest setHTTPBody:[data rawString]];
472 
473  [_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
474 
475  if (aSaveOperation === CPSaveOperation)
476  [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
477 
478  if (aSaveOperation !== CPSaveToOperation)
479  [self updateChangeCount:CPChangeCleared];
480 
481  // FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
482  var connection = [CPURLConnection connectionWithRequest:_writeRequest delegate:self];
483 
484  connection.session = _CPSaveSessionMake(anAbsoluteURL, aSaveOperation, oldChangeCount, aDelegate, aDidSaveSelector, aContextInfo, connection);
485 }
486 
487 /*
488  Implemented as a delegate method for CPURLConnection
489  @ignore
490 */
491 - (void)connection:(CPURLConnection)aConnection didReceiveResponse:(CPURLResponse)aResponse
492 {
493  // If we got this far and it wasn't an HTTP request, then everything is fine.
494  if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
495  return;
496 
497  var statusCode = [aResponse statusCode];
498 
499  // Nothing to do if everything is hunky dory.
500  if (statusCode === 200)
501  return;
502 
503  var session = aConnection.session;
504 
505  if (aConnection == _readConnection)
506  {
507  [aConnection cancel];
508 
509  alert("There was an error retrieving the document.");
510 
511  objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
512  }
513  else
514  {
515  // 409: Conflict, in Cappuccino, overwrite protection for documents.
516  if (statusCode == 409)
517  {
518  [aConnection cancel];
519 
520  if (confirm("There already exists a file with that name, would you like to overwrite it?"))
521  {
522  [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
523 
524  [aConnection start];
525  }
526  else
527  {
528  if (session.saveOperation != CPSaveToOperation)
529  {
530  _changeCount += session.changeCount;
531  [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
532  }
533 
534  _writeRequest = nil;
535 
536  objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
537  [self _sendDocumentSavedNotification:NO];
538  }
539  }
540  }
541 }
542 
543 /*
544  Implemented as a delegate method for CPURLConnection
545  @ignore
546 */
547 - (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
548 {
549  var session = aConnection.session;
550 
551  // READ
552  if (aConnection == _readConnection)
553  {
554  [self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil];
555 
556  objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
557  }
558  else
559  {
560  if (session.saveOperation != CPSaveToOperation)
561  [self setFileURL:session.absoluteURL];
562 
563  _writeRequest = nil;
564 
565  objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
566  [self _sendDocumentSavedNotification:YES];
567  }
568 }
569 
570 /*
571  Implemented as a delegate method for CPURLConnection
572  @ignore
573 */
574 - (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
575 {
576  var session = aConnection.session;
577 
578  if (_readConnection == aConnection)
579  objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
580 
581  else
582  {
583  if (session.saveOperation != CPSaveToOperation)
584  {
585  _changeCount += session.changeCount;
586  [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
587  }
588 
589  _writeRequest = nil;
590 
591  alert("There was an error saving the document.");
592 
593  objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
594  [self _sendDocumentSavedNotification:NO];
595  }
596 }
597 
598 /*
599  Implemented as a delegate method for CPURLConnection
600  @ignore
601 */
602 - (void)connectionDidFinishLoading:(CPURLConnection)aConnection
603 {
604  if (_readConnection == aConnection)
605  _readConnection = nil;
606 }
607 
608 // Managing Document Status
612 - (BOOL)isDocumentEdited
613 {
614  return _changeCount != 0;
615 }
616 
621 - (void)updateChangeCount:(CPDocumentChangeType)aChangeType
622 {
623  if (aChangeType == CPChangeDone)
624  ++_changeCount;
625  else if (aChangeType == CPChangeUndone)
626  --_changeCount;
627  else if (aChangeType == CPChangeCleared)
628  _changeCount = 0;
629  /*else if (aChangeType == CPCHangeReadOtherContents)
630 
631  else if (aChangeType == CPChangeAutosaved)*/
632 
633  [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
634 }
635 
636 // Managing File Types
641 - (void)setFileType:(CPString)aType
642 {
643  _fileType = aType;
644 }
645 
649 - (CPString)fileType
650 {
651  return _fileType;
652 }
653 
654 // Working with Undo Manager
659 - (BOOL)hasUndoManager
660 {
661  return _hasUndoManager;
662 }
663 
668 - (void)setHasUndoManager:(BOOL)aFlag
669 {
670  if (_hasUndoManager == aFlag)
671  return;
672 
673  _hasUndoManager = aFlag;
674 
675  if (!_hasUndoManager)
676  [self setUndoManager:nil];
677 }
678 
679 /* @ignore */
680 - (void)_undoManagerWillCloseGroup:(CPNotification)aNotification
681 {
682  var undoManager = [aNotification object];
683 
684  if ([undoManager isUndoing] || [undoManager isRedoing])
685  return;
686 
687  [self updateChangeCount:CPChangeDone];
688 }
689 
690 /* @ignore */
691 - (void)_undoManagerDidUndoChange:(CPNotification)aNotification
692 {
693  [self updateChangeCount:CPChangeUndone];
694 }
695 
696 /* @ignore */
697 - (void)_undoManagerDidRedoChange:(CPNotification)aNotification
698 {
699  [self updateChangeCount:CPChangeDone];
700 }
701 
702 /*
703  Sets the document's undo manager. This method will add the
704  undo manager as an observer to the notification center.
705  @param anUndoManager the new undo manager for the document
706 */
707 - (void)setUndoManager:(CPUndoManager)anUndoManager
708 {
709  var defaultCenter = [CPNotificationCenter defaultCenter];
710 
711  if (_undoManager)
712  {
713  [defaultCenter removeObserver:self
714  name:CPUndoManagerDidUndoChangeNotification
715  object:_undoManager];
716 
717  [defaultCenter removeObserver:self
718  name:CPUndoManagerDidRedoChangeNotification
719  object:_undoManager];
720 
721  [defaultCenter removeObserver:self
722  name:CPUndoManagerWillCloseUndoGroupNotification
723  object:_undoManager];
724  }
725 
726  _undoManager = anUndoManager;
727 
728  if (_undoManager)
729  {
730 
731  [defaultCenter addObserver:self
732  selector:@selector(_undoManagerDidUndoChange:)
733  name:CPUndoManagerDidUndoChangeNotification
734  object:_undoManager];
735 
736  [defaultCenter addObserver:self
737  selector:@selector(_undoManagerDidRedoChange:)
738  name:CPUndoManagerDidRedoChangeNotification
739  object:_undoManager];
740 
741  [defaultCenter addObserver:self
742  selector:@selector(_undoManagerWillCloseGroup:)
743  name:CPUndoManagerWillCloseUndoGroupNotification
744  object:_undoManager];
745  }
746 }
747 
754 - (CPUndoManager)undoManager
755 {
756  if (_hasUndoManager && !_undoManager)
757  [self setUndoManager:[[CPUndoManager alloc] init]];
758 
759  return _undoManager;
760 }
761 
762 /*
763  Implemented as a delegate of a CPWindow
764  @ignore
765 */
766 - (CPUndoManager)windowWillReturnUndoManager:(CPWindow)aWindow
767 {
768  return [self undoManager];
769 }
770 
771 // Handling User Actions
778 - (void)saveDocument:(id)aSender
779 {
780  [self saveDocumentWithDelegate:nil didSaveSelector:nil contextInfo:nil];
781 }
782 
783 - (void)saveDocumentWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo
784 {
785  if (_fileURL)
786  {
788  postNotificationName:CPDocumentWillSaveNotification
789  object:self];
790 
791  [self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
792  }
793  else
794  [self _saveDocumentAsWithDelegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
795 }
796 
801 - (void)saveDocumentAs:(id)aSender
802 {
803  [self _saveDocumentAsWithDelegate:nil didSaveSelector:nil contextInfo:nil];
804 }
805 
806 - (void)_saveDocumentAsWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo
807 {
808  var savePanel = [CPSavePanel savePanel],
809  response = [savePanel runModal];
810 
811  if (!response)
812  return;
813 
814  var saveURL = [savePanel URL];
815 
817  postNotificationName:CPDocumentWillSaveNotification
818  object:self];
819 
820  [self saveToURL:saveURL ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
821 }
822 
823 /*
824  @ignore
825 */
826 - (void)_sendDocumentSavedNotification:(BOOL)didSave
827 {
828  if (didSave)
830  postNotificationName:CPDocumentDidSaveNotification
831  object:self];
832  else
834  postNotificationName:CPDocumentDidFailToSaveNotification
835  object:self];
836 }
837 
838 @end
839 
840 @implementation CPDocument (ClosingDocuments)
841 
842 - (void)close
843 {
844  [_windowControllers makeObjectsPerformSelector:@selector(removeDocumentAndCloseIfNecessary:) withObject:self];
846 }
847 
848 - (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
849 {
850  if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound))
851  [self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
852 
853  else if ([delegate respondsToSelector:selector])
854  objj_msgSend(delegate, selector, self, YES, info);
855 }
856 
857 - (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
858 {
859  if (aDocument === self && shouldClose)
860  [self close];
861 
862  objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
863 }
864 
865 - (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
866 {
867  if (![self isDocumentEdited])
868  return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
869 
870  _canCloseAlert = [[CPAlert alloc] init];
871 
872  [_canCloseAlert setDelegate:self];
873  [_canCloseAlert setAlertStyle:CPWarningAlertStyle];
874  [_canCloseAlert setTitle:@"Unsaved Document"];
875  [_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([self displayName] || [self fileName]) + "\"?"];
876 
877  [_canCloseAlert addButtonWithTitle:@"Save"];
878  [_canCloseAlert addButtonWithTitle:@"Cancel"];
879  [_canCloseAlert addButtonWithTitle:@"Don't Save"];
880 
881  _canCloseAlert._context = {delegate:aDelegate, selector:aSelector, context:context};
882 
883  [_canCloseAlert runModal];
884 }
885 
886 - (void)alertDidEnd:(CPAlert)alert returnCode:(int)returnCode
887 {
888  if (alert !== _canCloseAlert)
889  return;
890 
891  var delegate = alert._context.delegate,
892  selector = alert._context.selector,
893  context = alert._context.context;
894 
895  if (returnCode === 0)
896  [self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context];
897  else
898  objj_msgSend(delegate, selector, self, returnCode === 2, context);
899 
900  _canCloseAlert = nil;
901 }
902 
903 @end
904 
905 var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo)
906 {
907  return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
908 };
909 
910 var _CPSaveSessionMake = function(anAbsoluteURL, aSaveOperation, aChangeCount, aDelegate, aDidSaveSelector, aContextInfo, aConnection)
911 {
912  return { absoluteURL:anAbsoluteURL, saveOperation:aSaveOperation, changeCount:aChangeCount, delegate:aDelegate, didSaveSelector:aDidSaveSelector, contextInfo:aContextInfo, connection:aConnection };
913 };