OSDN Git Service

Applicatio Delegate を提供するプロパティを作成
[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 = NSMinX(frame)
76             newFrame.origin.y = NSMaxY(frame) - NSHeight(newFrame)
77             window.setFrame(newFrame, display: true)
78         }
79     }
80     var contentVisibleRect: NSRect {
81         get {
82             return webView.mainFrame.frameView.documentView.visibleRect
83         }
84         set {
85             webView.mainFrame.frameView.documentView.scrollToVisible(newValue)
86         }
87     }
88     
89     fileprivate var bookmarkShowing: Bool = false
90     fileprivate var waitingBookmarkItem: Bookmark?
91     
92     private lazy var bookmarkListViwController: BookmarkListViewController? = {
93         [weak self] in
94         guard let `self` = self else { return nil }
95         let controller = BookmarkListViewController()
96         self.bookmarkListView = controller.view
97         controller.delegate = self
98         
99         var frame = self.webView.frame
100         frame.size.width = 200
101         frame.origin.x = -200
102         self.bookmarkListView.frame = frame
103         self.webView.superview?.addSubview(self.bookmarkListView, positioned: .below, relativeTo: self.webView)
104         
105         return controller
106     }()
107     
108     override func windowDidLoad() {
109         super.windowDidLoad()
110         
111         webView.addObserver(self, forKeyPath: "canGoBack", context: nil)
112         webView.addObserver(self, forKeyPath: "canGoForward", context: nil)
113         webView.applicationNameForUserAgent = AppDelegate.shared.appNameForUserAgent
114         webView.frameLoadDelegate = self
115     }
116     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
117         if keyPath == "canGoBack" {
118             goSegment.setEnabled(webView.canGoBack, forSegment: 0)
119             return
120         }
121         if keyPath == "canGoForward" {
122             goSegment.setEnabled(webView.canGoForward, forSegment: 1)
123             return
124         }
125         
126         super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
127     }
128     override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
129         guard let action = menuItem.action else { return false }
130         switch action {
131         case Selector.addBookmark:
132             return webView.mainFrameURL != nil
133         case Selector.showBookmark:
134             if showsBookmarkList() {
135                 menuItem.title = NSLocalizedString("Hide Bookmark", comment: "Menu item title, Hide Bookmark")
136             } else {
137                 menuItem.title = NSLocalizedString("Show Bookmark", comment: "Menu item title, Show Bookmark")
138             }
139             return true
140         case Selector.selectBookmark:
141             return true
142         case Selector.reloadContent:
143             return true
144         default:
145             return false
146         }
147     }
148     override func swipe(with event: NSEvent) {
149         if event.deltaX > 0 && showsBookmarkList() {
150             showBookmark(nil)
151         }
152         if event.deltaX < 0 && !showsBookmarkList() {
153             showBookmark(nil)
154         }
155     }
156     
157     fileprivate func move(bookmark: Bookmark) {
158         if !canMovePage {
159             AppDelegate.shared.createNewBrowser().move(bookmark: bookmark)
160             return
161         }
162         
163         webView.mainFrameURL = bookmark.urlString
164         windowContentSize = bookmark.windowContentSize
165         canResize = bookmark.canResize
166         canScroll = bookmark.canScroll
167         waitingBookmarkItem = bookmark
168     }
169     fileprivate func showsBookmarkList() -> Bool {
170         return webView.frame.origin.x > 0
171     }
172     
173     // MARK: - IBAction
174     @IBAction func selectBookmark(_ sender: AnyObject?) {
175         guard let item = sender?.representedObject as? Bookmark
176             else { return }
177         move(bookmark: item)
178     }
179     @IBAction func reloadContent(_ sender: AnyObject?) {
180         webView.reload(nil)
181     }
182     @IBAction func goHome(_ sender: AnyObject?) {
183         webView.mainFrameURL = "http://www.dmm.com/"
184     }
185     @IBAction func clickGoBackSegment(_ sender: AnyObject?) {
186         guard let cell = goSegment.cell as? NSSegmentedCell
187             else { return }
188         let tag = cell.tag(forSegment: cell.selectedSegment)
189         switch tag {
190         case 0:
191             webView.goBack(nil)
192         case 1:
193             webView.goForward(nil)
194         default:
195             break
196         }
197     }
198     @IBAction func addBookmark(_ sender: AnyObject?) {
199         guard let window = window,
200             let bookmark = BookmarkManager.shared().createNewBookmark()
201             else { return }
202         bookmark.name = window.title
203         bookmark.urlString = webView.mainFrameURL
204         bookmark.windowContentSize = windowContentSize
205         bookmark.contentVisibleRect = contentVisibleRect
206         bookmark.canResize = canResize
207         bookmark.canScroll = canScroll
208         bookmark.scrollDelay = 0.5
209     }
210     @IBAction func showBookmark(_ sender: AnyObject?) {
211         guard let window = window,
212             let _ = bookmarkListViwController,
213             !bookmarkShowing
214             else { return }
215         bookmarkShowing = true
216         
217         var frame = bookmarkListView.frame
218         frame.size.height = webView.frame.size.height
219         bookmarkListView.frame = frame
220         
221         var newFrame = webView.frame
222         
223         if showsBookmarkList() {
224             frame.origin.x = -200
225             newFrame.origin.x = 0
226             newFrame.size.width = window.frame.size.width
227         } else {
228             frame.origin.x = 0
229             newFrame.origin.x = 200
230             newFrame.size.width = window.frame.size.width - 200
231         }
232         
233         let webAnime: [String : Any] = [
234             NSViewAnimationTargetKey: webView,
235             NSViewAnimationEndFrameKey: NSValue(rect: newFrame)
236         ]
237         let bookmarkAnime: [String : Any] = [
238             NSViewAnimationTargetKey: bookmarkListView,
239             NSViewAnimationEndFrameKey: NSValue(rect: frame)
240         ]
241         let anime = NSViewAnimation(viewAnimations: [webAnime, bookmarkAnime])
242         anime.delegate = self
243         anime.start()
244     }
245     @IBAction func scrollLeft(_ sender: AnyObject?) {
246         var rect = contentVisibleRect
247         rect.origin.x += 1
248         contentVisibleRect = rect
249     }
250     @IBAction func scrollRight(_ sender: AnyObject?) {
251         var rect = contentVisibleRect
252         rect.origin.x -= 1
253         contentVisibleRect = rect
254     }
255     @IBAction func scrollUp(_ sender: AnyObject?) {
256         var rect = contentVisibleRect
257         rect.origin.y += 1
258         contentVisibleRect = rect
259     }
260     @IBAction func scrollDown(_ sender: AnyObject?) {
261         var rect = contentVisibleRect
262         rect.origin.y -= 1
263         contentVisibleRect = rect
264     }
265     @IBAction func increaseWidth(_ sender: AnyObject?) {
266         guard let window = window else { return }
267         var frame = window.frame
268         frame.size.width += 1
269         window.setFrame(frame, display: true)
270     }
271     @IBAction func decreaseWidth(_ sender: AnyObject?) {
272         guard let window = window else { return }
273         var frame = window.frame
274         frame.size.width -= 1
275         window.setFrame(frame, display: true)
276     }
277     @IBAction func increaseHeight(_ sender: AnyObject?) {
278         guard let window = window else { return }
279         var frame = window.frame
280         frame.size.height += 1
281         frame.origin.y -= 1
282         window.setFrame(frame, display: true)
283     }
284     @IBAction func decreaseHeight(_ sender: AnyObject?) {
285         guard let window = window else { return }
286         var frame = window.frame
287         frame.size.height -= 1
288         frame.origin.y += 1
289         window.setFrame(frame, display: true)
290     }
291 }
292
293 extension ExternalBrowserWindowController: BookmarkListViewControllerDelegate {
294     func didSelectBookmark(_ bookmark: Bookmark) {
295         move(bookmark: bookmark)
296     }
297 }
298
299 extension ExternalBrowserWindowController: NSAnimationDelegate {
300     func animationDidEnd(_ animation: NSAnimation) {
301         bookmarkShowing = false
302     }
303 }
304
305 extension ExternalBrowserWindowController: WebFrameLoadDelegate, WebPolicyDelegate {
306     
307     func updateContentVisibleRect(_ timer: Timer) {
308         guard let item = timer.userInfo as? Bookmark else { return }
309         contentVisibleRect = item.contentVisibleRect
310     }
311     func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
312         if let waitingBookmarkItem = waitingBookmarkItem {
313             Timer.scheduledTimer(timeInterval: waitingBookmarkItem.scrollDelay, target: self, selector: .updateContentVisibleRect, userInfo: waitingBookmarkItem, repeats: false)
314         }
315         waitingBookmarkItem = nil
316     }
317     func webView(_ webView: WebView!, decidePolicyForNavigationAction actionInformation: [AnyHashable: Any]!, request: URLRequest!, frame: WebFrame!, decisionListener listener: WebPolicyDecisionListener!) {
318         if actionInformation?[WebActionNavigationTypeKey] as? WebNavigationType == .linkClicked {
319             if canMovePage {
320                 listener.use()
321             }
322             return
323         }
324         listener.use()
325     }
326 }
327