<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -39,6 +39,11 @@ CPApp = nil;
 
 CPApplicationWillFinishLaunchingNotification    = @&quot;CPApplicationWillFinishLaunchingNotification&quot;;
 CPApplicationDidFinishLaunchingNotification     = @&quot;CPApplicationDidFinishLaunchingNotification&quot;;
+CPApplicationWillTerminateNotification          = @&quot;CPApplicationWillTerminateNotification&quot;;
+
+CPTerminateNow      = YES;
+CPTerminateCancel   = NO;
+CPTerminateLater    = -1; // not currently supported
 
 CPRunStoppedResponse    = -1000;
 CPRunAbortedResponse    = -1001;
@@ -295,7 +300,30 @@ CPRunContinuesResponse  = -1002;
 
 - (void)terminate:(id)aSender
 {
-    [CPPlatform terminateApplication];
+    [[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
+                                                              didCloseAllSelector:@selector(_documentController:didCloseAll:context:)
+                                                                      contextInfo:nil];
+}
+
+- (void)_documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
+{
+    // callback method for terminate:
+    if (didCloseAll)
+    {
+        if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
+            [self replyToApplicationShouldTerminate:[_delegate applicationShouldTerminate:self]];
+        else
+            [self replyToApplicationShouldTerminate:YES];
+    }
+}
+
+- (void)replyToApplicationShouldTerminate:(BOOL)terminate
+{
+    if (terminate == CPTerminateNow)
+    {
+        [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillTerminateNotification object:self];
+        [CPPlatform terminateApplication];
+    }
 }
 
 - (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps</diff>
      <filename>AppKit/CPApplication.j</filename>
    </modified>
    <modified>
      <diff>@@ -94,7 +94,8 @@ var CPControlBlackColor     = [CPColor blackColor];
     id                  _target;
     SEL                 _action;
     int                 _sendActionOn;
-    
+    BOOL                _sendsActionOnEndEditing @accessors(property=sendsActionOnEndEditing);
+
     // Mouse Tracking Support
     BOOL                _continuousTracking;
     BOOL                _trackingWasWithinFrame;</diff>
      <filename>AppKit/CPControl.j</filename>
    </modified>
    <modified>
      <diff>@@ -282,12 +282,13 @@ var CPDocumentUntitledCount = 0;
             var view = [viewController view],
                 theWindow = [[CPWindow alloc] initWithContentRect:[view frame] styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
 
-            [theWindow setSupportsMultipleDocuments:YES];
-
             windowController = [[CPWindowController alloc] initWithWindow:theWindow];
         }
     }
 
+    if (windowController &amp;&amp; viewController)
+        [windowController setSupportsMultipleDocuments:YES];
+
     if (windowController)
         [self addWindowController:windowController];
 
@@ -838,7 +839,7 @@ var CPDocumentUntitledCount = 0;
 
 - (void)close
 {
-    [_windowControllers makeObjectsPerformSelector:@selector(close)];
+    [_windowControllers makeObjectsPerformSelector:@selector(removeDocumentAndCloseIfNecessary:) withObject:self];
     [[CPDocumentController sharedDocumentController] removeDocument:self];
 }
 
@@ -846,6 +847,7 @@ var CPDocumentUntitledCount = 0;
 {
     if ([controller shouldCloseDocument] || ([_windowControllers count] &lt; 2 &amp;&amp; [_windowControllers indexOfObject:controller] !== CPNotFound))
         [self canCloseDocumentWithDelegate:delegate shouldCloseSelector:selector contextInfo:info];
+
     else if ([delegate respondsToSelector:selector])
         objj_msgSend(delegate, selector, self, YES, info);
 }</diff>
      <filename>AppKit/CPDocument.j</filename>
    </modified>
    <modified>
      <diff>@@ -323,3 +323,38 @@ var CPSharedDocumentController = nil;
 }
 
 @end
