OSDN Git Service

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