OSDN Git Service

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