+
+@implementation CPDocumentController (Closing)
+
+- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info 
+{
+    var context = {
+        delegate: aDelegate,
+        selector: didCloseSelector,
+        context: info
+    };
+
+    [self _closeDocumentsStartingWith:nil shouldClose:YES context:context];
+}
+
+// Recursive callback method. Start it by passing in a document of nil.
+- (void)_closeDocumentsStartingWith:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
+{
+    if (shouldClose)
+    {
+        [aDocument close];
+
+        if ([[self documents] count] &gt; 0)
+        {
+            [[[self documents] lastObject] canCloseDocumentWithDelegate:self
+                                                    shouldCloseSelector:@selector(_closeDocumentsStartingWith:shouldClose:context:)
+                                                            contextInfo:context];
+            return;
+        }
+    }
+
+    if ([context.delegate respondsToSelector:context.selector])
+        objj_msgSend(context.delegate, context.selector, self, [[self documents] count] === 0, context.context);
+}
+
+@end</diff>
      <filename>AppKit/CPDocumentController.j</filename>
    </modified>
    <modified>
      <diff>@@ -269,8 +269,8 @@ CPTextFieldStatePlaceholder = CPThemeState(&quot;placeholder&quot;);
 
                 if (aDOMEvent &amp;&amp; aDOMEvent.keyCode == CPReturnKeyCode)
                 {
-                    [owner sendAction:[owner action] to:[owner target]];    
-                    [[owner window] makeFirstResponder:nil];
+                    [owner sendAction:[owner action] to:[owner target]];
+                    [owner selectText:nil];
                 }
                 else if (aDOMEvent &amp;&amp; aDOMEvent.keyCode == CPTabKeyCode)
                 {
@@ -666,6 +666,9 @@ CPTextFieldStatePlaceholder = CPThemeState(&quot;placeholder&quot;);
     //post CPControlTextDidEndEditingNotification
     [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
 
+    if ([self sendsActionOnEndEditing])
+        [self sendAction:[self action] to:[self target]];    
+
     return YES;
 }
 </diff>
      <filename>AppKit/CPTextField.j</filename>
    </modified>
    <modified>
      <diff>@@ -186,7 +186,9 @@ var CPViewControllerViewKey     = @&quot;CPViewControllerViewKey&quot;,
         _view = [aCoder decodeObjectForKey:CPViewControllerViewKey];
         _title = [aCoder decodeObjectForKey:CPViewControllerTitleKey];
         _cibName = [aCoder decodeObjectForKey:CPViewControllerCibNameKey];
-        _cibBundle = [aCoder decodeObjectForKey:CPViewControllerBundleKey] || [CPBundle mainBundle];
+
+        var bundlePath = [aCoder decodeObjectForKey:CPViewControllerBundleKey];
+        _cibBundle = bundlePath ? [CPBundle bundleWithPath:bundlePath] : [CPBundle mainBundle];
 
         _cibExternalNameTable = [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
     }
@@ -205,7 +207,7 @@ var CPViewControllerViewKey     = @&quot;CPViewControllerViewKey&quot;,
     [aCoder encodeObject:_view forKey:CPViewControllerViewKey];
     [aCoder encodeObject:_title forKey:CPViewControllerTitleKey];
     [aCoder encodeObject:_cibName forKey:CPViewControllerCibNameKey];
-    [aCoder encodeObject:_cibBundle forKey:CPViewControllerBundleKey];
+    [aCoder encodeObject:[_cibBundle bundlePath] forKey:CPViewControllerBundleKey];
 }
 
 @end</diff>
      <filename>AppKit/CPViewController.j</filename>
    </modified>
    <modified>
      <diff>@@ -258,7 +258,6 @@ var CPWindowSaveImage       = nil,
     BOOL                                _isMovableByWindowBackground;
     unsigned                            _shadowStyle;
 
-    BOOL                                _supportsMultipleDocuments;
     BOOL                                _isDocumentEdited;
     BOOL                                _isDocumentSaving;
 
@@ -460,19 +459,6 @@ CPTexturedBackgroundWindowMask
     return _CPBorderlessBridgeWindowView;
 }
 
