This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Doric/doric-iOS/Devkit/Classes/RATreeView/RATreeNodeCollectionController.m
2021-07-21 19:32:31 +08:00

302 lines
11 KiB
Objective-C

//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