RATreeNodeCollectionController.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. //The MIT License (MIT)
  2. //
  3. //Copyright (c) 2014 Rafał Augustyniak
  4. //
  5. //Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. //this software and associated documentation files (the "Software"), to deal in
  7. //the Software without restriction, including without limitation the rights to
  8. //use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. //the Software, and to permit persons to whom the Software is furnished to do so,
  10. //subject to the following conditions:
  11. //
  12. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. //FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. //COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. //IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. //CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. //
  19. #import "RATreeNodeCollectionController.h"
  20. #import "RATreeNodeController.h"
  21. #import "RATreeNode.h"
  22. #import "RATreeNodeItem+Private.h"
  23. #import "RABatchChanges.h"
  24. @interface RATreeNodeCollectionController () <RATreeNodeItemDataSource>
  25. @property (nonatomic, strong) RATreeNodeController *rootController;
  26. @end
  27. @implementation RATreeNodeCollectionController
  28. - (NSInteger)numberOfVisibleRowsForItems
  29. {
  30. return self.rootController.numberOfVisibleDescendants;
  31. }
  32. - (RATreeNode *)treeNodeForIndex:(NSInteger)index
  33. {
  34. return [self.rootController controllerForIndex:index].treeNode;
  35. }
  36. - (NSInteger)indexForItem:(id)item
  37. {
  38. return [self.rootController indexForItem:item];
  39. }
  40. - (NSInteger)lastVisibleDescendantIndexForItem:(id)item
  41. {
  42. return [self.rootController lastVisibleDescendatIndexForItem:item];
  43. }
  44. - (id)parentForItem:(id)item
  45. {
  46. RATreeNodeController *controller = [self.rootController controllerForItem:item];
  47. return controller.parentController.treeNode.item;
  48. }
  49. - (NSInteger)levelForItem:(id)item
  50. {
  51. return [self.rootController controllerForItem:item].level;
  52. }
  53. - (id)childInParent:(id)parent atIndex:(NSInteger)index
  54. {
  55. RATreeNodeController *controller = [self.rootController controllerForItem:parent].childControllers[index];
  56. return controller.treeNode.item;
  57. }
  58. - (void)expandRowForItem:(id)item updates:(void (^)(NSIndexSet *))updates
  59. {
  60. [self expandRowForItem:item expandChildren:YES updates:updates];
  61. }
  62. - (void)expandRowForItem:(id)item expandChildren:(BOOL)expandChildren updates:(void (^)(NSIndexSet *))updates
  63. {
  64. NSParameterAssert(updates);
  65. RATreeNodeController *parentController = [self.rootController controllerForItem:item];
  66. NSMutableArray *items = [@[item] mutableCopy];
  67. while ([items count] > 0) {
  68. id currentItem = [items firstObject];
  69. [items removeObject:currentItem];
  70. RATreeNodeController *controller = [self.rootController controllerForItem:currentItem];
  71. NSMutableArray *oldChildItems = [NSMutableArray array];
  72. for (RATreeNodeController *nodeController in controller.childControllers) {
  73. [oldChildItems addObject:nodeController.treeNode.item];
  74. }
  75. NSInteger numberOfChildren = [self.dataSource treeNodeCollectionController:self numberOfChildrenForItem:controller.treeNode.item];
  76. NSIndexSet *allIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, numberOfChildren)];
  77. NSArray *currentChildControllersAndIndexes = [self controllersAndIndexesForNodesWithIndexes:allIndexes inParentController:controller];
  78. NSArray *currentChildControllers = [currentChildControllersAndIndexes valueForKey:@"controller"];
  79. NSMutableArray *childControllersToInsert = [NSMutableArray array];
  80. NSMutableIndexSet *indexesForInsertions = [NSMutableIndexSet indexSet];
  81. NSMutableArray *childControllersToRemove = [NSMutableArray array];
  82. NSMutableIndexSet *indexesForDeletions = [NSMutableIndexSet indexSet];
  83. for (RATreeNodeController *loopNodeController in currentChildControllers) {
  84. if (![controller.childControllers containsObject:loopNodeController]
  85. && ![oldChildItems containsObject:controller.treeNode.item]) {
  86. [childControllersToInsert addObject:loopNodeController];
  87. NSInteger index = [currentChildControllers indexOfObject:loopNodeController];
  88. NSAssert(index != NSNotFound, nil);
  89. [indexesForInsertions addIndex:index];
  90. }
  91. }
  92. for (RATreeNodeController *loopNodeController in controller.childControllers) {
  93. if (![currentChildControllers containsObject:loopNodeController]
  94. && ![childControllersToInsert containsObject:loopNodeController]) {
  95. [childControllersToRemove addObject:loopNodeController];
  96. NSInteger index = [controller.childControllers indexOfObject:loopNodeController];
  97. NSAssert(index != NSNotFound, nil);
  98. [indexesForDeletions addIndex:index];
  99. }
  100. }
  101. [controller removeChildControllersAtIndexes:indexesForDeletions];
  102. [controller insertChildControllers:childControllersToInsert atIndexes:indexesForInsertions];
  103. if (expandChildren) {
  104. for (RATreeNodeController *nodeController in controller.childControllers) {
  105. [items addObject:nodeController.treeNode.item];
  106. }
  107. }
  108. [controller expandAndExpandChildren:expandChildren];
  109. }
  110. updates(parentController.descendantsIndexes);
  111. }
  112. - (void)collapseRowForItem:(id)item collapseChildren:(BOOL)collapseChildren updates:(void (^)(NSIndexSet *))updates
  113. {
  114. NSParameterAssert(updates);
  115. RATreeNodeController *controller = [self.rootController controllerForItem:item];
  116. NSIndexSet *deletions = controller.descendantsIndexes;
  117. [controller collapseAndCollapseChildren:collapseChildren];
  118. updates(deletions);
  119. }
  120. - (void)insertItemsAtIndexes:(NSIndexSet *)indexes inParent:(id)item
  121. {
  122. RATreeNodeController *parentController = [self.rootController controllerForItem:item];
  123. NSArray *newControllers = [self controllersForNodesWithIndexes:indexes inParentController:parentController];
  124. [parentController insertChildControllers:newControllers atIndexes:indexes];
  125. }
  126. - (void)moveItemAtIndex:(NSInteger)index inParent:(id)parent toIndex:(NSInteger)newIndex inParent:(id)newParent updates:(void (^)(NSIndexSet *, NSIndexSet *))updates
  127. {
  128. NSParameterAssert(updates);
  129. NSMutableIndexSet *removedIndexes = [NSMutableIndexSet indexSet];
  130. NSMutableIndexSet *addedIndexes = [NSMutableIndexSet indexSet];
  131. RATreeNodeController *parentController = [self.rootController controllerForItem:parent];
  132. if (parent == newParent) {
  133. [parentController moveChildControllerAtIndex:index toIndex:newIndex];
  134. } else {
  135. RATreeNodeController *childController = parentController.childControllers[index];
  136. [removedIndexes addIndex:childController.index];
  137. [removedIndexes addIndexes:childController.descendantsIndexes];
  138. RATreeNodeController *newParentController = [self.rootController controllerForItem:parent];
  139. [parentController removeChildControllersAtIndexes:[NSIndexSet indexSetWithIndex:index]];
  140. [newParentController insertChildControllers:@[childController] atIndexes:[NSIndexSet indexSetWithIndex:newIndex]];
  141. [addedIndexes addIndex:childController.index];
  142. [addedIndexes addIndexes:childController.descendantsIndexes];
  143. }
  144. updates(removedIndexes, addedIndexes);
  145. }
  146. - (void)removeItemsAtIndexes:(NSIndexSet *)indexes inParent:(id)item updates:(void (^)(NSIndexSet *))updates
  147. {
  148. RATreeNodeController *parentController = [self.rootController controllerForItem:item];
  149. NSMutableIndexSet *indexesToRemoval = [NSMutableIndexSet indexSet];
  150. [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
  151. RATreeNodeController *controller = parentController.childControllers[idx];
  152. [indexesToRemoval addIndex:controller.index];
  153. [indexesToRemoval addIndexes:controller.descendantsIndexes];
  154. }];
  155. [parentController removeChildControllersAtIndexes:indexes];
  156. updates(indexesToRemoval);
  157. }
  158. - (NSArray *)controllersAndIndexesForNodesWithIndexes:(NSIndexSet *)indexes inParentController:(RATreeNodeController *)parentController
  159. {
  160. NSMutableArray *childControllers = [parentController.childControllers mutableCopy];
  161. NSMutableArray *currentControllers = [NSMutableArray array];
  162. NSMutableArray *invalidItems = [NSMutableArray array];
  163. for (RATreeNodeController *nodeController in parentController.childControllers) {
  164. [invalidItems addObject:nodeController.treeNode.item];
  165. }
  166. [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
  167. RATreeNodeController *controller;
  168. RATreeNodeController *oldControllerForCurrentIndex = nil;
  169. RATreeNodeItem *lazyItem = [[RATreeNodeItem alloc] initWithParent:parentController.treeNode.item index:idx];
  170. lazyItem.dataSource = self;
  171. for (RATreeNodeController *controller in parentController.childControllers) {
  172. if ([controller.treeNode.item isEqual:lazyItem.item]) {
  173. oldControllerForCurrentIndex = controller;
  174. }
  175. }
  176. if (oldControllerForCurrentIndex != nil) {
  177. controller = oldControllerForCurrentIndex;
  178. } else {
  179. controller = [[RATreeNodeController alloc] initWithParent:parentController item:lazyItem expandedBlock:^BOOL(id item) {
  180. return [childControllers indexOfObjectPassingTest:^BOOL(RATreeNodeController *controller, NSUInteger idx, BOOL *stop) {
  181. return [controller.treeNode.item isEqual:item];
  182. }] != NSNotFound;
  183. }];
  184. }
  185. [currentControllers addObject:@{ @"index" : @(idx),
  186. @"controller" : controller }];
  187. }];
  188. return [currentControllers copy];
  189. }
  190. - (NSArray *)controllersForNodesWithIndexes:(NSIndexSet *)indexes inParentController:(RATreeNodeController *)parentController
  191. {
  192. return [[self controllersAndIndexesForNodesWithIndexes:indexes inParentController:parentController] valueForKey:@"controller"];
  193. }
  194. - (NSArray *)controllersForNodes:(NSInteger)nodesNumber inParentController:(RATreeNodeController *)parentController
  195. {
  196. NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, nodesNumber)];
  197. return [self controllersForNodesWithIndexes:indexSet inParentController:parentController];
  198. }
  199. #pragma mark - RATreeNodeController delegate
  200. - (id)treeNodeController:(RATreeNodeController *)controller child:(NSInteger)childIndex
  201. {
  202. return [self.dataSource treeNodeCollectionController:self child:childIndex ofItem:controller.treeNode.item];
  203. }
  204. - (NSInteger)numberOfChildrenForTreeNodeController:(RATreeNodeController *)controller
  205. {
  206. return [self.dataSource treeNodeCollectionController:self numberOfChildrenForItem:controller.treeNode.item];
  207. }
  208. #pragma mark - RATreeNodeItem data source
  209. - (id)itemForTreeNodeItem:(RATreeNodeItem *)treeNodeItem
  210. {
  211. return [self.dataSource treeNodeCollectionController:self child:treeNodeItem.index ofItem:treeNodeItem.parent];
  212. }
  213. #pragma mark - Properties
  214. - (RATreeNodeController *)rootController
  215. {
  216. if (!_rootController) {
  217. _rootController = [[RATreeNodeController alloc] initWithParent:nil item:nil expandedBlock:^BOOL(id _) {
  218. return YES;
  219. }];
  220. NSInteger numberOfChildren = [self.dataSource treeNodeCollectionController:self numberOfChildrenForItem:nil];
  221. NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, numberOfChildren)];
  222. NSArray *childControllers = [self controllersForNodesWithIndexes:indexSet inParentController:_rootController];
  223. [_rootController insertChildControllers:childControllers atIndexes:indexSet];
  224. }
  225. return _rootController;
  226. }
  227. @end