/* * CPCib.j * AppKit * * Created by Francisco Tolmasky. * Copyright 2008, 280 North, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @import @import @import @import "_CPCibClassSwapper.j" @import "_CPCibCustomObject.j" @import "_CPCibCustomResource.j" @import "_CPCibCustomView.j" @import "_CPCibKeyedUnarchiver.j" @import "_CPCibObjectData.j" @import "_CPCibProxyObject.j" @import "_CPCibWindowTemplate.j" @import "_CPLocalizableString.j" CPCibOwner = @"CPCibOwner"; CPCibTopLevelObjects = @"CPCibTopLevelObjects"; CPCibReplacementClasses = @"CPCibReplacementClasses"; CPCibExternalObjects = @"CPCibExternalObjects"; var CPCibObjectDataKey = @"CPCibObjectDataKey"; /*! @ingroup appkit */ @implementation CPCib : CPObject { BOOL _awakenCustomResources @accessors(property=_awakenCustomResources); CPBundle _bundle; CPData _data; CPString _cibName; id _loadDelegate; } - (id)_initWithData:(CPData)data bundle:(CPBundle)aBundle cibName:(CPString)aCibName { self = [super init]; _data = data; _cibName = aCibName; _bundle = aBundle; _awakenCustomResources = YES; return self; } - (id)initWithContentsOfURL:(CPURL)aURL { self = [super init]; if (self) { _cibName = [aURL lastPathComponent]; _data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil]; if (!_data) return nil; _awakenCustomResources = YES; } return self; } - (id)initWithContentsOfURL:(CPURL)aURL loadDelegate:(id)aLoadDelegate { self = [super init]; if (self) { _cibName = [aURL lastPathComponent]; [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:aURL] delegate:self]; _awakenCustomResources = YES; _loadDelegate = aLoadDelegate; } return self; } - (id)initWithCibNamed:(CPString)aName bundle:(CPBundle)aBundle { if (![aName hasSuffix:@".cib"]) aName = [aName stringByAppendingString:@".cib"]; // If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later. var bundle = aBundle || [CPBundle mainBundle]; self = [self initWithContentsOfURL:[bundle _cibPathForResource:aName]]; if (self) _bundle = aBundle; return self; } - (id)initWithCibNamed:(CPString)aName bundle:(CPBundle)aBundle loadDelegate:(id)aLoadDelegate { if (![aName hasSuffix:@".cib"]) aName = [aName stringByAppendingString:@".cib"]; // If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later. var bundle = aBundle || [CPBundle mainBundle]; self = [self initWithContentsOfURL:[bundle _cibPathForResource:aName] loadDelegate:aLoadDelegate]; if (self) _bundle = aBundle; return self; } - (BOOL)instantiateCibWithExternalNameTable:(CPDictionary)anExternalNameTable { var bundle = _bundle, owner = [anExternalNameTable objectForKey:CPCibOwner]; if (!bundle && owner) bundle = [CPBundle bundleForClass:[owner class]]; var unarchiver = [[_CPCibKeyedUnarchiver alloc] initForReadingWithData:_data bundle:bundle awakenCustomResources:_awakenCustomResources cibName:_cibName], replacementClasses = [anExternalNameTable objectForKey:CPCibReplacementClasses]; if (replacementClasses) { var key = nil, keyEnumerator = [replacementClasses keyEnumerator]; while ((key = [keyEnumerator nextObject]) !== nil) [unarchiver setClass:[replacementClasses objectForKey:key] forClassName:key]; } [unarchiver setExternalObjectsForProxyIdentifiers:[anExternalNameTable objectForKey:CPCibExternalObjects]]; var objectData = [unarchiver decodeObjectForKey:CPCibObjectDataKey]; if (!objectData || ![objectData isKindOfClass:[_CPCibObjectData class]]) return NO; var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects]; [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; // Display Visible Windows. [objectData displayVisibleWindows]; return YES; } - (BOOL)instantiateCibWithOwner:(id)anOwner topLevelObjects:(CPArray)topLevelObjects { // anOwner can be nil, and we can't store nil in a dictionary. If we leave it out, // anyone who asks for CPCibOwner will get nil back. var nameTable = @{ CPCibTopLevelObjects: topLevelObjects }; if (anOwner) [nameTable setObject:anOwner forKey:CPCibOwner]; return [self instantiateCibWithExternalNameTable:nameTable]; } @end @implementation CPCib (CPURLConnectionDelegate) - (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data { // FIXME: Why aren't we getting connection:didFailWithError: if (!data) return [self connection:aConnection didFailWithError:nil]; _data = [CPData dataWithRawString:data]; } - (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError { if ([_loadDelegate respondsToSelector:@selector(cibDidFailToLoad:)]) [_loadDelegate cibDidFailToLoad:self]; _loadDelegate = nil; } - (void)connectionDidFinishLoading:(CPURLConnection)aConnection { if ([_loadDelegate respondsToSelector:@selector(cibDidFinishLoading:)]) [_loadDelegate cibDidFinishLoading:self]; _loadDelegate = nil; } @end var CPCibDataFileKey = @"CPCibDataFileKey", CPCibBundleIdentifierKey = @"CPCibBundleIdentifierKey"; @implementation CPCib (CPCoding) - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; var base64 = [aCoder decodeObjectForKey:CPCibDataFileKey]; _data = [CPData dataWithBase64:base64]; return self; } - (void)encodeWithCoder:(CPCoder)aCoder { [aCoder encodeObject:[_data base64] forKey:CPCibDataFileKey]; } @end