OSDN Git Service

guard の書き方を統一した
[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 private extension Selector {
13     
14     static let addBookmark = #selector(ExternalBrowserWindowController.addBookmark(_:))
15     static let showBookmark = #selector(ExternalBrowserWindowController.showBookmark(_:))
16     static let selectBookmark = #selector(ExternalBrowserWindowController.selectBookmark(_:))
17     static let reloadContent = #selector(ExternalBrowserWindowController.reloadContent(_:))
18     static let updateContentVisibleRect = #selector(ExternalBrowserWindowController.updateContentVisibleRect(_:))
19 }
20
21 final class ExternalBrowserWindowController: NSWindowController {
22     
23     let managedObjectContext = BookmarkManager.shared().manageObjectContext
24     
25     deinit {
26         
27         webView.removeObserver(self, forKeyPath: "canGoBack")
28         webView.removeObserver(self, forKeyPath: "canGoForward")
29     }
30     
31     @IBOutlet var webView: WebView!
32     @IBOutlet var goSegment: NSSegmentedControl!
33     @IBOutlet var bookmarkListView: NSView!
34     
35     override var windowNibName: NSNib.Name {
36         
37         return .nibName(instanceOf: self)
38     }
39     
40     @objc dynamic var canResize: Bool = true {
41         
42         willSet {
43             guard let window = window else { return }
44             
45             if canResize == newValue { return }
46             
47             var styleMask = window.styleMask
48             if newValue {
49                 
50                 styleMask.insert(.resizable)
51                 
52             } else {
53                 
54                 styleMask.remove(.resizable)
55             }
56             
57             window.styleMask = styleMask
58         }
59     }
60     
61     @objc dynamic var canScroll: Bool = true {
62         
63         willSet {
64             guard let webView = webView else { return }
65             
66             if canScroll == newValue { return }
67             
68             if newValue {
69                 
70                 webView.mainFrame.frameView.allowsScrolling = true
71                 
72             } else {
73                 
74                 webView.mainFrame.frameView.allowsScrolling = false
75             }
76         }
77     }
78     @objc dynamic var canMovePage: Bool = true
79     
80     var urlString: String? {
81         
82         return webView.mainFrameURL
83     }
84     
85     var windowContentSize: NSSize {
86         
87         get {
88             guard let window = window else { return .zero }
89             
90             return window.contentRect(forFrameRect: window.frame).size
91         }
92         set {
93             guard let window = window else { return }
94             
95             var contentRect: NSRect = .zero
96             contentRect.size = newValue
97             var newFrame = window.frameRect(forContentRect: contentRect)
98             let frame = window.frame
99             newFrame.origin.x = frame.minX
100             newFrame.origin.y = frame.maxY - newFrame.height
101             window.setFrame(newFrame, display: true)
102         }
103     }
104     
105     var contentVisibleRect: NSRect {
106         
107         get { return webView.mainFrame.frameView.documentView.visibleRect }
108         set { webView.mainFrame.frameView.documentView.scrollToVisible(newValue) }
109     }
110     
111     private var bookmarkShowing: Bool = false
112     private var waitingBookmarkItem: Bookmark?
113     
114     private lazy var bookmarkListViwController: BookmarkListViewController? = { [weak self] in
115         
116         guard let `self` = self else { return nil }
117         
118         let controller = BookmarkListViewController()
119         self.bookmarkListView = controller.view
120         controller.delegate = self
121         
122         var frame = self.webView.frame
123         frame.size.width = 200
124         frame.origin.x = -200
125         self.bookmarkListView.frame = frame
126         self.webView.superview?.addSubview(self.bookmarkListView, positioned: .below, relativeTo: self.webView)
127         
128         return controller
129     }()
130     
131     override func windowDidLoad() {
132         
133         super.windowDidLoad()
134         
135         webView.addObserver(self, forKeyPath: "canGoBack", context: nil)
136         webView.addObserver(self, forKeyPath: "canGoForward", context: nil)
137         webView.applicationNameForUserAgent = AppDelegate.shared.appNameForUserAgent
138         webView.frameLoadDelegate = self
139     }
140     
141     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
142         
143         if keyPath == "canGoBack" {
144             
145             goSegment.setEnabled(webView.canGoBack, forSegment: 0)
146             
147             return
148         }
149         
150         if keyPath == "canGoForward" {
151             
152             goSegment.setEnabled(webView.canGoForward, forSegment: 1)
153             
154             return
155         }
156         
157         super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
158     }
159     
160     override func swipe(with event: NSEvent) {
161         
162         if event.deltaX > 0 && showsBookmarkList() {
163             
164             showBookmark(nil)
165         }
166         
167         if event.deltaX < 0 && !showsBookmarkList() {
168             
169             showBookmark(nil)
170         }
171     }
172     
173     private func move(bookmark: Bookmark) {
174         
175         if !canMovePage {
176             
177             AppDelegate.shared.createNewBrowser().move(bookmark: bookmark)
178             return
179         }
180         
181         webView.mainFrameURL = bookmark.urlString
182         windowContentSize = bookmark.windowContentSize
183         canResize = bookmark.canResize
184         canScroll = bookmark.canScroll
185         waitingBookmarkItem = bookmark
186     }
187     
188     private func showsBookmarkList() -> Bool {
189         
190         return webView.frame.origin.x > 0
191     }
192 }
193
194 // MARK: - IBAction
195 extension ExternalBrowserWindowController {
196     
197     override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
198         
199         guard let action = menuItem.action else { return false }
200         
201         switch action {
202         case Selector.addBookmark:
203             return webView.mainFrameURL != nil
204             
205         case Selector.showBookmark:
206             if showsBookmarkList() {
207                 
208                 menuItem.title = NSLocalizedString("Hide Bookmark", comment: "Menu item title, Hide Bookmark")
209                 
210             } else {
211                 
212                 menuItem.title = NSLocalizedString("Show Bookmark", comment: "Menu item title, Show Bookmark")
213             }
214             return true
215             
216         case Selector.selectBookmark:
217             return true
218             
219         case Selector.reloadContent:
220             return true
221             
222         default:
223             return false
224         }
225     }
226     
227     @IBAction func selectBookmark(_ sender: AnyObject?) {
228         
229         guard let item = sender?.representedObject as? Bookmark else { return }
230         
231         move(bookmark: item)
232     }
233     
234     @IBAction func reloadContent(_ sender: AnyObject?) {
235         
236         webView.reload(nil)
237     }
238     
239     @IBAction func goHome(_ sender: AnyObject?) {
240         
241         webView.mainFrameURL = "http://www.dmm.com/"
242     }
243     
244     @IBAction func clickGoBackSegment(_ sender: AnyObject?) {
245         
246         guard let cell = goSegment.cell as? NSSegmentedCell else { return }
247         
248         let tag = cell.tag(forSegment: cell.selectedSegment)
249         switch tag {
250         case 0:
251             webView.goBack(nil)
252             
253         case 1:
254             webView.goForward(nil)
255             
256         default:
257             break
258         }
259     }
260     
261     @IBAction func addBookmark(_ sender: AnyObject?) {
262         
263         guard let window = window else { return }
264         guard let bookmark = BookmarkManager.shared().createNewBookmark() else { return }
265         
266         bookmark.name = window.title
267         bookmark.urlString = webView.mainFrameURL
268         bookmark.windowContentSize = windowContentSize
269         bookmark.contentVisibleRect = contentVisibleRect
270         bookmark.canResize = canResize
271         bookmark.canScroll = canScroll
272         bookmark.scrollDelay = 0.5
273     }
274     
275     @IBAction func showBookmark(_ sender: AnyObject?) {
276         
277         guard let window = window else { return }
278         guard let _ = bookmarkListViwController else { return }
279         guard !bookmarkShowing else { return }
280         
281         bookmarkShowing = true
282         
283         var frame = bookmarkListView.frame
284         frame.size.height = webView.frame.size.height
285         bookmarkListView.frame = frame
286         
287         var newFrame = webView.frame
288         
289         if showsBookmarkList() {
290             
291             frame.origin.x = -200
292             newFrame.origin.x = 0
293             newFrame.size.width = window.frame.size.width
294             
295         } else {
296             
297             frame.origin.x = 0
298             newFrame.origin.x = 200
299             newFrame.size.width = window.frame.size.width - 200
300         }
301         
302         let webAnime: [NSViewAnimation.Key: Any] = [
303             .target: webView,
304             .endFrame: NSValue(rect: newFrame)
305         ]
306         let bookmarkAnime: [NSViewAnimation.Key: Any] = [
307             .target: bookmarkListView,
308             .endFrame: NSValue(rect: frame)
309         ]
310         let anime = NSViewAnimation(viewAnimations: [webAnime, bookmarkAnime])
311         anime.delegate = self
312         anime.start()
313     }
314     
315     @IBAction func scrollLeft(_ sender: AnyObject?) {
316         
317         var rect = contentVisibleRect
318         rect.origin.x += 1
319         contentVisibleRect = rect
320     }
321     
322     @IBAction func scrollRight(_ sender: AnyObject?) {
323         
324         var rect = contentVisibleRect
325         rect.origin.x -= 1
326         contentVisibleRect = rect
327     }
328     
329     @IBAction func scrollUp(_ sender: AnyObject?) {
330         
331         var rect = contentVisibleRect
332         rect.origin.y += 1
333         contentVisibleRect = rect
334     }
335     
336     @IBAction func scrollDown(_ sender: AnyObject?) {
337         
338         var rect = contentVisibleRect
339         rect.origin.y -= 1
340         contentVisibleRect = rect
341     }
342     
343     @IBAction func increaseWidth(_ sender: AnyObject?) {
344         
345         guard let window = window else { return }
346         
347         var frame = window.frame
348         frame.size.width += 1
349         window.setFrame(frame, display: true)
350     }
351     
352     @IBAction func decreaseWidth(_ sender: AnyObject?) {
353         
354         guard let window = window else { return }
355         
356         var frame = window.frame
357         frame.size.width -= 1
358         window.setFrame(frame, display: true)
359     }
360     
361     @IBAction func increaseHeight(_ sender: AnyObject?) {
362         
363         guard let window = window else { return }
364         
365         var frame = window.frame
366         frame.size.height += 1
367         frame.origin.y -= 1
368         window.setFrame(frame, display: true)
369     }
370     
371     @IBAction func decreaseHeight(_ sender: AnyObject?) {
372         
373         guard let window = window else { return }
374         
375         var frame = window.frame
376         frame.size.height -= 1
377         frame.origin.y += 1
378         window.setFrame(frame, display: true)
379     }
380 }
381
382 extension ExternalBrowserWindowController: BookmarkListViewControllerDelegate {
383     
384     func didSelectBookmark(_ bookmark: Bookmark) {
385         
386         move(bookmark: bookmark)
387     }
388 }
389
390 extension ExternalBrowserWindowController: NSAnimationDelegate {
391     
392     func animationDidEnd(_ animation: NSAnimation) {
393         
394         bookmarkShowing = false
395     }
396 }
397
398 extension ExternalBrowserWindowController: WebFrameLoadDelegate, WebPolicyDelegate {
399     
400     @objc func updateContentVisibleRect(_ timer: Timer) {
401         
402         guard let item = timer.userInfo as? Bookmark else { return }
403         
404         contentVisibleRect = item.contentVisibleRect
405     }
406     
407     func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
408         
409         if let waitingBookmarkItem = waitingBookmarkItem {
410             
411             Timer.scheduledTimer(timeInterval: waitingBookmarkItem.scrollDelay,
412                                  target: self,
413                                  selector: .updateContentVisibleRect,
414                                  userInfo: waitingBookmarkItem,
415                                  repeats: false)
416         }
417         waitingBookmarkItem = nil
418     }
419     
420     func webView(_ webView: WebView!,
421                  decidePolicyForNavigationAction actionInformation: [AnyHashable: Any]!,
422                  request: URLRequest!,
423                  frame: WebFrame!,
424                  decisionListener listener: WebPolicyDecisionListener!) {
425         
426         if actionInformation?[WebActionNavigationTypeKey] as? WebNavigationType == .linkClicked {
427             
428             if canMovePage {
429                 
430                 listener.use()
431             }
432             
433             return
434         }
435         
436         listener.use()
437     }
438 }