Files
SimDirs-mirror/SimDirs/UI/SourceController.swift
2021-11-26 23:48:59 +01:00

191 lines
6.8 KiB
Swift

//
// SourceController.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
protocol OutlineProvider {
var outlineTitle : String { get }
var outlineImage : NSImage? { get }
var childCount : Int { get }
func childAtIndex(_ index: Int) -> OutlineProvider?
}
extension OutlineProvider {
var expandable : Bool { return self.childCount > 0 }
}
class SourceController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
@IBOutlet weak var outlineView : NSOutlineView!
@IBOutlet weak var displayTypeView: NSSegmentedControl!
@IBOutlet weak var installedSwitch: NSSwitch!
enum DisplayType {
case versions(platforms: [SimPlatform])
case devices([SimDevice])
case apps([SimApp])
}
private var displayType: DisplayType = .versions(platforms: []) {
didSet {
self.outlineView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let (platforms, _, _) = self.prepareModel()
self.displayType = .versions(platforms: platforms)
}
private func prepareModel() -> (platforms: [SimPlatform], devices: [SimDevice], apps: [SimApp]) {
var platforms = SimPlatform.scan()
var devices = platforms.flatMap{ platform -> [SimDevice] in
platform.osVersions.flatMap { os -> [SimDevice] in
os.devices.map { device -> SimDevice in
let new = device.copy() as! SimDevice
new.name = "\(os.outlineTitle) - \(device.name)"
return new
}
}
}
let apps = platforms.flatMap{ platform -> [SimApp] in
platform.osVersions.flatMap { os -> [SimApp] in
os.devices.flatMap { device -> [SimApp] in
device.apps.map { app -> SimApp in
let new = app.copy() as! SimApp
new.displayName = new.outlineTitle + " - \(device.outlineTitle) - \(os.outlineTitle)"
return new
}
}
}
}.sorted { a,b in a.modificationDate ?? Date.distantPast > b.modificationDate ?? Date.distantPast }
if installedSwitch.state == .on {
platforms = platforms.compactMap { platform -> SimPlatform?
in
let new = platform.copy() as! SimPlatform
new.osVersions = platform.osVersions.compactMap { os -> SimOSVersion? in
let new = os.copy() as! SimOSVersion
new.devices = os.devices.filter { $0.expandable }
return new.devices.isEmpty ? nil : new
}
return new.osVersions.isEmpty ? nil : new
}
devices = devices
.filter { $0.expandable }
}
return (platforms, devices, apps)
}
// MARK: - NSOutlineViewDataSource -
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
switch self.displayType {
case .versions(let platforms):
return (item as? OutlineProvider)?.childCount ?? platforms.count
case .devices(let devices):
return (item as? OutlineProvider)?.childCount ?? devices.count
case .apps(let apps):
return (item as? OutlineProvider)?.childCount ?? apps.count
}
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
switch self.displayType {
case .versions(let platforms):
return (item as? OutlineProvider)?.childAtIndex(index) ?? platforms[index]
case .devices(let devices):
return (item as? OutlineProvider)?.childAtIndex(index) ?? devices[index]
case .apps(let apps):
return (item as? OutlineProvider)?.childAtIndex(index) ?? apps[index]
}
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
switch self.displayType {
case .versions(let platforms):
return (item as? OutlineProvider)?.expandable ?? (platforms.count > 0)
case .devices(let devices):
return (item as? OutlineProvider)?.expandable ?? (devices.count > 0)
case .apps(let apps):
return (item as? OutlineProvider)?.expandable ?? (apps.count > 0)
}
}
// MARK: - NSOutlineViewDelegate -
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
var view : NSTableCellView? = nil
var title = ""
var image : NSImage? = nil
if let outlineProvider = item as? OutlineProvider {
title = outlineProvider.outlineTitle
image = outlineProvider.outlineImage
}
if let outlineCell = outlineView.makeView(withIdentifier: convertToNSUserInterfaceItemIdentifier(image != nil ? "ImageCell" : "TextCell"), owner: self) as? NSTableCellView {
outlineCell.textField?.stringValue = title
outlineCell.imageView?.image = image
view = outlineCell
}
return view
}
func outlineView(_ outlineView: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
return (item as? OutlineProvider)?.outlineImage != nil ? 24.0 : 20.0
}
func outlineViewSelectionDidChange(_ notification: Notification) {
if let thing = (self.parent as? NSSplitViewController)?.splitViewItems[safe: 1]?.viewController as? DetailController {
var selectedItem : AnyObject? = nil
let row = self.outlineView.selectedRow
if row != NSNotFound {
selectedItem = self.outlineView.item(atRow: row) as AnyObject?
}
thing.selectedItem = selectedItem
}
}
// MARK: - Interaction -
@IBAction private func displayTypeChanged(_ sender: NSSegmentedControl) {
self.update()
}
@IBAction func installedFilterChanged(_ sender: NSSwitch) {
self.update()
}
@IBAction func rescan(_ sender: AnyObject?) {
self.update()
}
private func update() {
let (platforms, devices, apps) = self.prepareModel()
switch self.displayTypeView.selectedSegment {
case 0:
self.displayType = .versions(platforms: platforms)
case 1:
self.displayType = .devices(devices)
case 2:
self.displayType = .apps(apps)
default:
break
}
}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToNSUserInterfaceItemIdentifier(_ input: String) -> NSUserInterfaceItemIdentifier {
return NSUserInterfaceItemIdentifier(rawValue: input)
}