diff --git a/Core Data Editor/Core Data Editor.xcodeproj/project.pbxproj b/Core Data Editor/Core Data Editor.xcodeproj/project.pbxproj index 95c835e..33b10a4 100644 --- a/Core Data Editor/Core Data Editor.xcodeproj/project.pbxproj +++ b/Core Data Editor/Core Data Editor.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 4018D7842306011600A59D01 /* CDEUUIDAttributeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4018D7832306011600A59D01 /* CDEUUIDAttributeView.xib */; }; + 4018D7872306401100A59D01 /* CDEUUIDAttributeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4018D7862306401100A59D01 /* CDEUUIDAttributeViewController.m */; }; AB0181171997C805000FE094 /* NSDirectoryEnumerator+ProjectBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = AB0181161997C805000FE094 /* NSDirectoryEnumerator+ProjectBrowser.m */; }; AB06C0AF1854CB07002945CB /* CDEToOneRelationshipRequestDataCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = AB06C0AE1854CB07002945CB /* CDEToOneRelationshipRequestDataCoordinator.m */; }; AB0927511768C6EC00FC59FB /* CDEEntitiesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AB09274F1768C6EC00FC59FB /* CDEEntitiesViewController.m */; }; @@ -219,6 +221,9 @@ /* Begin PBXFileReference section */ 2E25BCB4198D645100BBA0C0 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 4018D7832306011600A59D01 /* CDEUUIDAttributeView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CDEUUIDAttributeView.xib; sourceTree = ""; }; + 4018D7852306401100A59D01 /* CDEUUIDAttributeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDEUUIDAttributeViewController.h; sourceTree = ""; }; + 4018D7862306401100A59D01 /* CDEUUIDAttributeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CDEUUIDAttributeViewController.m; sourceTree = ""; }; AB0181151997C805000FE094 /* NSDirectoryEnumerator+ProjectBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDirectoryEnumerator+ProjectBrowser.h"; sourceTree = ""; }; AB0181161997C805000FE094 /* NSDirectoryEnumerator+ProjectBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDirectoryEnumerator+ProjectBrowser.m"; sourceTree = ""; }; AB06C0AD1854CB07002945CB /* CDEToOneRelationshipRequestDataCoordinator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDEToOneRelationshipRequestDataCoordinator.h; sourceTree = ""; }; @@ -599,6 +604,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4018D7882306401D00A59D01 /* UUID */ = { + isa = PBXGroup; + children = ( + 4018D7852306401100A59D01 /* CDEUUIDAttributeViewController.h */, + 4018D7862306401100A59D01 /* CDEUUIDAttributeViewController.m */, + 4018D7832306011600A59D01 /* CDEUUIDAttributeView.xib */, + ); + name = UUID; + sourceTree = ""; + }; AB06C0AC1854CAD5002945CB /* To-One Relationship Request Coordinator */ = { isa = PBXGroup; children = ( @@ -1861,6 +1876,7 @@ ABEEA5BF178194B70096DE4C /* Date */, ABEEA5C1178194C60096DE4C /* Number */, ABEEA5C2178194CC0096DE4C /* Binary */, + 4018D7882306401D00A59D01 /* UUID */, ABC189F117809EDC00AF4F15 /* CDEAttributeViewControllerDelegate.h */, ABC189F217809EDC00AF4F15 /* CDEAttributeViewController.h */, ABC189F317809EDC00AF4F15 /* CDEAttributeViewController.m */, @@ -2057,6 +2073,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = ABBEA7CD1765CB730024A9D2; @@ -2103,6 +2120,7 @@ ABD5BCE317807B4F0050025B /* Relationship-ToMany.pdf in Resources */, ABD5BCE417807B4F0050025B /* Relationship-ToOne.pdf in Resources */, ABC18A1A17809EDC00AF4F15 /* CDEBooleanAttributeView.xib in Resources */, + 4018D7842306011600A59D01 /* CDEUUIDAttributeView.xib in Resources */, ABC18A1C17809EDC00AF4F15 /* CDEStringAttributeView.xib in Resources */, ABC18A1F17809EDC00AF4F15 /* CDEDatePickerViewController.xib in Resources */, ABC18A2117809EDC00AF4F15 /* CDEDateAttributeView.xib in Resources */, @@ -2180,6 +2198,7 @@ AB22AC7A17664480004890AC /* NSBundle+CDEModelFinder.m in Sources */, AB0927511768C6EC00FC59FB /* CDEEntitiesViewController.m in Sources */, AB0927571768C81E00FC59FB /* CDEEditorViewController.m in Sources */, + 4018D7872306401100A59D01 /* CDEUUIDAttributeViewController.m in Sources */, AB0927631768E65200FC59FB /* NSURL+CDEAdditions.m in Sources */, AB09276A1768F36100FC59FB /* CDEApplicationDelegate.m in Sources */, AB09279B1768F73000FC59FB /* CDEManagedObjectsViewController.m in Sources */, diff --git a/Core Data Editor/Core Data Editor/CDEAttributeViewController.m b/Core Data Editor/Core Data Editor/CDEAttributeViewController.m index 56b9f43..37f3e13 100644 --- a/Core Data Editor/Core Data Editor/CDEAttributeViewController.m +++ b/Core Data Editor/Core Data Editor/CDEAttributeViewController.m @@ -5,6 +5,7 @@ #import "CDEBooleanAttributeViewController.h" #import "CDEDateAttributeViewController.h" #import "CDEBinaryAttributeViewController.h" +#import "CDEUUIDAttributeViewController.h" const static NSString *CDEAttributeViewControllerResultingValueObservationContext = @"CDEAttributeViewControllerResultingValueObservationContext"; @@ -67,6 +68,9 @@ + (Class)attributeViewControllerClassForAttributeDescription:(NSAttributeDescrip if([CDEManagedObjectsTableViewAttributeHelper attributeTypeIsNumber:[attributeDescription attributeType]]) { return [CDENumberAttributeViewController class]; } + if([attributeDescription attributeType] == NSUUIDAttributeType) { + return [CDEUUIDAttributeViewController class]; + } return nil; } diff --git a/Core Data Editor/Core Data Editor/CDEBinaryAttributeViewController.m b/Core Data Editor/Core Data Editor/CDEBinaryAttributeViewController.m index 0ffd780..0b02806 100644 --- a/Core Data Editor/Core Data Editor/CDEBinaryAttributeViewController.m +++ b/Core Data Editor/Core Data Editor/CDEBinaryAttributeViewController.m @@ -55,7 +55,7 @@ - (IBAction)saveResultingValueAs:(id)sender { NSSavePanel *panel = [NSSavePanel savePanel]; panel.canCreateDirectories = YES; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { - if(result != NSFileHandlingPanelOKButton) { + if(result != NSModalResponseOK) { return; } if([[self resultingValue] isKindOfClass:[NSData class]] == NO) { @@ -75,7 +75,7 @@ - (IBAction)setResultingValueFromFile:(id)sender { NSOpenPanel *panel = [NSOpenPanel openPanel]; panel.canCreateDirectories = YES; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { - if(result != NSFileHandlingPanelOKButton) { + if(result != NSModalResponseOK) { return; } // if([[self resultingValue] isKindOfClass:[NSData class]] == NO) { diff --git a/Core Data Editor/Core Data Editor/CDEBinaryValueTableCellView.m b/Core Data Editor/Core Data Editor/CDEBinaryValueTableCellView.m index fb438a7..13304ba 100644 --- a/Core Data Editor/Core Data Editor/CDEBinaryValueTableCellView.m +++ b/Core Data Editor/Core Data Editor/CDEBinaryValueTableCellView.m @@ -40,7 +40,7 @@ - (IBAction)saveObjectValueAs:(id)sender { NSSavePanel *panel = [NSSavePanel savePanel]; panel.canCreateDirectories = YES; [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { - if(result != NSFileHandlingPanelOKButton) { + if(result != NSModalResponseOK) { return; } if([self.objectValue isKindOfClass:[NSData class]] == NO) { diff --git a/Core Data Editor/Core Data Editor/CDECSVImportWindowController.m b/Core Data Editor/Core Data Editor/CDECSVImportWindowController.m index 0c0187f..3c3627e 100644 --- a/Core Data Editor/Core Data Editor/CDECSVImportWindowController.m +++ b/Core Data Editor/Core Data Editor/CDECSVImportWindowController.m @@ -151,7 +151,7 @@ - (IBAction)showOpenCSVFilePanel:(id)sender { panel.allowedFileTypes = @[@"csv"]; panel.accessoryView = self.delimiterViewController.view; [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { - BOOL userChoseOKButton = (NSFileHandlingPanelOKButton == result); + BOOL userChoseOKButton = (NSModalResponseOK == result); if(userChoseOKButton == NO) { return; } diff --git a/Core Data Editor/Core Data Editor/CDEDropStoreViewController.m b/Core Data Editor/Core Data Editor/CDEDropStoreViewController.m index 610ee39..406ed16 100644 --- a/Core Data Editor/Core Data Editor/CDEDropStoreViewController.m +++ b/Core Data Editor/Core Data Editor/CDEDropStoreViewController.m @@ -74,7 +74,7 @@ - (id)init { - (IBAction)createNewStore:(id)sender { NSSavePanel *panel = [NSSavePanel savePanel]; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { - if(result != NSFileHandlingPanelOKButton) { + if(result != NSModalResponseOK) { return; } NSURL *URL = [panel URL]; diff --git a/Core Data Editor/Core Data Editor/CDEEditorViewController.m b/Core Data Editor/Core Data Editor/CDEEditorViewController.m index 34f6a81..7603f74 100644 --- a/Core Data Editor/Core Data Editor/CDEEditorViewController.m +++ b/Core Data Editor/Core Data Editor/CDEEditorViewController.m @@ -282,7 +282,7 @@ - (IBAction)showImportCSVFileWindow:(id)sender { } #pragma mark - CDEEntitiesViewControllerDelegate -- (void)entitiesViewController:(CDEEntitiesViewController *)entitiesViewController didSelectEntitiyDescription:(NSEntityDescription *)entityDescription { +- (void)entitiesViewController:(CDEEntitiesViewController *)entitiesViewController didSelectEntityDescription:(NSEntityDescription *)entityDescription { // Before assiging check for equality CDEAutosaveInformation *persistentInformation = [[CDEAutosaveInformation alloc] initWithDictionaryRepresentation:self.configuration.autosaveInformationByEntityName]; diff --git a/Core Data Editor/Core Data Editor/CDEEntitiesViewController.m b/Core Data Editor/Core Data Editor/CDEEntitiesViewController.m index 8bc877e..c9d21ba 100644 --- a/Core Data Editor/Core Data Editor/CDEEntitiesViewController.m +++ b/Core Data Editor/Core Data Editor/CDEEntitiesViewController.m @@ -168,7 +168,7 @@ - (void)outlineViewSelectionDidChange:(NSNotification *)notification { return; } - if([self.delegate respondsToSelector:@selector(entitiesViewController:didSelectEntitiyDescription:)] == NO) { + if([self.delegate respondsToSelector:@selector(entitiesViewController:didSelectEntityDescription:)] == NO) { return; } @@ -176,7 +176,7 @@ - (void)outlineViewSelectionDidChange:(NSNotification *)notification { if ([self.outlineView selectedRow] != -1) { selectedEntity = [self.outlineView itemAtRow:self.outlineView.selectedRow]; } - [self.delegate entitiesViewController:self didSelectEntitiyDescription:selectedEntity]; + [self.delegate entitiesViewController:self didSelectEntityDescription:selectedEntity]; } - (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item { diff --git a/Core Data Editor/Core Data Editor/CDEEntitiesViewControllerDelegate.h b/Core Data Editor/Core Data Editor/CDEEntitiesViewControllerDelegate.h index 803cb65..c426fbb 100644 --- a/Core Data Editor/Core Data Editor/CDEEntitiesViewControllerDelegate.h +++ b/Core Data Editor/Core Data Editor/CDEEntitiesViewControllerDelegate.h @@ -5,6 +5,6 @@ @protocol CDEEntitiesViewControllerDelegate @required -- (void)entitiesViewController:(CDEEntitiesViewController *)entitiesViewController didSelectEntitiyDescription:(NSEntityDescription *)entityDescription; +- (void)entitiesViewController:(CDEEntitiesViewController *)entitiesViewController didSelectEntityDescription:(NSEntityDescription *)entityDescription; @end diff --git a/Core Data Editor/Core Data Editor/CDEEntityRequestDataCoordinator.m b/Core Data Editor/Core Data Editor/CDEEntityRequestDataCoordinator.m index 0c44fed..f7a60d8 100644 --- a/Core Data Editor/Core Data Editor/CDEEntityRequestDataCoordinator.m +++ b/Core Data Editor/Core Data Editor/CDEEntityRequestDataCoordinator.m @@ -78,20 +78,31 @@ - (void)prepare { } } } - - NSError *fetchError = nil; - NSString *entityName = self.request.entityDescription.name; - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName]; - NSArray *objects = [self.request.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError]; - if(objects == nil) { - NSLog(@"error: %@", fetchError); - return; - } - self.filteringArray = [FilteringArray new]; - [self.filteringArray addObjectsFromArray:objects]; - [self.tableView reloadData]; + + [self executeFetchRequest]; + [self.tableView reloadData]; } +-(void)executeFetchRequest { + if(self.filteringArray == nil) { + self.filteringArray = [FilteringArray new]; + } + else { + [self.filteringArray removeAllObjects]; + } + NSError *fetchError = nil; + NSString *entityName = self.request.entityDescription.name; + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName]; + fetchRequest.sortDescriptors = self.request.sortDescriptors; + NSArray *objects = [self.request.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError]; + if(objects == nil) { + NSLog(@"error: %@", fetchError); + return; + } + [self.filteringArray addObjectsFromArray:objects]; +} + + - (void)invalidate { } @@ -101,13 +112,16 @@ - (NSManagedObject *)createAndAddManagedObject { return object; } -- (void)removeSelectedManagedObjects { +- (void)removeSelectedManagedObjects:(BOOL)andDeleteThem; // AH: passing YES removes AND deletes the objects. Passing NO only removes them. + { NSIndexSet *indexes = [self indexesOfSelectedManagedObjects]; NSArray* objects = [self.filteringArray objectsAtIndexes:indexes]; [self.filteringArray removeObjectsAtIndexes:indexes]; - for(NSManagedObject *object in objects) { - [self.request.managedObjectContext deleteObject:object]; - } + if(andDeleteThem) { + for(NSManagedObject *object in objects) { + [self.request.managedObjectContext deleteObject:object]; + } + } [self.tableView reloadData]; } @@ -136,6 +150,10 @@ - (BOOL)canPerformDelete { return (self.tableView.selectedRow != -1); } +- (BOOL)canPerformNullify { + return NO; // can't nullify an object. You can only delete it! +} + #pragma mark - Autosave - (void)updateAutosaveInformation:(CDEAutosaveInformation *)autosaveInformation { // do nothing by default diff --git a/Core Data Editor/Core Data Editor/CDEManagedObjectView.m b/Core Data Editor/Core Data Editor/CDEManagedObjectView.m index 52e3a2c..6044c11 100644 --- a/Core Data Editor/Core Data Editor/CDEManagedObjectView.m +++ b/Core Data Editor/Core Data Editor/CDEManagedObjectView.m @@ -10,6 +10,7 @@ @interface CDEManagedObjectView() #pragma mark Properties +@property (retain) NSTextField *objectIDTextField; // AH: to display the objectID of the to-one relationship. @property (retain) NSMutableArray *attributeViewControllers; @property (retain) NSDictionary *managedObjectBindingInfo; @property (retain) CDEGenerateThumbnailsController *generateThumbnailsController; @@ -118,6 +119,9 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N - (void)refresh { [[self subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; + + self.objectIDTextField = [NSTextField labelWithString:self.managedObject ? [NSString stringWithFormat:@"objectID: %@",[self.managedObject.objectID stringRepresentationForDisplay_cde]] : @"nil objectID"]; + [self addSubview:self.objectIDTextField]; for(CDEAttributeViewController *attributeViewController in self.attributeViewControllers) { attributeViewController.delegate = nil; @@ -177,6 +181,12 @@ - (void)layoutAttributeViews { CGFloat height = 10.0f; CGFloat nameViewWidthScaleFactor = 0.35; CGFloat valueViewWidthScaleFactor = 1.0 - nameViewWidthScaleFactor; + + [self.objectIDTextField sizeToFit]; + [self.objectIDTextField setFrameOrigin:NSMakePoint(nameViewWidthScaleFactor * NSWidth([self bounds]), height)]; + height += NSHeight(self.objectIDTextField.frame); + + for(CDEAttributeViewController *attributeViewController in self.attributeViewControllers) { NSRect newValueFrame = NSMakeRect(nameViewWidthScaleFactor * NSWidth([self bounds]), height, valueViewWidthScaleFactor * NSWidth([self bounds]) - 10.0, NSHeight([[attributeViewController view] frame])); if([attributeViewController attributeNameView] != nil) { diff --git a/Core Data Editor/Core Data Editor/CDEManagedObjectView.xib b/Core Data Editor/Core Data Editor/CDEManagedObjectView.xib index 1f5f10e..dd53878 100644 --- a/Core Data Editor/Core Data Editor/CDEManagedObjectView.xib +++ b/Core Data Editor/Core Data Editor/CDEManagedObjectView.xib @@ -1,7 +1,8 @@ - + - + + @@ -10,13 +11,14 @@ + - + @@ -35,35 +37,35 @@ - + - + - + - + - + - + - + - - + - + - - - + + @@ -65,10 +79,10 @@ CA - + - + @@ -97,7 +111,7 @@ CA - + @@ -121,11 +135,11 @@ CA - + @@ -154,5 +169,6 @@ CA + diff --git a/Core Data Editor/Core Data Editor/CDEOrderedRelationshipRequestDataCoordinator.m b/Core Data Editor/Core Data Editor/CDEOrderedRelationshipRequestDataCoordinator.m index 9bd134a..a9ac0b2 100644 --- a/Core Data Editor/Core Data Editor/CDEOrderedRelationshipRequestDataCoordinator.m +++ b/Core Data Editor/Core Data Editor/CDEOrderedRelationshipRequestDataCoordinator.m @@ -4,20 +4,7 @@ #import "CDERequestDataCoordinator_Subclass.h" #import "CDEOrderIndexTableCellView.h" #import "NSTableCellView+JKNibLoading.h" - -@interface NSTableColumn (OrderedRelationshipRequestDataCoordinator) - -- (BOOL)isOrderIndexColumn_cde; - -@end - -@implementation NSTableColumn (OrderedRelationshipRequestDataCoordinator) - -- (BOOL)isOrderIndexColumn_cde { - return [self.identifier isEqualToString:@"CDE_orderIndexColumn"]; -} - -@end +#import "NSTableColumn+CDERequestDataCoordinator.h" @interface CDEOrderedRelationshipRequestDataCoordinator () @@ -176,5 +163,10 @@ - (BOOL)canPerformDelete { return ([relatedObjects count] > 0); } +- (BOOL)canPerformNullify { + return [self canPerformDelete]; // same rule as canPerformDelete +} + + @end diff --git a/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.h b/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.h index f0d0830..1662fb5 100644 --- a/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.h +++ b/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.h @@ -22,6 +22,8 @@ #pragma mark - For Subclassers // The default implementation returns columns for supported attributes, relationships and a column for the objectID @property (nonatomic, copy, readonly) NSArray *tableColumns; +@property (nonatomic, strong, readonly) NSTableColumn *sortingColumn; +@property (nonatomic, assign, readonly) BOOL sortingAscending; - (NSInteger)numberOfObjects; @@ -40,9 +42,10 @@ - (void)removeManagedObjectAtIndex:(NSUInteger)index; - (NSIndexSet *)indexesOfSelectedManagedObjects; - (NSArray *)selectedManagedObjects; -- (void)removeSelectedManagedObjects; +- (void)removeSelectedManagedObjects:(BOOL)andDeleteThem; // AH: passing YES removes AND deletes the objects. Passing NO only removes them. - (NSView *)viewForTableColumn:(NSTableColumn *)tableColumn atIndex:(NSInteger)atIndex; +- (void)sortByTableColumn:(NSTableColumn *)tableColumn ascending:(BOOL)ascending; - (IBAction)takeBoolValueFromSender:(id)sender; - (void)controlTextDidEndEditing:(NSNotification *)notification; @@ -62,6 +65,7 @@ #pragma mark - For Subclassers / Used to disable/enable the buttons - (BOOL)canPerformAdd; - (BOOL)canPerformDelete; +- (BOOL)canPerformNullify; #pragma mark - Autosave - (CDEEntityAutosaveInformation *)entityAutosaveInformation; diff --git a/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.m b/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.m index e173cfd..46e6b69 100644 --- a/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.m +++ b/Core Data Editor/Core Data Editor/CDERequestDataCoordinator.m @@ -28,6 +28,8 @@ @interface CDERequestDataCoordinator () + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %{value1}@ + + + + + + + + diff --git a/Core Data Editor/Core Data Editor/CDEUUIDAttributeViewController.h b/Core Data Editor/Core Data Editor/CDEUUIDAttributeViewController.h new file mode 100644 index 0000000..64993f2 --- /dev/null +++ b/Core Data Editor/Core Data Editor/CDEUUIDAttributeViewController.h @@ -0,0 +1,17 @@ +// +// CDEUUIDAttributeViewController.h +// Core Data Editor +// +// Created by Steve Madsen on 8/15/19. +// Copyright © 2019 Christian Kienle. All rights reserved. +// + +#import "CDEAttributeViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface CDEUUIDAttributeViewController : CDEAttributeViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Core Data Editor/Core Data Editor/CDEUUIDAttributeViewController.m b/Core Data Editor/Core Data Editor/CDEUUIDAttributeViewController.m new file mode 100644 index 0000000..0e54a37 --- /dev/null +++ b/Core Data Editor/Core Data Editor/CDEUUIDAttributeViewController.m @@ -0,0 +1,35 @@ +// +// CDEUUIDAttributeViewController.m +// Core Data Editor +// +// Created by Steve Madsen on 8/15/19. +// Copyright © 2019 Christian Kienle. All rights reserved. +// + +#import "CDEUUIDAttributeViewController.h" + +@implementation CDEUUIDAttributeViewController + +#pragma mark CMKViewController +- (NSString *)nibName { + return @"CDEUUIDAttributeView"; +} + +- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor { + if ([[NSUUID alloc] initWithUUIDString:[fieldEditor string]] != nil) { + return YES; + } + + NSAlert *alert = [[NSAlert alloc] init]; + alert.informativeText = [NSString stringWithFormat:@"Input '%@' is not a UUID", [fieldEditor string]]; + alert.messageText = @"Validation Error"; + [alert runModal]; + + return NO; +} + +- (void) setResultingValue:(id)newValue { + [super setResultingValue:[[NSUUID alloc] initWithUUIDString:newValue]]; +} + +@end diff --git a/Core Data Editor/Core Data Editor/CDEUnorderedRelationshipRequestDataCoordinator.m b/Core Data Editor/Core Data Editor/CDEUnorderedRelationshipRequestDataCoordinator.m index 7df82fd..99870e0 100644 --- a/Core Data Editor/Core Data Editor/CDEUnorderedRelationshipRequestDataCoordinator.m +++ b/Core Data Editor/Core Data Editor/CDEUnorderedRelationshipRequestDataCoordinator.m @@ -38,9 +38,6 @@ - (void)prepare { self.arrayController.entityName = entity.name; self.arrayController.managedObjectContext = self.request.managedObjectContext; - NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entity.name]; - fetchRequest.entity = entity; - // Person -- pets -->> Pet // Person <-- owner -- Pet // $person (pets) @@ -51,6 +48,19 @@ - (void)prepare { predicate = [NSPredicate predicateWithFormat:@"ANY %K == %@", self.request.relationshipDescription.inverseRelationship.name, self.request.managedObject]; } self.arrayController.filterPredicate = predicate; + + [self executeFetchRequest]; + + [self.tableView bind:NSContentBinding toObject:self.arrayController withKeyPath:@"arrangedObjects" options:nil]; + [self.tableView bind:NSSortDescriptorsBinding toObject:self.arrayController withKeyPath:@"sortDescriptors" options:nil]; +} + +-(void)executeFetchRequest +{ + NSEntityDescription *entity = self.request.relationshipDescription.destinationEntity; + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entity.name]; + fetchRequest.entity = entity; + fetchRequest.sortDescriptors = self.request.sortDescriptors; NSError *error = nil; BOOL fetched = [self.arrayController fetchWithRequest:fetchRequest merge:NO error:&error]; @@ -58,9 +68,6 @@ - (void)prepare { NSLog(@"Error: %@", error); return; } - - [self.tableView bind:NSContentBinding toObject:self.arrayController withKeyPath:@"arrangedObjects" options:nil]; - [self.tableView bind:NSSortDescriptorsBinding toObject:self.arrayController withKeyPath:@"sortDescriptors" options:nil]; } - (void)invalidate { @@ -97,6 +104,10 @@ - (BOOL)canPerformDelete { return [[self.arrayController selectedObjects] count] > 0; } +- (BOOL)canPerformNullify { + return [self canPerformDelete]; // same rule as canPerformDelete +} + - (void)didChangeFilterPredicate { self.arrayController.filterPredicate = self.filterPredicate; [self.tableView reloadData]; diff --git a/Core Data Editor/Core Data Editor/FilteringArray.h b/Core Data Editor/Core Data Editor/FilteringArray.h index b090442..36663df 100644 --- a/Core Data Editor/Core Data Editor/FilteringArray.h +++ b/Core Data Editor/Core Data Editor/FilteringArray.h @@ -1,6 +1,7 @@ #import @interface FilteringArray: NSObject +- (void)removeAllObjects; - (void)setFilterPredicate:(NSPredicate *)predicate; - (void)addObject:(ObjectType)anObject; - (void)removeObjectAtIndex:(NSUInteger)index; diff --git a/Core Data Editor/Core Data Editor/FilteringArray.m b/Core Data Editor/Core Data Editor/FilteringArray.m index 1a5d5c7..4c57d62 100644 --- a/Core Data Editor/Core Data Editor/FilteringArray.m +++ b/Core Data Editor/Core Data Editor/FilteringArray.m @@ -23,7 +23,7 @@ - (void)setFilterPredicate:(NSPredicate *)predicate { } - (void)applyFilter { - self._filteredObjects = self._allObjects; + [self._filteredObjects setArray:self._allObjects]; if(self._predicate == nil) { return; @@ -46,6 +46,11 @@ - (id)objectAtIndex:(NSUInteger)index { } return [self._filteredObjects objectAtIndex:index]; } + +- (void)removeAllObjects { + [self._allObjects removeAllObjects]; + [self applyFilter]; +} - (void)addObjectsFromArray:(NSArray *)otherArray { [self._allObjects addObjectsFromArray:otherArray]; [self applyFilter]; diff --git a/Core Data Editor/Core Data Editor/NSAttributeDescription+CDEAdditions.m b/Core Data Editor/Core Data Editor/NSAttributeDescription+CDEAdditions.m index 6aa5434..32d09d6 100644 --- a/Core Data Editor/Core Data Editor/NSAttributeDescription+CDEAdditions.m +++ b/Core Data Editor/Core Data Editor/NSAttributeDescription+CDEAdditions.m @@ -8,7 +8,8 @@ #pragma mark - Working with Attribute Types BOOL CDEIsStringAttributeType(NSAttributeType type) { - return (type == NSStringAttributeType); + return (type == NSStringAttributeType || + type == NSUUIDAttributeType); } BOOL CDEIsFloatingPointAttributeType(NSAttributeType type) { @@ -40,6 +41,7 @@ + (Class)tableCellViewClassForAttributeType_cde:(NSAttributeType)type { result = [CDEFloatingPointValueTableCellView class]; break; case NSStringAttributeType: + case NSUUIDAttributeType: result = [CDEStringValueTableCellView class]; break; case NSBooleanAttributeType: diff --git a/Core Data Editor/Core Data Editor/PreferencesIntegrationVC.m b/Core Data Editor/Core Data Editor/PreferencesIntegrationVC.m index 0cc7ae1..47b4dbd 100644 --- a/Core Data Editor/Core Data Editor/PreferencesIntegrationVC.m +++ b/Core Data Editor/Core Data Editor/PreferencesIntegrationVC.m @@ -50,7 +50,7 @@ - (IBAction)showSimulatorDirectoryPicker:(id)sender { [panel setCanChooseDirectories:YES]; [panel setCanChooseFiles:NO]; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { - if(result == NSFileHandlingPanelOKButton) { + if(result == NSModalResponseOK) { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; defaults.simulatorDirectory_cde = panel.URL; self.simulatorDirectoryPopUpButton.URL = defaults.simulatorDirectory_cde; @@ -63,7 +63,7 @@ - (IBAction)showBuildDirectoryPicker:(id)sender { [panel setCanChooseDirectories:YES]; [panel setCanChooseFiles:NO]; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { - if(result == NSFileHandlingPanelOKButton) { + if(result == NSModalResponseOK) { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; defaults.buildProductsDirectory_cde = panel.URL; self.buildDirectoryPopUpButton.URL = defaults.buildProductsDirectory_cde; diff --git a/README.md b/README.md index cbc2fde..009d810 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,19 @@ -# Build Status -| Branch | Status | -| ------------- |:-------------:| -| Master | [![Build Status](https://travis-ci.org/ChristianKienle/Core-Data-Editor.svg?branch=master)](https://travis-ci.org/ChristianKienle/Core-Data-Editor) | -| Develop | [![Build Status](https://travis-ci.org/ChristianKienle/Core-Data-Editor.svg?branch=develop)](https://travis-ci.org/ChristianKienle/Core-Data-Editor) | +# Goals of this fork +- Enhance usability and add some features: + - Make (most of) the columns sortable. NSUUID columns are not sortable at this moment. + - Allows to *remove* an object from a relationship (to many or to one) instead of *deleting* it. There is a new "clear" button to do that. + - Support NSUUID attribute types (from sjmadsen) + - Made ManagedObject picker Popover window much bigger by default. Also resizable + - Displays the objectID of to-one relationships in the relationship details view + - Fix annoyances such as filtering that did not reset the previous content when cleared + +- Maintain the tool in the long term. + + +# Major issues that are *by design* + +The biggest problem of this tool, since its beginning is that your NSManagedObject subclasses are not loaded in Core Data Editor. Any validation code that is not in the ManagedObjectModel, any triggered setter you may have implemented on save, on insert or whatever won't be called and may produce an invalid record in term of business logic. So beware: either don't use NSManagedObject subclasses (and thus limit your power with Core Data) or be cautious when you trigger changes in your NSManagedObject subclasses. + # Core Data Editor