123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- //The MIT License (MIT)
- //
- //Copyright (c) 2014 Rafał Augustyniak
- //
- //Permission is hereby granted, free of charge, to any person obtaining a copy of
- //this software and associated documentation files (the "Software"), to deal in
- //the Software without restriction, including without limitation the rights to
- //use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- //the Software, and to permit persons to whom the Software is furnished to do so,
- //subject to the following conditions:
- //
- //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- //FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- //COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- //IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- //CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- #import "RATreeNodeCollectionController.h"
- #import "RATreeNodeController.h"
- #import "RATreeNode.h"
- #import "RATreeNodeItem+Private.h"
- #import "RABatchChanges.h"
- @interface RATreeNodeCollectionController () <RATreeNodeItemDataSource>
- @property (nonatomic, strong) RATreeNodeController *rootController;
- @end
- @implementation RATreeNodeCollectionController
- - (NSInteger)numberOfVisibleRowsForItems
- {
- return self.rootController.numberOfVisibleDescendants;
- }
- - (RATreeNode *)treeNodeForIndex:(NSInteger)index
- {
- return [self.rootController controllerForIndex:index].treeNode;
- }
- - (NSInteger)indexForItem:(id)item
- {
- return [self.rootController indexForItem:item];
- }
- - (NSInteger)lastVisibleDescendantIndexForItem:(id)item
- {
- return [self.rootController lastVisibleDescendatIndexForItem:item];
- }
- - (id)parentForItem:(id)item
- {
- RATreeNodeController *controller = [self.rootController controllerForItem:item];
- return controller.parentController.treeNode.item;
- }
- - (NSInteger)levelForItem:(id)item
- {
- return [self.rootController controllerForItem:item].level;
- }
- - (id)childInParent:(id)parent atIndex:(NSInteger)index
- {
- RATreeNodeController *controller = [self.rootController controllerForItem:parent].childControllers[index];
- return controller.treeNode.item;
- }
- - (void)expandRowForItem:(id)item updates:(void (^)(NSIndexSet *))updates
- {
- [self expandRowForItem:item expandChildren:YES updates:updates];
- }
- - (void)expandRowForItem:(id)item expandChildren:(BOOL)expandChildren updates:(void (^)(NSIndexSet *))updates
- {
- NSParameterAssert(updates);
-
- RATreeNodeController *parentController = [self.rootController controllerForItem:item];
- NSMutableArray *items = [@[item] mutableCopy];
-
- while ([items count] > 0) {
- id currentItem = [items firstObject];
- [items removeObject:currentItem];
-
- RATreeNodeController *controller = [self.rootController controllerForItem:currentItem];
- NSMutableArray *oldChildItems = [NSMutableArray array];
- for (RATreeNodeController *nodeController in controller.childControllers) {
- [oldChildItems addObject:nodeController.treeNode.item];
- }
-
- NSInteger numberOfChildren = [self.dataSource treeNodeCollectionController:self numberOfChildrenForItem:controller.treeNode.item];
- NSIndexSet *allIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, numberOfChildren)];
-
- NSArray *currentChildControllersAndIndexes = [self controllersAndIndexesForNodesWithIndexes:allIndexes inParentController:controller];
- NSArray *currentChildControllers = [currentChildControllersAndIndexes valueForKey:@"controller"];
-
- NSMutableArray *childControllersToInsert = [NSMutableArray array];
- NSMutableIndexSet *indexesForInsertions = [NSMutableIndexSet indexSet];
- NSMutableArray *childControllersToRemove = [NSMutableArray array];
- NSMutableIndexSet *indexesForDeletions = [NSMutableIndexSet indexSet];
-
- for (RATreeNodeController *loopNodeController in currentChildControllers) {
- if (![controller.childControllers containsObject:loopNodeController]
- && ![oldChildItems containsObject:controller.treeNode.item]) {
- [childControllersToInsert addObject:loopNodeController];
- NSInteger index = [currentChildControllers indexOfObject:loopNodeController];
- NSAssert(index != NSNotFound, nil);
- [indexesForInsertions addIndex:index];
- }
- }
-
- for (RATreeNodeController *loopNodeController in controller.childControllers) {
- if (![currentChildControllers containsObject:loopNodeController]
- && ![childControllersToInsert containsObject:loopNodeController]) {
- [childControllersToRemove addObject:loopNodeController];
- NSInteger index = [controller.childControllers indexOfObject:loopNodeController];
- NSAssert(index != NSNotFound, nil);
- [indexesForDeletions addIndex:index];
- }
- }
-
- [controller removeChildControllersAtIndexes:indexesForDeletions];
- [controller insertChildControllers:childControllersToInsert atIndexes:indexesForInsertions];
-
- if (expandChildren) {
- for (RATreeNodeController *nodeController in controller.childControllers) {
- [items addObject:nodeController.treeNode.item];
- }
- }
- [controller expandAndExpandChildren:expandChildren];
- }
-
- updates(parentController.descendantsIndexes);
- }
- - (void)collapseRowForItem:(id)item collapseChildren:(BOOL)collapseChildren updates:(void (^)(NSIndexSet *))updates
- {
- NSParameterAssert(updates);
-
- RATreeNodeController *controller = [self.rootController controllerForItem:item];
- NSIndexSet *deletions = controller.descendantsIndexes;
- [controller collapseAndCollapseChildren:collapseChildren];
-
- updates(deletions);
- }
- - (void)insertItemsAtIndexes:(NSIndexSet *)indexes inParent:(id)item
- {
- RATreeNodeController *parentController = [self.rootController controllerForItem:item];
- NSArray *newControllers = [self controllersForNodesWithIndexes:indexes inParentController:parentController];
- [parentController insertChildControllers:newControllers atIndexes:indexes];
- }
- - (void)moveItemAtIndex:(NSInteger)index inParent:(id)parent toIndex:(NSInteger)newIndex inParent:(id)newParent updates:(void (^)(NSIndexSet *, NSIndexSet *))updates
- {
- NSParameterAssert(updates);
-
- NSMutableIndexSet *removedIndexes = [NSMutableIndexSet indexSet];
- NSMutableIndexSet *addedIndexes = [NSMutableIndexSet indexSet];
-
- RATreeNodeController *parentController = [self.rootController controllerForItem:parent];
-
- if (parent == newParent) {
- [parentController moveChildControllerAtIndex:index toIndex:newIndex];
-
- } else {
- RATreeNodeController *childController = parentController.childControllers[index];
-
- [removedIndexes addIndex:childController.index];
- [removedIndexes addIndexes:childController.descendantsIndexes];
-
- RATreeNodeController *newParentController = [self.rootController controllerForItem:parent];
- [parentController removeChildControllersAtIndexes:[NSIndexSet indexSetWithIndex:index]];
- [newParentController insertChildControllers:@[childController] atIndexes:[NSIndexSet indexSetWithIndex:newIndex]];
-
- [addedIndexes addIndex:childController.index];
- [addedIndexes addIndexes:childController.descendantsIndexes];
- }
-
- updates(removedIndexes, addedIndexes);
- }
- - (void)removeItemsAtIndexes:(NSIndexSet *)indexes inParent:(id)item updates:(void (^)(NSIndexSet *))updates
- {
- RATreeNodeController *parentController = [self.rootController controllerForItem:item];
-
- NSMutableIndexSet *indexesToRemoval = [NSMutableIndexSet indexSet];
- [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
- RATreeNodeController *controller = parentController.childControllers[idx];
- [indexesToRemoval addIndex:controller.index];
- [indexesToRemoval addIndexes:controller.descendantsIndexes];
- }];
-
- [parentController removeChildControllersAtIndexes:indexes];
-
- updates(indexesToRemoval);
- }
- - (NSArray *)controllersAndIndexesForNodesWithIndexes:(NSIndexSet *)indexes inParentController:(RATreeNodeController *)parentController
- {
- NSMutableArray *childControllers = [parentController.childControllers mutableCopy];
- NSMutableArray *currentControllers = [NSMutableArray array];
-
- NSMutableArray *invalidItems = [NSMutableArray array];
- for (RATreeNodeController *nodeController in parentController.childControllers) {
- [invalidItems addObject:nodeController.treeNode.item];
- }
-
- [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
-
- RATreeNodeController *controller;
- RATreeNodeController *oldControllerForCurrentIndex = nil;
-
-
- RATreeNodeItem *lazyItem = [[RATreeNodeItem alloc] initWithParent:parentController.treeNode.item index:idx];
- lazyItem.dataSource = self;
-
-
- for (RATreeNodeController *controller in parentController.childControllers) {
- if ([controller.treeNode.item isEqual:lazyItem.item]) {
- oldControllerForCurrentIndex = controller;
- }
- }
- if (oldControllerForCurrentIndex != nil) {
- controller = oldControllerForCurrentIndex;
-
- } else {
- controller = [[RATreeNodeController alloc] initWithParent:parentController item:lazyItem expandedBlock:^BOOL(id item) {
- return [childControllers indexOfObjectPassingTest:^BOOL(RATreeNodeController *controller, NSUInteger idx, BOOL *stop) {
- return [controller.treeNode.item isEqual:item];
- }] != NSNotFound;
- }];
- }
-
- [currentControllers addObject:@{ @"index" : @(idx),
- @"controller" : controller }];
- }];
-
- return [currentControllers copy];
- }
- - (NSArray *)controllersForNodesWithIndexes:(NSIndexSet *)indexes inParentController:(RATreeNodeController *)parentController
- {
- return [[self controllersAndIndexesForNodesWithIndexes:indexes inParentController:parentController] valueForKey:@"controller"];
- }
- - (NSArray *)controllersForNodes:(NSInteger)nodesNumber inParentController:(RATreeNodeController *)parentController
- {
- NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, nodesNumber)];
- return [self controllersForNodesWithIndexes:indexSet inParentController:parentController];
- }
- #pragma mark - RATreeNodeController delegate
- - (id)treeNodeController:(RATreeNodeController *)controller child:(NSInteger)childIndex
- {
- return [self.dataSource treeNodeCollectionController:self child:childIndex ofItem:controller.treeNode.item];
- }
- - (NSInteger)numberOfChildrenForTreeNodeController:(RATreeNodeController *)controller
- {
- return [self.dataSource treeNodeCollectionController:self numberOfChildrenForItem:controller.treeNode.item];
- }
- #pragma mark - RATreeNodeItem data source
- - (id)itemForTreeNodeItem:(RATreeNodeItem *)treeNodeItem
- {
- return [self.dataSource treeNodeCollectionController:self child:treeNodeItem.index ofItem:treeNodeItem.parent];
- }
- #pragma mark - Properties
- - (RATreeNodeController *)rootController
- {
- if (!_rootController) {
- _rootController = [[RATreeNodeController alloc] initWithParent:nil item:nil expandedBlock:^BOOL(id _) {
- return YES;
- }];
-
- NSInteger numberOfChildren = [self.dataSource treeNodeCollectionController:self numberOfChildrenForItem:nil];
- NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, numberOfChildren)];
- NSArray *childControllers = [self controllersForNodesWithIndexes:indexSet inParentController:_rootController];
- [_rootController insertChildControllers:childControllers atIndexes:indexSet];
- }
-
- return _rootController;
- }
- @end
|