diff --git a/ChangeLog b/ChangeLog index 6fddf923b..fda98746b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2020-01-23 Fred Kiefer + + * Source/GSXib5KeyedUnarchiver.m: Remove NSWindowTemplate5. + * Source/GSXibLoader.m: Clean up code. + * Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h, + * Source/GSXibKeyedUnarchiver.m: Provide method to load both sorts + of XIB files. + * Source/NSArrayController.m: Add horrible hack to get KVB on + array controller to work. + 2020-01-22 Fred Kiefer * Source/GSXib5KeyedUnarchiver.m, diff --git a/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h b/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h index 47b98cac4..6b89d265b 100644 --- a/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h +++ b/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h @@ -43,6 +43,9 @@ NSMutableDictionary *decoded; } ++ (BOOL) checkXib5: (NSData *)data; ++ (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data; + - (void) _initCommon; - (id) decodeObjectForXib: (GSXibElement*)element forClassName: (NSString*)classname diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 798e395af..f003111e0 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -113,50 +113,6 @@ static NSString *ApplicationClass = nil; @end -@interface NSWindowTemplate5 : NSWindowTemplate -{ - BOOL _visibleAtLaunch; -} -@end - -@implementation NSWindowTemplate5 - -- (id) initWithCoder: (NSCoder *)coder -{ - self = [super initWithCoder: coder]; - if (self) - { - _visibleAtLaunch = YES; - - if ([coder containsValueForKey: @"visibleAtLaunch"]) - { - _visibleAtLaunch = [coder decodeBoolForKey: @"visibleAtLaunch"]; - } - } - - return self; -} - -- (id) nibInstantiate -{ - if (_realObject == nil) - { - // Instantiate the real object... - [super nibInstantiate]; - - // >= XIB 5 - startup visible windows... - if (_visibleAtLaunch) - { - // bring visible windows to front... - [(NSWindow *)_realObject orderFront: self]; - } - } - - return _realObject; -} - -@end - @interface IBActionConnection5 : IBActionConnection { NSString *trigger; @@ -360,7 +316,7 @@ static NSArray *XmlBoolDefaultYes = nil; @"IBOutletConnection5", @"outlet", @"IBActionConnection5", @"action", @"NSNibBindingConnector", @"binding", - @"NSWindowTemplate5", @"window", + @"NSWindowTemplate", @"window", @"NSView", @"tableCellView", @"IBUserDefinedRuntimeAttribute5", @"userDefinedRuntimeAttribute", nil]; @@ -631,7 +587,7 @@ static NSArray *XmlBoolDefaultYes = nil; if (parentId == nil) { - NSLog(@"Missing parent Id for connection on parent @%", parent); + NSLog(@"Missing parent Id for connection on parent %@", parent); // Fake an id for parent parentId = [[NSUUID UUID] UUIDString]; [parent setAttribute: parentId forKey: @"id"]; @@ -700,9 +656,14 @@ static NSArray *XmlBoolDefaultYes = nil; return AUTORELEASE(objectRecord); } -- (void) addRuntimeAttributesForElement: (GSXibElement*)element forID: (NSString*)idString +- (NSString*) getRefIDFor: (GSXibElement*)element postFix: (NSString*)postfix +{ + id orderedObject = [_orderedObjectsDict objectForKey: [element attributeForKey: @"id"]]; + return [NSString stringWithFormat: @"%@.%@", [orderedObject attributeForKey: @"id"], postfix]; +} + +- (void) addRuntimeAttributesForElement: (GSXibElement*)element forID: (NSString*)refID { - NSString *refID = [NSString stringWithFormat: @"%@.IBAttributePlaceholdersKey", idString]; GSXibElement *objectRecord = (GSXibElement*)[_flattenedProperties elementForKey: refID]; // Mimic the old IBAttributePlaceholders instance... @@ -2946,8 +2907,24 @@ didStartElement: (NSString*)elementName { // Create the flattened property data for the runtime attributes in the OLD XIB format... id runtimeAttributes = [element elementForKey: @"userDefinedRuntimeAttributes"]; - id orderedObject = [_orderedObjectsDict objectForKey: [element attributeForKey: @"id"]]; - [self addRuntimeAttributesForElement: runtimeAttributes forID: [orderedObject attributeForKey: @"id"]]; + NSString *refID = [self getRefIDFor: element postFix: @"%IBAttributePlaceholdersKey"]; + + [self addRuntimeAttributesForElement: runtimeAttributes forID: refID]; + } + else if ([[element attributeForKey: @"key"] isEqualToString: @"window"]) + { + NSString *refID = [self getRefIDFor: element postFix: @"NSWindowTemplate.visibleAtLaunch"]; + id runtimeAttribute = [[GSXibElement alloc] initWithType: @"string" + andAttributes: nil]; + id visibleAtLaunch = [element attributeForKey: @"visibleAtLaunch"]; + + if (visibleAtLaunch == nil) + { + visibleAtLaunch = @"YES"; + } + [runtimeAttribute setValue: visibleAtLaunch]; + + [_flattenedProperties setElement: runtimeAttribute forKey: refID]; } return object; diff --git a/Source/GSXibKeyedUnarchiver.m b/Source/GSXibKeyedUnarchiver.m index 6c142c96a..240ac49ba 100644 --- a/Source/GSXibKeyedUnarchiver.m +++ b/Source/GSXibKeyedUnarchiver.m @@ -34,12 +34,55 @@ Boston, MA 02110-1301, USA. */ +#import #import "GNUstepGUI/GSXibKeyedUnarchiver.h" #import "GNUstepGUI/GSXibElement.h" #import "GNUstepGUI/GSNibLoading.h" +#import "GSXib5KeyedUnarchiver.h" @implementation GSXibKeyedUnarchiver ++ (BOOL) checkXib5: (NSData *)data +{ +#if GNUSTEP_BASE_HAVE_LIBXML + // Ensure we have a XIB 5 version...first see if we can parse the XML... + NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data + options: 0 + error: NULL]; + if (document == nil) + { + return NO; + } + else + { + // Test to see if this is an Xcode 5 XIB... + NSArray *documentNodes = [document nodesForXPath: @"/document" error: NULL]; + + // Need at LEAST ONE document node...we should find something a bit more + // specific to check here... + return [documentNodes count] != 0; + } +#else + // We now default to checking XIB 5 versions + return YES; +#endif +} + ++ (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data +{ + NSKeyedUnarchiver *unarchiver = nil; + + if ([self checkXib5: data]) + { + unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; + } + else + { + unarchiver = [[GSXibKeyedUnarchiver alloc] initForReadingWithData: data]; + } + return AUTORELEASE(unarchiver); +} + - (NSData *) _preProcessXib: (NSData *)data { NSData *result = data; diff --git a/Source/GSXibLoader.m b/Source/GSXibLoader.m index 2ea39c37d..6d712fbae 100644 --- a/Source/GSXibLoader.m +++ b/Source/GSXibLoader.m @@ -35,7 +35,6 @@ #import #import #import -#import #import "AppKit/NSApplication.h" #import "AppKit/NSMenu.h" @@ -44,7 +43,6 @@ #import "GNUstepGUI/GSNibLoading.h" #import "GNUstepGUI/GSXibLoading.h" #import "GNUstepGUI/GSXibKeyedUnarchiver.h" -#import "GSXib5KeyedUnarchiver.h" @interface NSApplication (NibCompatibility) - (void) _setMainMenu: (NSMenu*)aMenu; @@ -85,14 +83,11 @@ - (void) awake: (NSArray *)rootObjects withContext: (NSDictionary *)context { - NSEnumerator *en; - id obj; NSMutableArray *topLevelObjects = [context objectForKey: NSNibTopLevelObjects]; id owner = [context objectForKey: NSNibOwner]; - id first = nil; - id app = nil; - NSCustomObject *object; - NSString *className; + NSEnumerator *en; + id obj; + NSUInteger index = 0; if ([rootObjects count] == 0) { @@ -100,42 +95,21 @@ return; } - // Get the file's owner and NSApplication object references... - object = (NSCustomObject*)[rootObjects objectAtIndex: 1]; - if ([[object className] isEqualToString: @"FirstResponder"]) - { - first = [object realObject]; - } - else - { - NSLog(@"%s:first responder missing\n", __PRETTY_FUNCTION__); - } - - object = (NSCustomObject*)[rootObjects objectAtIndex: 2]; - className = [object className]; - if ([className isEqualToString: @"NSApplication"] || - [NSClassFromString(className) isSubclassOfClass:[NSApplication class]]) - { - app = [object realObject]; - } - else - { - NSLog(@"%s:NSApplication missing '%@'\n", __PRETTY_FUNCTION__, className); - } - // Use the owner as first root object [(NSCustomObject*)[rootObjects objectAtIndex: 0] setRealObject: owner]; en = [rootObjects objectEnumerator]; while ((obj = [en nextObject]) != nil) { + index++; + if ([obj respondsToSelector: @selector(nibInstantiate)]) { obj = [obj nibInstantiate]; } // IGNORE file's owner, first responder and NSApplication instances... - if ((obj != nil) && (obj != owner) && (obj != first) && (obj != app)) + if ((obj != nil) && (index > 3)) { [topLevelObjects addObject: obj]; // All top level objects must be released by the caller to avoid @@ -166,51 +140,17 @@ } } -- (BOOL) checkXib5: (NSData *)data -{ -#if GNUSTEP_BASE_HAVE_LIBXML - // Ensure we have a XIB 5 version...first see if we can parse the XML... - NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data - options: 0 - error: NULL]; - if (document == nil) - { - return NO; - } - else - { - // Test to see if this is an Xcode 5 XIB... - NSArray *documentNodes = [document nodesForXPath: @"/document" error: NULL]; - - // Need at LEAST ONE document node...we should find something a bit more - // specific to check here... - return [documentNodes count] != 0; - } -#else - // We now default to checking XIB 5 versions - return YES; -#endif -} - - (BOOL) loadModelData: (NSData *)data externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone; { BOOL loaded = NO; - NSKeyedUnarchiver *unarchiver = nil; NS_DURING { if (data != nil) { - if ([self checkXib5: data]) - { - unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; - } - else - { - unarchiver = [[GSXibKeyedUnarchiver alloc] initForReadingWithData: data]; - } + NSKeyedUnarchiver *unarchiver = [GSXibKeyedUnarchiver unarchiverForReadingWithData: data]; if (unarchiver != nil) { @@ -226,7 +166,6 @@ inContainer: objects withContext: context]; loaded = YES; - RELEASE(unarchiver); } else { @@ -241,7 +180,6 @@ NS_HANDLER { NSLog(@"Exception occurred while loading model: %@",[localException reason]); - // TEST_RELEASE(unarchiver); } NS_ENDHANDLER diff --git a/Source/NSArrayController.m b/Source/NSArrayController.m index 291fedb39..feec51aca 100644 --- a/Source/NSArrayController.m +++ b/Source/NSArrayController.m @@ -2,7 +2,7 @@ Controller class for arrays - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 2020 Free Software Foundation, Inc. Author: Fred Kiefer Date: June 2006 @@ -88,7 +88,11 @@ if ([result isKindOfClass: [NSArray class]]) { - return AUTORELEASE([[GSObservableArray alloc] + // FIXME: Using the correct memory management here + // Leads to an issue inside of KVO. For now we leak the + // object until this gets fixed. + //return AUTORELEASE([[GSObservableArray alloc] + return ([[GSObservableArray alloc] initWithArray: result]); } @@ -152,7 +156,6 @@ { if ((self = [super initWithContent: content]) != nil) { - [self rearrangeObjects]; [self setSelectsInsertedObjects: YES]; } @@ -187,8 +190,7 @@ } else { - // FIXME: Should check whether _arranged_objects is mutable - ASSIGN(_arranged_objects, [_arranged_objects arrayByAddingObject: obj]); + DESTROY(_arranged_objects); } if ([self selectsInsertedObjects]) { @@ -207,8 +209,7 @@ } else { - // FIXME: Should check whether _arranged_objects is mutable - ASSIGN(_arranged_objects, [_arranged_objects arrayByAddingObjectsFromArray: obj]); + DESTROY(_arranged_objects); } if ([self selectsInsertedObjects]) { @@ -228,8 +229,7 @@ } else { - // FIXME - //[_arranged_objects removeObject: obj]; + DESTROY(_arranged_objects); } [self didChangeValueForKey: NSContentBinding]; } @@ -245,8 +245,7 @@ } else { - // FIXME - //[_arranged_objects removeObjectsInArray: obj]; + DESTROY(_arranged_objects); } [self didChangeValueForKey: NSContentBinding]; } @@ -385,7 +384,7 @@ - (NSArray*) selectedObjects { // We make the selection work on the arranged objects - return [_arranged_objects objectsAtIndexes: _selection_indexes]; + return [[self arrangedObjects] objectsAtIndexes: _selection_indexes]; } - (NSUInteger) selectionIndex @@ -472,14 +471,19 @@ - (id) arrangedObjects { + if (_arranged_objects == nil) + { + [self rearrangeObjects]; + } return _arranged_objects; } - (void) rearrangeObjects { [self willChangeValueForKey: @"arrangedObjects"]; + DESTROY(_arranged_objects); _arranged_objects = [[GSObservableArray alloc] - initWithArray: [self arrangeObjects: _content]]; + initWithArray: [self arrangeObjects: _content]]; [self didChangeValueForKey: @"arrangedObjects"]; }