OSDN Git Service

Doutakuを導入
[kcd/KCD.git] / KCD / ShipViewController.swift
1 //
2 //  ShipViewController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/25.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 private enum ViewType: Int {
12     
13     case exp
14     case power
15     case power2
16     case power3
17 }
18
19 /// 2018.02.24
20 /// #keyPath(Ship.master_ship.soku)がkeyであるNSSortDescriptorが含まれるとクラッシュする可能性があるため
21 /// 新設した#keyPath(Ship.soku)をkeyにするように書き換える
22 private func exchangeSortKey(original: [NSSortDescriptor]) -> [NSSortDescriptor] {
23     
24     return original
25         .map { sortDesc -> NSSortDescriptor in
26             
27             if sortDesc.key == #keyPath(Ship.master_ship.soku) {
28                 
29                 return NSSortDescriptor(key: #keyPath(Ship.soku), ascending: sortDesc.ascending)
30             }
31             
32             return sortDesc
33     }
34 }
35
36 final class ShipViewController: MainTabVIewItemViewController {
37     
38     @objc let managedObjectContext = ServerDataStore.default.context
39     
40     @IBOutlet private var shipController: NSArrayController!
41     @IBOutlet private var expTableView: NSScrollView!
42     @IBOutlet private var powerTableView: NSScrollView!
43     @IBOutlet private var power2TableView: NSScrollView!
44     @IBOutlet private var power3TableView: NSScrollView!
45     @IBOutlet private weak var standardDeviationField: NSTextField!
46     
47     private var sortDescriptorsObservation: NSKeyValueObservation?
48     private var arrangedObjectsObservation: NSKeyValueObservation?
49     
50     private var notificationObserver = NotificationObserver()
51     
52     override var nibName: NSNib.Name {
53         
54         return .nibName(instanceOf: self)
55     }
56     
57     override var hasShipTypeSelector: Bool { return true }
58     override var selectedShipType: ShipTabType {
59         
60         didSet {
61             shipController.filterPredicate = shipTypePredicte(for: selectedShipType)
62             shipController.rearrangeObjects()
63         }
64     }
65     
66     @objc var standardDeviation: Double {
67         
68         guard let ships = shipController.arrangedObjects as? [Ship], !ships.isEmpty else { return 0.0 }
69         guard let avg = shipController.value(forKeyPath: "arrangedObjects.@avg.lv") as? Double else { return 0.0 }
70         
71         let total = ships.reduce(0.0) {
72             
73             let delta = Double($1.lv) - avg
74             
75             return $0 + delta * delta
76         }
77         
78         return sqrt(total / Double(ships.count))
79     }
80     
81 //    @objc dynamic var sortDescriptors: [NSSortDescriptor] {
82 //        get { return UserDefaults.standard[.shipviewSortDescriptors] }
83 //        set { UserDefaults.standard[.shipviewSortDescriptors] = sortDescriptors }
84 //    }
85     
86     private weak var currentTableView: NSView?
87     
88     override func viewDidLoad() {
89         
90         super.viewDidLoad()
91         
92         currentTableView = expTableView
93         
94         do {
95             
96             try shipController.fetch(with: nil, merge: true)
97             
98         } catch {
99             
100             fatalError("ShipViewController: can not fetch. \(error)")
101             
102         }
103         
104         shipController.sortDescriptors = exchangeSortKey(original: UserDefaults.standard[.shipviewSortDescriptors])
105
106         sortDescriptorsObservation = shipController.observe(\NSArrayController.sortDescriptors) { [weak self] _, _ in
107
108             UserDefaults.standard[.shipviewSortDescriptors] = self?.shipController.sortDescriptors ?? []
109         }
110         arrangedObjectsObservation = shipController.observe(\NSArrayController.arrangedObjects) { [weak self] _, _ in
111             
112             self?.notifyChangeValue(forKey: #keyPath(standardDeviation))
113         }
114         
115         let tableViews = [expTableView, powerTableView, power2TableView, power3TableView]
116         tableViews
117             .forEach {
118                 
119                 notificationObserver
120                     .addObserver(forName: NSScrollView.didEndLiveScrollNotification, object: $0, queue: .main) {
121                         
122                         guard let target = $0.object as? NSScrollView else { return }
123                         
124                         let visibleRect = target.documentVisibleRect
125                         tableViews
126                             .filter { $0 != target }
127                             .forEach { $0?.documentView?.scrollToVisible(visibleRect) }
128                 }
129         }
130         #if DEBUG
131             standardDeviationField.isHidden = false
132         #endif
133     }
134     
135     private func showView(with type: ViewType) {
136         
137         let newSelection: NSView = {
138             
139             switch type {
140             case .exp: return expTableView
141             case .power: return powerTableView
142             case .power2: return power2TableView
143             case .power3: return power3TableView
144             }
145         }()
146         
147         if currentTableView == newSelection { return }
148         
149         guard let tableView = currentTableView else { return }
150         
151         newSelection.frame = tableView.frame
152         newSelection.autoresizingMask = tableView.autoresizingMask
153         view.replaceSubview(tableView, with: newSelection)
154         view.window?.makeFirstResponder(newSelection)
155         currentTableView = newSelection
156     }
157     
158     private func tag(_ sender: AnyObject?) -> Int {
159         
160         switch sender {
161             
162         case let segmented as NSSegmentedControl:
163             let cell = segmented.cell as? NSSegmentedCell
164             
165             return cell?.tag(forSegment: segmented.selectedSegment) ?? -1
166             
167         case let control as NSControl:
168             return control.tag
169             
170         default:
171             return -1
172         }
173     }
174     
175     @IBAction func changeView(_ sender: AnyObject?) {
176         
177         ViewType(rawValue: tag(sender)).map(showView)
178     }
179 }
180
181 extension ShipViewController: NSTableViewDelegate {
182     
183     func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
184         
185         guard let identifier = tableColumn?.identifier else { return nil }
186         
187         return tableView.makeView(withIdentifier: identifier, owner: nil)
188     }
189 }