// // KMBrowserWindowController.swift // PDF Reader Pro // // Created by wanjun on 2022/12/9. // import Cocoa @objcMembers class KMBrowserWindowController: CTBrowserWindowController { var rightSegmentControl: KMSegmentedBox? var filterType: Int = 0 var mainViewController: NSViewController? var isShowingTokenTimeOutAlert: Bool = false var currentTimer: Timer? private(set) var isMultiTabMode: Bool = false var rightMessageVC: KMVerificationMessageViewController! var rightToolbarItemView: NSView! private var homeVC: KMNHomeViewController? var savedNormalSetup: NSMutableDictionary = NSMutableDictionary() // 记录当前显示模式 // var _mwcFlags: MwcFlags = MwcFlags() deinit { KMPrint("KMBrowserWindowController deinit...") DistributedNotificationCenter.default().removeObserver(self) NotificationCenter.default.removeObserver(self) } override func loadWindow() { super.loadWindow() } override func windowDidLoad() { super.windowDidLoad() NSImage.makeTextAlignImages() NSImage.makeAdornImages() window?.backgroundColor = NSColor.km_init(hex: "#DFE1E5") self.window?.appearance = NSApp.appearance self.window?.titlebarAppearsTransparent = true self.window?.delegate = self rightTabStripView_.delete = self homeRightTabStripView_.delete = self rightTabStripView_.updateView() fileUploadPanel.delete = self homeRightTabStripView_.homeRightSearchField.delegate = self isMultiTabMode = true NotificationCenter.default.addObserver(self, selector: #selector(closeAllTabs(_:)), name: NSNotification.Name.init(rawValue: "KMTabControllerCloseAllTabs"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(openNewWindow(_:)), name: NSNotification.Name.init(rawValue: "KMTabControllerOpenNewWindow"), object: nil) DistributedNotificationCenter.default().addObserver(self, selector: #selector(_themeChanged), name: NSApplication.interfaceThemeChangedNotification, object: nil) updateViewColor() var tabbingMode = NSWindow.TabbingMode.automatic let openDocumentType = KMPreference.shared.openDocumentType if openDocumentType == .inSameWindow { tabbingMode = .preferred } else if openDocumentType == .newWindow { tabbingMode = .disallowed } #if VERSION_FREE if IAPProductsManager.default().isAvailableAllFunction() == false { tabbingMode = .disallowed } #endif let windowSizeOption = KMPreferenceManager.shared.openFileType if (windowSizeOption == .maxim) { Task { self.window?.setFrame(NSScreen.main?.visibleFrame ?? (self.window?.frame ?? .zero), display: false) } } if windowSizeOption == .fit { } } @objc func closeAction() { self.window?.performClose(nil) } override func windowShouldClose(_ sender: NSWindow) -> Bool { if let cnt = self.browser?.tabStripModel?.count(), cnt > 1 { if self.browser?.window != nil { self.browser?.windowDidBeginToClose() } return false } return true } override func windowWillClose(_ notification: Notification) { } override func windowDidResize(_ notification: Notification) { let model = self.browser?.tabStripModel if let cnt = model?.count(), cnt <= 0 { return } let document: KMMainDocument = model?.activeTabContents() as! KMMainDocument document.homeViewController?.rightInfoView.windowFrameUpdated() } override func layoutSubviews() { super.layoutSubviews() } @objc private func _themeChanged(_ sender: Notification) { let isDarkModel = KMAdvertisementConfig.isDarkModel() if isDarkModel { self.window?.appearance = .init(named: .darkAqua) } else { self.window?.appearance = .init(named: .aqua) } self.window?.contentView?.appearance = self.window?.appearance ?? .init(named: .aqua) self.interfaceThemeDidChanged(self.window?.appearance?.name ?? .aqua) } override func updateViewColor() { super.updateViewColor() window?.backgroundColor = KMTabAppearance.tabsViewBackgroundColor() } override var hasToolbar: Bool { get { return false } } func showSnapshots(setups: NSArray?) { let doc = self.document as? KMMainDocument doc?.mainViewController?.showSnapshots(setups: setups) } var km_browser: KMBrowser? { get { return self.browser as? KMBrowser } } // MARK: Private Methods func openDocumentWindow() -> Void { // MARK TODO: + 号开启 // self.browser.addHomeTabContents() self.tabStripView?.addTabButton?.layer?.backgroundColor = .clear self.km_browser?.addNewTabContents() } func selectTabContents(path filePath: String) -> KMMainDocument? { let document = NSDocumentController.shared.document(for: URL(fileURLWithPath: filePath)) var selectDocument: KMMainDocument? if document != nil { if document!.isKind(of: KMMainDocument.self) { selectDocument = document as! KMMainDocument } } return selectDocument } // MARK: Getter override var rightStripView: NSView! { get { if self.rightToolbarItemView == nil { self.rightToolbarItemView = NSView.init(frame: NSMakeRect(0, 10, 184, 40)) self.rightToolbarItemView.wantsLayer = true if self.rightMessageVC == nil { self.rightMessageVC = KMVerificationMessageViewController.init() } self.rightMessageVC.frameUpdateHandle = { [weak self] rect in guard let rsView = self?.rightToolbarItemView else { return } var superRect = rsView.frame if (superRect.size.width < self!.rightMessageVC.view.frame.size.width + 8) { superRect.size.width = self!.rightMessageVC.view.frame.size.width + 8 } if let supView = rsView.superview { let viewRect = supView.frame if (superRect.origin.x) + (superRect.size.width) > (viewRect.origin.x) + (viewRect.size.width) { let offsetValue = ((superRect.origin.x) + (superRect.size.width) - (viewRect.origin.x) - (viewRect.size.width)) superRect.origin.x -= offsetValue } } self?.rightToolbarItemView.frame = superRect } var rect = self.rightMessageVC.view.frame; rect.origin.x = NSWidth(self.rightToolbarItemView.frame) - rect.size.width - 8 rect.origin.y = (NSHeight(self.rightToolbarItemView.frame) - rect.size.height)/2 self.rightMessageVC.view.frame = rect self.rightMessageVC.view.autoresizingMask = [ .maxXMargin] self.rightToolbarItemView.addSubview(self.rightMessageVC.view) } return self.rightToolbarItemView } } override var homeRightStripView: NSView! { get { return homeRightTabStripView_ } } // MARK: Button Action func commandDispatch(_ sender: Any) -> Void { var needShowChooseWindow = false //#if VERSION_FREE //#if VERSION_DMG if (!IAPProductsManager.default().isAvailableAllFunction()) { needShowChooseWindow = true } //#endif if needShowChooseWindow { let preferenceNoteShow = UserDefaults.standard.bool(forKey: KMTabbingHintShowFlag) if preferenceNoteShow { } else { if !KMDataManager.default.isTabbingWin{ KMDataManager.default.isTabbingWin = true let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController() tabbingWin.selectCallBack = {[weak self] continueOrNot in KMDataManager.default.isTabbingWin = false let winC = self?.kmCurrentWindowC as? KMTabbingHintWindowController let newTab = winC?.newTabInWindowButton.state == .on if continueOrNot { if IAPProductsManager.default().isAvailableAllFunction() && newTab { self?.openDocumentWindow() } else { self?.reopenDocument(forPaths: nil) } } else { } } self.km_beginSheet(windowC: tabbingWin) } } } else { openDocumentWindow() } } func reopenDocument(forPaths path: String?) -> Void { if path == nil { let browser = KMBrowser.init() as KMBrowser browser.windowController = KMBrowserWindowController.init(browser: browser) browser.addHomeTabContents() browser.windowController.showWindow(self) }else { NSDocumentController.shared.km_safe_openDocument(withContentsOf: URL(fileURLWithPath: path!), display: true) { doc, open, err in } } } func closeAllTabs(_ sender: Any) -> Void { if let noti = sender as? NSNotification, noti.object is CTTabController { if let window_ = (noti.object as! CTTabController).view.window, window_.isEqual(to: self.window) == false { return } } if self.browser != nil { self.browser.closeAllTabs() } } func openNewWindow(_ sender: Any) -> Void { if let noti = sender as? NSNotification, noti.object is CTTabController { if let window_ = (noti.object as! CTTabController).view.window, window_.isEqual(to: self.window) == false { return } } // 分离 Tab let windowC = self.detachTab(toNewWindow: self.activeTabView() as? CTTabView) // 新增 home Tab (windowC as? CTBrowserWindowController)?.browser?.addHomeTabContentsWithDrag() windowC?.showWindow(nil) // if self.browser != nil { // let activeInt = self.browser.activeTabIndex() // let activeTab = self.browser.activeTabContents() // // self.browser.closeTab(at: activeInt, makeHistory: false) // // let browser: KMBrowser = KMBrowser.init() // browser.windowController = KMBrowserWindowController.init(browser: browser) // browser.addHomeTabContents() // browser.windowController.showWindow(self) // //// browser.add(activeTab, inForeground: false) //// browser.selectTab(at: 1) // if activeTab?.fileURL == nil { // return // } // let pdfDoc = CPDFDocument.init(url: (activeTab?.fileURL)!) // let document = NSDocumentController.shared.document(for: (activeTab?.fileURL)!) // KMMainDocument().tryToUnlockDocument(pdfDoc!) // // if ((pdfDoc?.isLocked)! == true) { // KMPasswordInputWindow.openWindow(window: self.window!, url: (activeTab?.fileURL)!) { result, password in // if result == .cancel { /// 关闭 // return // } // /// 解密成功 // var selectDocument: KMMainDocument? = nil // if ((document?.isKind(of: KMMainDocument.self)) != nil) { // selectDocument = (document as! KMMainDocument) // } // if selectDocument != nil { // let currentIndex = selectDocument?.browser.tabStripModel.index(of: selectDocument) // selectDocument?.browser.tabStripModel.selectTabContents(at: Int32(currentIndex!), userGesture: true) // if (selectDocument?.browser.window.isVisible)! as Bool { // selectDocument?.browser.window.orderFront(nil) // } else if (selectDocument?.browser.window.isMiniaturized)! as Bool { // selectDocument?.browser.window.orderFront(nil) // } // } else { // NSDocumentController.shared.km_safe_openDocument(withContentsOf: (activeTab?.fileURL)!, display: true) { document, _, error in // if (error == nil) { // (document as! KMMainDocument).mainViewController?.model.password = password // } // } // } // } // } else { // var selectDocument: KMMainDocument? = nil // if ((document?.isKind(of: KMMainDocument.self)) != nil) { // selectDocument = (document as! KMMainDocument) // } // if selectDocument != nil { // let currentIndex = selectDocument?.browser.tabStripModel.index(of: selectDocument) // selectDocument?.browser.tabStripModel.selectTabContents(at: Int32(currentIndex!), userGesture: true) // if (selectDocument?.browser.window.isVisible)! as Bool { // selectDocument?.browser.window.orderFront(nil) // } else if (selectDocument?.browser.window.isMiniaturized)! as Bool { // selectDocument?.browser.window.orderFront(nil) // } // } else { // NSDocumentController.shared.km_safe_openDocument(withContentsOf: (activeTab?.fileURL)!, display: true) { _, _, _ in // // } // } // } // } } func canMergeAllWindow() -> Bool { return self.fetchBrowserWindowControllers().count > 0 } fileprivate func fetchBrowserWindowControllers() -> [KMBrowserWindowController] { var windowArray: [KMBrowserWindowController] = [] for window in NSApp.windows { guard let windowController = window.windowController, windowController is KMBrowserWindowController else { continue } if let _tabScripC = (windowController as? KMBrowserWindowController)?.tabStripController, _tabScripC.viewsCount() <= 1 { continue } if (window.isVisible && (windowController.isEqual(to: self) == false)) { windowArray.append(windowController as! KMBrowserWindowController) } } return windowArray } func mergeAllWindow(_ sender: Any) { let windowArray = self.fetchBrowserWindowControllers() if (windowArray.count <= 0) { return } for windowC in windowArray { // 拼接窗口 [拼接窗口里的标签,除了home标签] self.append(windowC, toTabView: NSView()) if let browser = windowC.browser { if (browser.tabCount() <= 1 && browser.activeTabContents().isHome) { windowC.close() } } } } override func tabDidSelect(_ notification: Notification!) { super.tabDidSelect(notification) if let _userInfo = notification.userInfo, let _newContents = _userInfo[CTTabNewContentsUserInfoKey] as? KMMainDocument { _newContents.addWindowController(self) _newContents.mainViewController?.showMeasureFloatingWindowsIfNeed() } if let _userInfo = notification.userInfo, let _oldContents = _userInfo[CTTabContentsUserInfoKey] as? KMMainDocument { _oldContents.mainViewController?.hideMeasureFloatingWindows() } } override func layoutTabContentArea(_ frame: NSRect) { super.layoutTabContentArea(frame) self.rightStripView.autoresizingMask = [.minXMargin, .minYMargin] } override func openDocument(_ sender: Any!) { guard let _window = self.window else { KMPrint("openDocument error: window is nil.", beep: true) return } if let cnt = self.browser?.tabCount(), cnt > 1{ if !IAPProductsManager.default().isAvailableAllFunction() { if !KMDataManager.default.isTabbingWin{ KMDataManager.default.isTabbingWin = true let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController() tabbingWin.selectCallBack = { [weak self] continueOrNot in KMDataManager.default.isTabbingWin = false if continueOrNot { self?.reopenDocument(forPaths: nil) } else { } } self.km_beginSheet(windowC: tabbingWin) } return } if KMPreference.shared.openDocumentType == .newWindow { self.reopenDocument(forPaths: nil) return } } NSOpenPanel.km_open_multi_success(_window) { panel in panel.allowedFileTypes = KMTools.imageExtensions + KMTools.pdfExtensions } completion: { urls in var imageUrls: [URL] = [] for url in urls { if KMTools.isPDFType(url.pathExtension.lowercased()) { NSDocumentController.shared.km_safe_openDocument(withContentsOf: url, display: true) { _, _, _ in } } else { imageUrls.append(url) } } if imageUrls.isEmpty == false { NSApplication.ShowImageToPDFWindow(urls: imageUrls) } } } } // MARK: - KMInterfaceThemeChangedProtocol extension KMBrowserWindowController: KMInterfaceThemeChangedProtocol { func interfaceThemeDidChanged(_ appearance: NSAppearance.Name) { Task { @MainActor in self.updateViewColor() let selector = #selector(interfaceThemeDidChanged) let mainWindow = self.window var responder = mainWindow?.firstResponder while (responder != nil) { // KMPrint("res: \(responder)") // if self.isEqual(to: responder) { responder = responder?.nextResponder continue } if let res = responder?.responds(to: selector), res { responder?.perform(selector, with: appearance) } responder = responder!.nextResponder } let childWins = self.window?.childWindows ?? [] for childWin in childWins { if let winC = childWin.windowController { if winC.responds(to: selector) { winC.perform(selector, with: appearance) } } else { if childWin.responds(to: selector) { childWin.perform(selector, with: appearance) } } } } } } // MARK: - KMToolbarRightViewDelegate extension KMBrowserWindowController: KMToolbarRightViewDelegate { func pdfRightSegmentedControlAction(_ sender: KMSegmentedBox?) { DispatchQueue.main.async { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) } } func userInfoButtonAction(_ sender: NSButton) { } func homeRefreshButtonAction(_ sender: NSButton?) { self.layoutSubviews() } func homeUploadButtonAction(_ sender: NSButton) { } func homeMenuSortAction(_ sender: NSPopUpButton) { } func homeMenuFilterAction(_ sender: NSPopUpButton) { } } // MARK: - KMUploadFileDelegate extension KMBrowserWindowController: KMUploadFileDelegate { // override func cancelOperation(_ sender: Any?) { // // } } // MARK: - NSSearchFieldDelegate extension KMBrowserWindowController: NSSearchFieldDelegate { func controlTextDidChange(_ obj: Notification) { } func controlTextDidEndEditing(_ obj: Notification) { } func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool { var result = false return result } } // MARK: - // MARK: Menu Actions extension KMBrowserWindowController { func canResponseDocumentAction() -> Bool { if (self.browser == nil) { return false } guard let _ = self.browser.activeTabContents() as? KMMainDocument else { return false } return true } } // MARK: - // MARK: File Menu