-- (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
-{
-    shouldSupportMultipleDocuments = !!shouldSupportMultipleDocuments;
-
-    // FIXME: throw exception if window controller already has multiple documents and shouldSupportMultipleDocuments === NO
-    _supportsMultipleDocuments = shouldSupportMultipleDocuments;
-}
-
-- (BOOL)supportsMultipleDocuments
-{
-    return _supportsMultipleDocuments;
-}
-
 - (void)awakeFromCib
 {
     if (_initialFirstResponder)
@@ -1650,13 +1636,15 @@ CPTexturedBackgroundWindowMask
     else if ([self respondsToSelector:@selector(windowShouldClose:)] &amp;&amp; ![self windowShouldClose:self])
         return;
 
-    var document = [_windowController document];
-    if (document)
+    var documents = [_windowController documents];
+    if ([documents count])
     {
-        [document shouldCloseWindowController:_windowController 
-                                     delegate:self 
-                          shouldCloseSelector:@selector(_document:shouldClose:contextInfo:)
-                                  contextInfo:nil];
+        var index = [documents indexOfObject:[_windowController document]];
+
+        [documents[index] shouldCloseWindowController:_windowController 
+                                             delegate:self 
+                                  shouldCloseSelector:@selector(_document:shouldClose:contextInfo:)
+                                          contextInfo:index];
     }
     else
         [self close];
@@ -1665,7 +1653,27 @@ CPTexturedBackgroundWindowMask
 - (void)_document:(CPDocument)document shouldClose:(BOOL)shouldClose contextInfo:(Object)context
 {
     if (shouldClose)
-        [self close];
+    {
+        var windowController = [self windowController],
+            documents = [windowController documents];
+
+        [documents[context] close];
+
+        var count = [documents count];
+        if (count)
+        {
+            var index = context % count;
+
+            [windowController setDocument:documents[index]];
+
+            [documents[index] shouldCloseWindowController:_windowController 
+                                                 delegate:self 
+                                      shouldCloseSelector:@selector(_document:shouldClose:contextInfo:)
+                                              contextInfo:index];
+        }
+        else
+            [self close];
+    }
 }
 
 /*!</diff>
      <filename>AppKit/CPWindow/CPWindow.j</filename>
    </modified>
    <modified>
      <diff>@@ -43,8 +43,10 @@
 {
     CPWindow            _window;
 
+    CPArray             _documents;
     CPDocument          _document;
     BOOL                _shouldCloseDocument;
+    BOOL                _supportsMultipleDocuments;
 
     id                  _cibOwner;
     CPString            _windowCibName;
@@ -74,6 +76,8 @@
         [self setShouldCloseDocument:NO];
 
         [self setNextResponder:CPApp];
+
+        _documents = [];
     }
 
     return self;
@@ -220,6 +224,9 @@
 
     if (_document)
     {
+        if (![self supportsMultipleDocuments])
+            [self removeDocument:_document];
+        
         [defaultCenter removeObserver:self
                                  name:CPDocumentWillSaveNotification
                                object:_document];
@@ -237,6 +244,8 @@
 
     if (_document)
     {
+        [self addDocument:_document];
+
         [defaultCenter addObserver:self
                           selector:@selector(_documentWillSave:)
                               name:CPDocumentWillSaveNotification
@@ -263,6 +272,48 @@
     [self synchronizeWindowTitleWithDocumentName];
 }
 
+- (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
+{
+    _supportsMultipleDocuments = shouldSupportMultipleDocuments;
+}
+
+- (BOOL)supportsMultipleDocuments
+{
+    return _supportsMultipleDocuments;
+}
+
+- (void)addDocument:(CPDocument)aDocument
+{
+    if (aDocument &amp;&amp; ![_documents containsObject:aDocument])
+        [_documents addObject:aDocument];
+}
+
+- (void)removeDocument:(CPDocument)aDocument
+{
+    var index = [_documents indexOfObjectIdenticalTo:aDocument];
+
+    if (index === CPNotFound)
+        return;
+
+    [_documents removeObjectAtIndex:index];
+
+    if (_document === aDocument &amp;&amp; [_documents count])
+        [self setDocument:[_documents objectAtIndex:MIN(index, [_documents count] - 1)]];
+}
+
+- (void)removeDocumentAndCloseIfNecessary:(CPDocument)aDocument
+{
+    [self removeDocument:aDocument];
+
+    if (![_documents count])
+        [self close];
+}
+
+- (CPArray)documents
+{
+    return _documents;
+}
+
 - (void)setViewController:(CPViewController)aViewController
 {
     var containerView = [self viewControllerContainerView] || [[self window] contentView],</diff>
      <filename>AppKit/CPWindowController.j</filename>
    </modified>
    <modified>
      <diff>@@ -3,8 +3,9 @@ var FILE = require(&quot;file&quot;),
     objj = require(&quot;./objj&quot;),
     objj_preprocess = objj.objj_preprocess,
     IS_FILE = objj.IS_FILE,
-    GET_CODE = objj.GET_CODE,
     IS_LOCAL = objj.IS_LOCAL,
+    GET_CODE = objj.GET_CODE,
+    GET_FILE = objj.GET_FILE,
     MARKER_IMPORT_STD = objj.MARKER_IMPORT_STD,
     MARKER_IMPORT_LOCAL = objj.MARKER_IMPORT_LOCAL,
     MARKER_CODE = objj.MARKER_CODE,</diff>
      <filename>Objective-J/Tools/objj/lib-js/objj/objjc.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,6 +3,9 @@
 
 var File = require(&quot;file&quot;);
 
+var FILE = File;
+var OBJJ = require(&quot;objj/objj&quot;);
+var SYSTEM = require(&quot;system&quot;);
 
 function gen(/*va_args*/)
 {
@@ -58,12 +61,12 @@ function gen(/*va_args*/)
         config = {};
     if (File.isFile(configFile))
         config = JSON.parse(File.read(configFile));
-    print(config.FrameworksPath)
+    
     var destinationProject = new java.io.File(destination),
         configuration = noConfig ? [Configuration defaultConfiguration] : [Configuration userConfiguration];
 
     if (justFrameworks)
-        createFrameworksInFile(destinationProject, shouldSymbolicallyLink, force);
+        createFrameworksInFile(String(destinationProject.getCanonicalPath()), shouldSymbolicallyLink, force);
 
     else if (!destinationProject.exists())
     {
@@ -106,65 +109,60 @@ function gen(/*va_args*/)
         print(&quot;Directory already exists&quot;);
 }
 
-
-function createFrameworksInFile(/*String*/ aFile, /*Boolean*/ shouldSymbolicallyLink, /*Boolean*/ force)
+function createFrameworksInFile(/*String*/ aFile, /*Boolean*/ symlink, /*Boolean*/ force)
 {
-    if (!File.isDirectory(aFile))
-        throw new Error(&quot;Can't create Frameworks. Directory does not exist: &quot; + aFile);
-        
-    var destinationFrameworks = new java.io.File(aFile+ &quot;/Frameworks&quot;),
-        destinationDebugFrameworks = new java.io.File(aFile + &quot;/Frameworks/Debug&quot;);
-        
-    if (destinationFrameworks.exists()) {
-        if (force) {
-            print(&quot;Updating existing Frameworks directory.&quot;);
-            exec([&quot;rm&quot;, &quot;-rf&quot;, destinationFrameworks], true);
-        }
-        else {
-            print(&quot;Frameworks directory already exists. Use --force to overwrite.&quot;);
-            return;
-        }
-    } else {    
-        print(&quot;Creating Frameworks directory in &quot;+destinationFrameworks+&quot;.&quot;);
-    }
-
-    if (!shouldSymbolicallyLink)
-    {
-        var sourceFrameworks = new java.io.File(OBJJ_HOME + &quot;/lib/Frameworks&quot;);
+    var destination = FILE.path(aFile);
     
-        exec([&quot;cp&quot;, &quot;-R&quot;, sourceFrameworks.getCanonicalPath(), destinationFrameworks], true);
-
-        return;
-    }
-    
-    var BUILD = system.env[&quot;CAPP_BUILD&quot;] || system.env[&quot;STEAM_BUILD&quot;];
+    if (!destination.isDirectory())
+        throw new Error(&quot;Can't create Frameworks. Directory does not exist: &quot; + destination);
     
-    if (!BUILD)
+    if (symlink &amp;&amp; !(SYSTEM.env[&quot;CAPP_BUILD&quot;] || SYSTEM.env[&quot;STEAM_BUILD&quot;]))
         throw &quot;CAPP_BUILD or STEAM_BUILD must be defined&quot;;
+
+    var installedFrameworks = FILE.path(FILE.join(OBJJ.OBJJ_HOME, &quot;lib&quot;, &quot;Frameworks&quot;)),
+        builtFrameworks = FILE.path(SYSTEM.env[&quot;CAPP_BUILD&quot;] || SYSTEM.env[&quot;STEAM_BUILD&quot;]);
     
-    // Release Frameworks
-    new java.io.File(destinationFrameworks).mkdir();
+    var sourceFrameworks = symlink ? builtFrameworks.join(&quot;Release&quot;) : installedFrameworks,
+        sourceDebugFrameworks = symlink ? builtFrameworks.join(&quot;Debug&quot;) : installedFrameworks.join(&quot;Debug&quot;);
+        
+    var destinationFrameworks = destination.join(&quot;Frameworks&quot;),
+        destinationDebugFrameworks = destination.join(&quot;Frameworks&quot;, &quot;Debug&quot;);
     
-    exec([&quot;ln&quot;, &quot;-s&quot;,   new java.io.File(BUILD + &quot;/Release/Objective-J&quot;).getCanonicalPath(),
-                        new java.io.File(aFile + &quot;/Frameworks/Objective-J&quot;).getCanonicalPath()], true);
-
-    exec([&quot;ln&quot;, &quot;-s&quot;,   new java.io.File(BUILD + &quot;/Release/Foundation&quot;).getCanonicalPath(),
-                        new java.io.File(aFile + &quot;/Frameworks/Foundation&quot;).getCanonicalPath()], true);
-
-    exec([&quot;ln&quot;, &quot;-s&quot;,   new java.io.File(BUILD + &quot;/Release/AppKit&quot;).getCanonicalPath(),
-                        new java.io.File(aFile + &quot;/Frameworks/AppKit&quot;).getCanonicalPath()], true);
-
-    // Debug Frameworks
-    new java.io.File(destinationDebugFrameworks).mkdir();
+    print(&quot;Creating Frameworks directory in &quot; + destinationFrameworks + &quot;.&quot;);
     
-    exec([&quot;ln&quot;, &quot;-s&quot;,   new java.io.File(BUILD + &quot;/Debug/Objective-J&quot;).getCanonicalPath(),
-                        new java.io.File(aFile + &quot;/Frameworks/Debug/Objective-J&quot;).getCanonicalPath()], true);
-
-    exec([&quot;ln&quot;, &quot;-s&quot;,   new java.io.File(BUILD + &quot;/Debug/Foundation&quot;).getCanonicalPath(),
-                        new java.io.File(aFile + &quot;/Frameworks/Debug/Foundation&quot;).getCanonicalPath()], true);
+    //destinationFrameworks.mkdirs(); // redundant
+    destinationDebugFrameworks.mkdirs();
+    
+    [&quot;Objective-J&quot;, &quot;Foundation&quot;, &quot;AppKit&quot;].forEach(function(framework) {
+        installFramework(
+            sourceFrameworks.join(framework),
+            destinationFrameworks.join(framework),
+            force, symlink);
+        installFramework(
+            sourceDebugFrameworks.join(framework),
+            destinationDebugFrameworks.join(framework),
+            force, symlink);
+    });
+}
 
-    exec([&quot;ln&quot;, &quot;-s&quot;,   new java.io.File(BUILD + &quot;/Debug/AppKit&quot;).getCanonicalPath(),
-                        new java.io.File(aFile + &quot;/Frameworks/Debug/AppKit&quot;).getCanonicalPath()], true);
+function installFramework(source, dest, force, symlink) {
+    if (dest.exists()) {
+        if (force) {
+            dest.rmtree();
+        } else {
+            print(&quot;Warning: &quot; + dest + &quot; already exists. Use --force to overwrite.&quot;);
+            return;
+        }
+    }
+    if (source.exists()) {
+        print((symlink ? &quot;Symlinking &quot; : &quot;Copying &quot;) + source + &quot; to &quot; + dest);
+        if (symlink)
+            FILE.symlink(source, dest);
+        else
+            FILE.copyTree(source, dest);
+    }
+    else
+        print(&quot;Warning: &quot;+source+&quot; doesn't exist.&quot;);
 }
 
 function toIdentifier(/*String*/ aString)</diff>
      <filename>Tools/capp/Generate.j</filename>
    </modified>
    <modified>
      <diff>@@ -33,7 +33,7 @@
     {
         _title = [aCoder decodeObjectForKey:@&quot;NSTitle&quot;];
         _cibName = [aCoder decodeObjectForKey:@&quot;NSNibName&quot;];
-        _cibBundle = [aCoder decodeObjectForKey:@&quot;NSNibBundleIdentifier&quot;];
+        _cibBundle = [CPBundle bundleWithPath:[aCoder decodeObjectForKey:@&quot;NSNibBundleIdentifier&quot;]];
     }
 
     return self;</diff>
      <filename>Tools/nib2cib/NSViewController.j</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>d09c46b9531bd89434b824763d077bb10fc80dea</id>
    </parent>
    <parent>
      <id>95b9ea336bb4d3766e382e37930b076c06548291</id>
    </parent>
  </parents>
  <author>
    <name>Justin Mecham</name>
    <email>justin@thehive.com</email>
  </author>
  <url>http://github.com/jsmecham/cappuccino/commit/487e541c07f88ea6f46cfd1f87caed5e8940bcc7</url>
  <id>487e541c07f88ea6f46cfd1f87caed5e8940bcc7</id>
  <committed-date>2009-10-28T06:19:14-07:00</committed-date>
  <authored-date>2009-10-28T06:19:14-07:00</authored-date>
  <message>Merge branch 'master' of git://github.com/280north/cappuccino

Conflicts:
	AppKit/CPViewController.j
	Tools/nib2cib/NSViewController.j</message>
  <tree>46d1d5e7b5088c3b279bb627dd22de24a2029535</tree>
  <committer>
    <name>Justin Mecham</name>
    <email>justin@thehive.com</email>
  </committer>
</commit>
