OSDN Git Service

AppDelegateからウインドウに関する部分を分離した
[kcd/KCD.git] / KCD / ExternalBrowserWindowController.swift
1 //
2 //  ExternalBrowserWindowController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/23.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10 import WebKit
11
12 fileprivate extension Selector {
13     static let addBookmark = #selector(ExternalBrowserWindowController.addBookmark(_:))
14     static let showBookmark = #selector(ExternalBrowserWindowController.showBookmark(_:))
15     static let selectBookmark = #selector(ExternalBrowserWindowController.selectBookmark(_:))
16     static let reloadContent = #selector(ExternalBrowserWindowController.reloadContent(_:))
17     static let updateContentVisibleRect = #selector(ExternalBrowserWindowController.updateContentVisibleRect(_:))
18 }
19
20 class ExternalBrowserWindowController: NSWindowController {
21     let managedObjectContext = BookmarkManager.shared().manageObjectContext
22     
23     deinit {
24         webView.removeObserver(self, forKeyPath: "canGoBack")
25         webView.removeObserver(self, forKeyPath: "canGoForward")
26     }
27     
28     @IBOutlet var webView: WebView!
29     @IBOutlet var goSegment: NSSegmentedControl!
30     @IBOutlet var bookmarkListView: NSView!
31     
32     override var windowNibName: String! {
33         return "ExternalBrowserWindowController"
34     }
35     dynamic var canResize: Bool = true {
36         willSet {
37             guard let window = window else { return }
38             if canResize == newValue { return }
39             var style = window.styleMask.rawValue
40             if newValue {
41                 style |= NSResizableWindowMask.rawValue
42             } else {
43                 style &= ~NSResizableWindowMask.rawValue
44             }
45             window.styleMask = NSWindowStyleMask(rawValue: style)
46         }
47     }
48     dynamic var canScroll: Bool = true {
49         willSet {
50             guard let webView = webView else { return }
51             if canScroll == newValue { return }
52             if newValue {
53                 webView.mainFrame.frameView.allowsScrolling = true
54             } else {
55                 webView.mainFrame.frameView.allowsScrolling = false
56             }
57         }
58     }
59     dynamic var canMovePage: Bool = true
60     
61     var urlString: String? {
62         return webView.mainFrameURL
63     }
64     var windowContentSize: NSSize {
65         get {
66             guard let window = window else { return .zero }
67             return window.contentRect(forFrameRect: window.frame).size
68         }
69         set {
70             guard let window = window else { return }
71             var contentRect: NSRect = .zero
72             contentRect.size = newValue
73             var newFrame = window.frameRect(forContentRect: contentRect)
74             let frame = window.frame
75             newFrame.origin.x = frame.minX
76             newFrame.origin.y = frame.maxY - newFrame.height
77             window.setFrame(newFrame, display: true)
78         }
79     }
80     var contentVisibleRect: NSRect {
81         get { return webView.mainFrame.frameView.documentView.visibleRect }
82         set { webView.mainFrame.frameView.documentView.scrollToVisible(newValue) }
83     }
84     
85     fileprivate var bookmarkShowing: Bool = false
86     fileprivate var waitingBookmarkItem: Bookmark?
87     
88     fileprivate lazy var bookmarkListViwController: BookmarkListViewController? = {
89         [weak self] in
90         guard let `self` = self else { return nil }
91         let controller = BookmarkListViewController()
92         self.bookmarkListView = controller.view
93         controller.delegate = self
94         
95         var frame = self.webView.frame
96         frame.size.width = 200
97         frame.origin.x = -200
98         self.bookmarkListView.frame = frame
99         self.webView.superview?.addSubview(self.bookmarkListView, positioned: .below, relativeTo: self.webView)
100         
101         return controller
102     }()
103     
104     override func windowDidLoad() {
105         super.windowDidLoad()
106         
107         webView.addObserver(self, forKeyPath: "canGoBack", context: nil)
108         webView.addObserver(self, forKeyPath: "canGoForward", context: nil)
109         webView.applicationNameForUserAgent = AppDelegate.shared.appNameForUserAgent
110         webView.frameLoadDelegate = self
111     }
112     override func observeValue(forKeyPath keyPath: String?,
113                                of object: Any?,
114                                change: [NSKeyValueChangeKey: Any]?,
115                                context: UnsafeMutableRawPointer?) {
116         if keyPath == "canGoBack" {
117             goSegment.setEnabled(webView.canGoBack, forSegment: 0)
118             return
119         }
120         if keyPath == "canGoForward" {
121             goSegment.setEnabled(webView.canGoForward, forSegment: 1)
122             return
123         }
124         
125         super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
126     }
127     override func swipe(with event: NSEvent) {
128         if event.deltaX > 0 && showsBookmarkList() {
129             showBookmark(nil)
130         }
131         if event.deltaX < 0 && !showsBookmarkList() {
132             showBookmark(nil)
133         }
134     }
135     
136     fileprivate func move(bookmark: Bookmark) {
137         if !canMovePage {
138             AppDelegate.shared.createNewBrowser().move(bookmark: bookmark)
139             return
140         }
141         
142         webView.mainFrameURL = bookmark.urlString
143         windowContentSize = bookmark.windowContentSize
144         canResize = bookmark.canResize
145         canScroll = bookmark.canScroll
146         waitingBookmarkItem = bookmark
147     }
148     fileprivate func showsBookmarkList() -> Bool {
149         return webView.frame.origin.x > 0
150     }
151 }
152
153 // MARK: - IBAction
154 extension ExternalBrowserWindowController {
155     override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
156         guard let action = menuItem.action else { return false }
157         switch action {
158         case Selector.addBookmark:
159             return webView.mainFrameURL != nil
160         case Selector.showBookmark:
161             if showsBookmarkList() {
162                 menuItem.title = NSLocalizedString("Hide Bookmark", comment: "Menu item title, Hide Bookmark")
163             } else {
164                 menuItem.title = NSLocalizedString("Show Bookmark", comment: "Menu item title, Show Bookmark")
165             }
166             return true
167         case Selector.selectBookmark:
168             return true
169         case Selector.reloadContent:
170             return true
171         default:
172             return false
173         }
174     }
175     
176     @IBAction func selectBookmark(_ sender: AnyObject?) {
177         guard let item = sender?.representedObject as? Bookmark
178             else { return }
179         move(bookmark: item)
180     }
181     @IBAction func reloadContent(_ sender: AnyObject?) {
182         webView.reload(nil)
183     }
184     @IBAction func goHome(_ sender: AnyObject?) {
185         webView.mainFrameURL = "http://www.dmm.com/"
186     }
187     @IBAction func clickGoBackSegment(_ sender: AnyObject?) {
188         guard let cell = goSegment.cell as? NSSegmentedCell
189             else { return }
190         let tag = cell.tag(forSegment: cell.selectedSegment)
191         switch tag {
192         case 0:
193             webView.goBack(nil)
194         case 1:
195             webView.goForward(nil)
196         default:
197             break
198         }
199     }
200     @IBAction func addBookmark(_ sender: AnyObject?) {
201         guard let window = window,
202             let bookmark = BookmarkManager.shared().createNewBookmark()
203             else { return }
204         bookmark.name = window.title
205         bookmark.urlString = webView.mainFrameURL
206         bookmark.windowContentSize = windowContentSize
207         bookmark.contentVisibleRect = contentVisibleRect
208         bookmark.canResize = canResize
209         bookmark.canScroll = canScroll
210         bookmark.scrollDelay = 0.5
211     }
212     @IBAction func showBookmark(_ sender: AnyObject?) {
213         guard let window = window,
214             let _ = bookmarkListViwController,
215             !bookmarkShowing
216             else { return }
217         bookmarkShowing = true
218         
219         var frame = bookmarkListView.frame
220         frame.size.height = webView.frame.size.height
221         bookmarkListView.frame = frame
222         
223         var newFrame = webView.frame
224         
225         if showsBookmarkList() {
226             frame.origin.x = -200
227             newFrame.origin.x = 0
228             newFrame.size.width = window.frame.size.width
229         } else {
230             frame.origin.x = 0
231             newFrame.origin.x = 200
232             newFrame.size.width = window.frame.size.width - 200
233         }
234         
235         let webAnime: [String: Any] = [
236             NSViewAnimationTargetKey: webView,
237             NSViewAnimationEndFrameKey: NSValue(rect: newFrame)
238         ]
239         let bookmarkAnime: [String: Any] = [
240             NSViewAnimationTargetKey: bookmarkListView,
241             NSViewAnimationEndFrameKey: NSValue(rect: frame)
242         ]
243         let anime = NSViewAnimation(viewAnimations: [webAnime, bookmarkAnime])
244         anime.delegate = self
245         anime.start()
246     }
247     @IBAction func scrollLeft(_ sender: AnyObject?) {
248         var rect = contentVisibleRect
249         rect.origin.x += 1
250         contentVisibleRect = rect
251     }
252     @IBAction func scrollRight(_ sender: AnyObject?) {
253         var rect = contentVisibleRect
254         rect.origin.x -= 1
255         contentVisibleRect = rect
256     }
257     @IBAction func scrollUp(_ sender: AnyObject?) {
258         var rect = contentVisibleRect
259         rect.origin.y += 1
260         contentVisibleRect = rect
261     }
262     @IBAction func scrollDown(_ sender: AnyObject?) {
263         var rect = contentVisibleRect
264         rect.origin.y -= 1
265         contentVisibleRect = rect
266     }
267     @IBAction func increaseWidth(_ sender: AnyObject?) {
268         guard let window = window else { return }
269         var frame = window.frame
270         frame.size.width += 1
271         window.setFrame(frame, display: true)
272     }
273     @IBAction func decreaseWidth(_ sender: AnyObject?) {
274         guard let window = window else { return }
275         var frame = window.frame
276         frame.size.width -= 1
277         window.setFrame(frame, display: true)
278     }
279     @IBAction func increaseHeight(_ sender: AnyObject?) {
280         guard let window = window else { return }
281         var frame = window.frame
282         frame.size.height += 1
283         frame.origin.y -= 1
284         window.setFrame(frame, display: true)
285     }
286     @IBAction func decreaseHeight(_ sender: AnyObject?) {
287         guard let window = window else { return }
288         var frame = window.frame
289         frame.size.height -= 1
290         frame.origin.y += 1
291         window.setFrame(frame, display: true)
292     }
293 }
294
295 extension ExternalBrowserWindowController: BookmarkListViewControllerDelegate {
296     func didSelectBookmark(_ bookmark: Bookmark) {
297         move(bookmark: bookmark)
298     }
299 }
300
301 extension ExternalBrowserWindowController: NSAnimationDelegate {
302     func animationDidEnd(_ animation: NSAnimation) {
303         bookmarkShowing = false
304     }
305 }
306
307 extension ExternalBrowserWindowController: WebFrameLoadDelegate, WebPolicyDelegate {
308     
309     func updateContentVisibleRect(_ timer: Timer) {
310         guard let item = timer.userInfo as? Bookmark else { return }
311         contentVisibleRect = item.contentVisibleRect
312     }
313     func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
314         if let waitingBookmarkItem = waitingBookmarkItem {
315             Timer.scheduledTimer(timeInterval: waitingBookmarkItem.scrollDelay,
316                                  target: self,
317                                  selector: .updateContentVisibleRect,
318                                  userInfo: waitingBookmarkItem,
319                                  repeats: false)
320         }
321         waitingBookmarkItem = nil
322     }
323     func webView(_ webView: WebView!,
324                  decidePolicyForNavigationAction actionInformation: [AnyHashable: Any]!,
325                  request: URLRequest!,
326                  frame: WebFrame!,
327                  decisionListener listener: WebPolicyDecisionListener!) {
328         if actionInformation?[WebActionNavigationTypeKey] as? WebNavigationType == .linkClicked {
329             if canMovePage {
330                 listener.use()
331             }
332             return
333         }
334         listener.use()
335     }
336 }