Exhibition/ImageCollectionListController.swift
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Contains the `ImageCollectionListController` view controller subclass, which displays a list of `ImageCollection`s. |
*/ |
import Cocoa |
/** |
`ImageCollectionListController` displays a list of `ImageCollection`s in an |
`NSOutlineView`. It can be given a selection handler to report when an |
`ImageCollection` is selected. |
*/ |
class ImageCollectionListController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate { |
// MARK: Properties |
@IBOutlet var outlineView: NSOutlineView! |
override var nibName: String { |
return "ImageCollectionListController" |
} |
/// The identifier used for collection rows in the outline view |
static let collectionCellIdentifier = "DataCell" |
// MARK: Image Collection Management |
var imageCollectionSelectionHandler: (([ImageCollection]) -> Void)? |
var imageCollections = [ImageCollection]() { |
didSet { |
guard isViewLoaded else { return } |
reloadOutlineAndSelectFirstItemIfNecessary() |
} |
} |
// MARK: Life Cycle |
override func viewDidLoad() { |
super.viewDidLoad() |
reloadOutlineAndSelectFirstItemIfNecessary() |
} |
func reloadOutlineAndSelectFirstItemIfNecessary() { |
let oldSelection = outlineView.selectedRowIndexes |
outlineView.reloadData() |
if oldSelection.count == 0 { |
/* |
If the outline view didn't already have a selection, select the |
first `ImageCollection` (if one exists). |
*/ |
guard !imageCollections.isEmpty else { return } |
let firstIndexSet = IndexSet(integer: 0) |
outlineView.selectRowIndexes(firstIndexSet, byExtendingSelection: false) |
/* |
Programmatically changing the selection doesn't send a notification (it only |
happens when the user changes it). So, explicitly handle the new selection. |
*/ |
handleSelectionChanged() |
} |
else { |
// If there was an old selection, restore that old selection. |
outlineView.selectRowIndexes(oldSelection, byExtendingSelection: false) |
} |
} |
// MARK: OutlineView Data Source / Delegate |
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { |
return imageCollections[index] |
} |
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { |
// The root item has each collection as its children. |
if item == nil { |
return imageCollections.count |
} |
return 0 |
} |
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { |
guard let collection = item as? ImageCollection else { return nil } |
let view = outlineView.make(withIdentifier: ImageCollectionListController.collectionCellIdentifier, owner: self) as! NSTableCellView |
view.textField?.stringValue = collection.name |
view.imageView?.image = collection.tableViewIcon |
/* |
Turn on `translatesAutoresizingMaskIntoConstraints` so the outline view |
can manage the size and position of the views, specifically when the |
'Sidebar Icon Size' changes. With this on, the source nib must not be |
adding any runtime constraints to these views. |
*/ |
view.textField?.translatesAutoresizingMaskIntoConstraints = true |
view.imageView?.translatesAutoresizingMaskIntoConstraints = true |
return view |
} |
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { |
return false |
} |
func outlineView(_ outlineView: NSOutlineView, isGroupItem item: Any) -> Bool { |
return false |
} |
func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool { |
return item is ImageCollection |
} |
func outlineViewSelectionDidChange(_ notification: Notification) { |
guard outlineView == notification.object as? NSOutlineView else { return } |
handleSelectionChanged() |
} |
fileprivate func handleSelectionChanged() { |
guard let imageCollectionSelectionHandler = imageCollectionSelectionHandler else { return } |
let selectedRows = outlineView.selectedRowIndexes |
// Of the selected rows, get the ones that represent an `ImageCollection`. |
let imageCollections = selectedRows.flatMap { row in |
/* |
If the row doesn't represent an image collection, the result will |
be filtered out. |
*/ |
return outlineView.item(atRow: row) as? ImageCollection |
} |
imageCollectionSelectionHandler(imageCollections) |
} |
// MARK: IBActions |
@IBAction func showOpenPanelToAddImageCollection(_ sender: AnyObject?) { |
/// Show an `NSOpenPanel` to select a directory to create an `ImageCollection`. |
let openPanel = NSOpenPanel() |
openPanel.canChooseDirectories = true |
openPanel.canChooseFiles = false |
func modalCompletionHandler(_ modalResponse: NSModalResponse) { |
// Check that the response was OK, rather than Cancel. |
if modalResponse == NSFileHandlingPanelOKButton { |
/* |
For every URL selected, create an `ImageCollection` and add |
that to the list of displayed collections. |
*/ |
imageCollections += openPanel.urls.map { ImageCollection(rootURL: $0) } |
} |
} |
if let sheetParent = view.window { |
openPanel.beginSheetModal(for: sheetParent, completionHandler: modalCompletionHandler) |
} |
else { |
openPanel.begin(completionHandler: modalCompletionHandler) |
} |
} |
} |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-09-28