122 lines
2.7 KiB
Swift
122 lines
2.7 KiB
Swift
//
|
|
// TreeController.swift
|
|
// Evergreen
|
|
//
|
|
// Created by Brent Simmons on 5/29/16.
|
|
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public protocol TreeControllerDelegate: class {
|
|
|
|
func treeController(treeController: TreeController, childNodesFor: Node) -> [Node]?
|
|
}
|
|
|
|
public typealias NodeVisitBlock = (_ : Node) -> Void
|
|
|
|
public final class TreeController {
|
|
|
|
fileprivate weak var delegate: TreeControllerDelegate?
|
|
public let rootNode: Node
|
|
|
|
public init(delegate: TreeControllerDelegate, rootNode: Node) {
|
|
|
|
self.delegate = delegate
|
|
self.rootNode = rootNode
|
|
rebuild()
|
|
}
|
|
|
|
public convenience init(delegate: TreeControllerDelegate) {
|
|
|
|
self.init(delegate: delegate, rootNode: Node.genericRootNode())
|
|
}
|
|
|
|
@discardableResult
|
|
public func rebuild() -> Bool {
|
|
|
|
// Rebuild and re-sort. Return true if any changes in the entire tree.
|
|
|
|
return rebuildChildNodes(node: rootNode)
|
|
}
|
|
|
|
public func visitNodes(_ visitBlock: NodeVisitBlock) {
|
|
|
|
visitNode(rootNode, visitBlock)
|
|
}
|
|
|
|
public func nodeInArrayRepresentingObject(nodes: [Node], representedObject: AnyObject, recurse: Bool = false) -> Node? {
|
|
|
|
for oneNode in nodes {
|
|
|
|
if oneNode.representedObject === representedObject {
|
|
return oneNode
|
|
}
|
|
|
|
if recurse, oneNode.canHaveChildNodes, let childNodes = oneNode.childNodes {
|
|
if let foundNode = nodeInArrayRepresentingObject(nodes: childNodes, representedObject: representedObject, recurse: recurse) {
|
|
return foundNode
|
|
}
|
|
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public func nodeInTreeRepresentingObject(_ representedObject: AnyObject) -> Node? {
|
|
|
|
return nodeInArrayRepresentingObject(nodes: [rootNode], representedObject: representedObject, recurse: true)
|
|
}
|
|
}
|
|
|
|
private extension TreeController {
|
|
|
|
func visitNode(_ node: Node, _ visitBlock: NodeVisitBlock) {
|
|
|
|
visitBlock(node)
|
|
node.childNodes?.forEach{ (oneChildNode) in
|
|
visitNode(oneChildNode, visitBlock)
|
|
}
|
|
}
|
|
|
|
func nodeArraysAreEqual(_ nodeArray1: [Node]?, _ nodeArray2: [Node]?) -> Bool {
|
|
|
|
if nodeArray1 == nil && nodeArray2 == nil {
|
|
return true
|
|
}
|
|
if nodeArray1 != nil && nodeArray2 == nil {
|
|
return false
|
|
}
|
|
if nodeArray1 == nil && nodeArray2 != nil {
|
|
return false
|
|
}
|
|
|
|
return nodeArray1! == nodeArray2!
|
|
}
|
|
|
|
func rebuildChildNodes(node: Node) -> Bool {
|
|
|
|
if !node.canHaveChildNodes {
|
|
return false
|
|
}
|
|
|
|
var childNodesDidChange = false
|
|
|
|
let childNodes = delegate?.treeController(treeController: self, childNodesFor: node)
|
|
|
|
childNodesDidChange = !nodeArraysAreEqual(childNodes, node.childNodes)
|
|
if (childNodesDidChange) {
|
|
node.childNodes = childNodes
|
|
}
|
|
|
|
childNodes?.forEach{ (oneChildNode) in
|
|
if rebuildChildNodes(node: oneChildNode) {
|
|
childNodesDidChange = true
|
|
}
|
|
}
|
|
|
|
return childNodesDidChange
|
|
}
|
|
|
|
}
|