// // ContentViewController.swift // TagTunes // // Created by Kim Wittenburg on 21.01.16. // Copyright © 2016 Kim Wittenburg. All rights reserved. // import Cocoa import SearchAPI /// A `ContentViewController` displays a set of `TagTunesItem`s. It is /// responsible for allowing the user to associate `TagTunesTrack`s with /// `TagTunesEntityItem`s. /// /// The expected structure of the content view controller is a tree structure in /// the following form: /// /// 1. At the root level there are `TagTunesGroupItem`s (groups) and /// `TagTunesEntityItem`s (entities). /// 2. Groups can contain other entities (children). /// 3. Entities can have tracks associated with them. A track should not be /// associated with multiple entities. public class ContentViewController: NSViewController { override public func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ContentViewController.itemDidChangeState(_:)), name: TagTunesGroupItem.StateChangedNotificationName, object: nil) } /// Called when the `TagTunesGroupItem.StateChangedNotification` is posted. private dynamic func itemDidChangeState(notification: NSNotification) { if let item = notification.object as? TagTunesItem { updateItem(item) } } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } /// Returns all selected items. This property should remove duplicate items /// from the selection following these three rules: /// /// 1. If an entity is selected (and thus contained in the returned array) /// none of its `associatedTracks` should be contained in the returned /// array. /// 2. If a group is selected none of its children should be contained in the /// returned array. /// 3. If a track is selected and (1) and (2) do not appy it should be /// contained in the returned array. /// /// This value is not cached. If you need to access this multiple times in a /// row, you should consider caching it yourself in a local variable. The /// order in which the selected objects occur in the returned array may be /// different from the order in which they are displayed. /// /// This method must be implemented by subclasses. public var selectedItems: [AnyObject] { fatalError("Must override property selectedItems") } /// Returns the item the user clicked on. This property should be used /// instead of the `selectedItems` for any context menu related actions. This /// property should behave the same way that `selectedItems` does. /// /// This method must be implemented by subclasses. public var clickedItems: [AnyObject] { fatalError("Must override property clickedItem") } /// Returns the item that represents the specified `entity`. If no such item /// exists in the content view controller `nil` is returned. /// /// This method must be implemented by subclasses. public func itemForEntity(entity: SearchAPIEntity) -> TagTunesItem? { fatalError("Must override itemForEntity(_:)") } /// Adds the specified `item` to the view controller. This should insert the /// `item` at the root level of the controller. If the controller already /// contains an item that represents the same entity as the specified `item` /// this method should do nothing. /// /// This method must be implemented by subclasses. public func addItem(item: TagTunesItem) { fatalError("Must override addItem(_:)") } /// Updates the specified `item`. This method should be called if the /// properties of the `item` changed in any way and the view should be /// notified about it. If the `item` has not previously been added to the /// view controller this method should do nothing. /// /// This method must be implemented by subclasses. public func updateItem(item: TagTunesItem) { fatalError("Must override updateItem(_:)") } /// Updates all items. If many items in the view controller changed it may be /// more efficient to use this method instead of `updateItem(_:)`. /// /// This method must be implemented by subclasses. public func updateAllItems() { fatalError("Must override updateAllItems()") } /// Removes the selected items from the view controller. By default the /// implementation just calls `removeItems(selectedItems` but subclasses may /// override this method to optimize the behavior. public func removeSelectedItems() { removeItems(selectedItems) } /// Removes the specified items from the view controller and updates the view /// accordingly. /// /// This method must be implemented by subclasses. public func removeItems(items: [AnyObject]) { fatalError("Must override removeItems(_:)") } }