// // KMMainViewController.swift // PDF Reader Pro // // Created by wanjun on 2022/12/15. // import Cocoa @objcMembers class KMMainViewController: KMBaseViewController, NSTextFieldDelegate,KMPresentationTopViewControllerDelegate { @IBOutlet var PDFContendView: NSView! @IBOutlet var centerContentView: NSView! @IBOutlet var listView: CPDFListView! @IBOutlet var secondaryPdfView: KMSecondaryPDFView? @IBOutlet weak var readContentView: NSView! @IBOutlet weak var tipCurrentPageBox: KMBox! @IBOutlet weak var rightView: NSView! @IBOutlet weak var leftView: NSView! @IBOutlet weak var mianSplitView: KMSplitView! @IBOutlet weak var pdfSplitView: KMSplitView! @IBOutlet weak var newPDFSplitView: KMSplitView! @IBOutlet weak var pdfContentView: NSView! @IBOutlet weak var pdfSplitSecondView: NSBox! @IBOutlet weak var locationPageView: NSView! @IBOutlet weak var tipLabel: NSTextField! @IBOutlet weak var toplayoutConstraint: NSLayoutConstraint! @IBOutlet var childToolbarController: KMToolbarViewController! @IBOutlet var toolbarController: KMToolbarController! @IBOutlet weak var toolbarBox: NSBox! @IBOutlet weak var heightOffset: NSLayoutConstraint! //阅读模式界面 @IBOutlet weak var readModelView: KMReadModelView! @IBOutlet weak var bottomAreaView: KMBox! @IBOutlet weak var readModelViewWidthConstraint: NSLayoutConstraint! //页码显示器 @IBOutlet weak var pageNumberDisplayView: KMPageNumberDisplayView! @IBOutlet weak var tipCurrentPageBoxWidthConstraint: NSLayoutConstraint! @IBOutlet weak var topTipBox: NSBox! @IBOutlet weak var exitFullButton: NSButton! var model = KMMainModel() var isReadMode: Bool = false var readAlertView: CustomAlertView? var readLeftMethodType: BotaType = .None var readLeftPanelOpen = false var readLastLeftPanWidth = 0.0 var readLeftViewShowPanel = false var readRightPanelOpen = false var readToolbarType: KMToolbarViewType = .None var readToolbarItemIdentifier: String = "" var readToolMode: CToolMode = .textToolMode var readAnnotationType: CAnnotationType = .unkown var readSubViewType: RightSubViewType = .None //自动滚动 var autoFlowOptionsSheetController: KMAutoFlowOptionsSheetController? //Search var searchIndex: Int = 0 //Form var formAlertView: KMFormAlertView? //Secure var secureAlertView: KMSecureAlertView? //对比 var isCompareModel: Bool = false { didSet { self.toolbarController.updataItemVisible() } } //合并 var mergeWindowController: KMMergeWindowController? //水印 var watermarkWindowController: KMWatermarkWindowController? //密码弹窗 var passwordWindow: KMPasswordInputWindow? //对比 var compressWIndowControllerNew: KMCompressWIndowControllerNew? // var securityWindowController: KMSecurityWindowController? //引导 var guideInfoWindowController: KMGuideInfoWindowController? var presentationTopViewController: KMPresentationTopViewController? //春季活动 var recommondPopWindowVC: KMRecommondPopWindow? private var _needSave = false var needSave: Bool { set { _needSave = newValue if (_needSave == false) { self.clearIsPDFDocumentEdited() } } get { return _needSave } } var isPDFDocumentEdited: Bool { get { return self.model.isPDFDocumentEdited } } var leftSideViewController: KMLeftSideViewController = KMLeftSideViewController.init(type: KMLeftMethodMode()) var rightSideViewController: KMRightSideViewController! var searchResults: [KMSearchMode] = [] var mwcFlags: MwcFlags = MwcFlags() var document: CPDFDocument? var myDocument: NSDocument? weak var browserWindowController: KMBrowserWindowController? //慎直接使用这个方法 var cropSettingWindowController: KMCropSettingWindowController! var currentWindowController: NSWindowController! var savedNormalSetup: NSMutableDictionary = NSMutableDictionary() //数字签名 var digitalSignController: KMPDFDigitalSignViewController? var redactController: KMPDFRedactViewController! let CPDFOfficeLeftSidePaneWidthKey = "CPDFOfficeLeftSidePaneWidthKey" let CPDFOfficeRightSidePaneWidthKey = "CPDFOfficeRightSidePaneWidthKey" var extract: KMExtractImageWindowController? var functionWidth: Double { get { if self.isReadMode { if !self.model.isShowBOTA { return 0 } } return 48-4 } } var pageNumber: UInt? var openSecondaryPdfView: KMSecondaryViewController? var secondaryPdfContentView: NSView? var lastSplitPDFHeight: Float = 0.0 var pdfEditController: KMPDFEditViewController? { get { return self.getPDFEditController() } } var autoSaveTimer: Timer? private var _documentFirstLoad: Bool = true var eventMonitor: Any? var keyEventMonitor: Any? var mouseRightMenuEvent: NSEvent? var aiTranslationWindow: KMAITranslationWindowController? var aiTranslationConfirWC: KMAITranslationConfirmWindowController? lazy private var homeVC: KMHomeViewController? = { let vc = KMHomeViewController() return vc }() private var background_mask: NSView? fileprivate var _secureOptions: [CPDFDocumentWriteOption : Any]? var secureOptions: [CPDFDocumentWriteOption : Any]? { get { return self._secureOptions } } var documentAttribute: [CPDFDocumentAttribute : Any]? fileprivate var _removeSecureFlag = false var removeSecureFlag: Bool { get { return self._removeSecureFlag } } fileprivate var _saveWatermarkFlag = false var saveWatermarkFlag: Bool { get { return self._saveWatermarkFlag } } private var mainWindow_: NSWindow? var mainWindow: NSWindow? { get { return self.mainWindow_ } set { self.mainWindow_ = newValue } } let editPDFHanddler = KMEditPDfHanddler() var distanceMeasureInfoWindowController: CDistanceMeasureInfoWindowController? var perimeterMeasureInfoWindowController: CPerimeterMeasureInfoWindowController? var areaMeasureInfoWindowController: CAreaMeasureInfoWindowController? var srHanddler: KMSearchReplaceHanddler = KMSearchReplaceHanddler() deinit { NotificationCenter.default.removeObserver(self) self.listView.delegate = nil self.listView.document?.delegate = nil self.editPDFHanddler.clearData() self.removeEventMonitor() self.removeKeyEventMonitor() } override func awakeFromNib() { super.awakeFromNib() self.addBackgroundMaskView() self.PDFContendView.backgroundColor(NSColor.km_init(hex: "FFFFFF")) listView.delegate = self listView.pdfListViewDelegate = self // listView.editingConfig().isSupportMultipleSelectEditingArea = true if (document != nil) { // if (self.document!.isLocked) { // // } else { // } // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.listView.document = self.document self.listView.document?.delegate = self // } let autoScale = listView.autoScales if !autoScale { listView.scaleFactor = 1.0 } } self.initPDFLeftViewVC() self.initRightSideView() self.toolbarController.listView = self.listView self.toolbarController.mainViewController = self self.leftSideViewController.mainViewController = self self.newPDFSplitView.delegate = self } override func viewDidAppear() { super.viewDidAppear() //春季活动 if KMAdvertisementManager.manager.appClosedCount == 1 { if ((KMAdvertisementManager.manager.info.popWindowContent) != nil) { if KMAdvertisementManager.manager.info.popWindowContent!.content!.count > 0 { let info = KMAdvertisementManager.manager.info.popWindowContent!.content?.first if KMAdvertisementManager.checkAdvertisementValid(info!) { self.loadRecommondPopWindow() } } } KMAdvertisementManager.manager.appClosedCount = 2 } //刷新前一页后一页按钮 self.updateNextAndPreViousButtonState() KMLightMemberManager.manager.canShowAdvancedView = false // Task { @MainActor in // await KMLightMemberManager.manager.canUseAdvanced(needNetworking: true) // } self.addEventMonitor() self.view.window?.makeFirstResponder(self.listView) // 更新属性页面的信息 NotificationCenter.default.post(name: KMInfoWindowC.windowDidBecomeMainNotification, object: self.myDocument) self.interfaceThemeDidChanged(self.view.window?.appearance?.name ?? (NSApp.appearance?.name ?? .aqua)) if (self.document == nil) { return } if (self.document == nil || self.document!.isLocked == false) { self.loadFunctionGuide() } if (self.document?.isLocked == false) { if self.model.needConvertNotes && self.tabViewIsDragging() == false { self.showConvertNotesProgress() } return } if (self.view.window == nil) { return } if (self.model.password != nil) { if let data = self.listView.document?.unlock(withPassword: self.model.password), data { self.model.isSaveKeyChain = false if self.model.needConvertNotes && self.tabViewIsDragging() == false { self.showConvertNotesProgress() } return } } DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { if self.view.window != nil && self.tabViewIsDragging() == false { self.passwordWindow = KMPasswordInputWindow.openWindow(window: self.view.window!, url: self.document!.documentURL) { [weak self] result , password in if (result == .cancel) { // self.browserWindowController?.browser?.closeTab() (self?.myDocument as? KMMainDocument)?.browser?.closeTab() return } self?.model.isSaveKeyChain = true self?.listView?.document = self?.document self?.document?.unlock(withPassword: password) } } else { if self.model.needConvertNotes && self.tabViewIsDragging() == false { self.showConvertNotesProgress() } } } } override func viewWillDisappear() { super.viewWillDisappear() if self.interactionMode != .presentation { self.removeEventMonitor() } self.editPDFHanddler.hiddenWindows() } override func viewWillLayout() { super.viewWillLayout() if (KMTools.isFullScreen(self.view.window ?? NSWindow())) { // 全屏 self.exitFullButton.isHidden = false self.listView.backgroundColor = KMPreferenceManager.shared.displayBackgroundFullScreenColor } else { self.exitFullButton.isHidden = true self.listView.backgroundColor = KMPreferenceManager.shared.displayBackgroundNormalColor } if let guideWC = self.guideInfoWindowController{ var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size guideWC.show() } } override func viewDidLoad() { super.viewDidLoad() mwcFlags.settingUpWindow = 1 toolbarController.delegate = self self.editPDFHanddler.viewC = self self.srHanddler.pdfView = self.listView //TODO: 先让项目运行,看后面怎么调整这段逻辑,目前最外层是 KMBrowserWindowController toolbarBox.contentView = toolbarController.view if (UserDefaults.standard.object(forKey: CPDFOfficeLeftSidePaneWidthKey) != nil) { UserDefaults.standard.set(256, forKey: CPDFOfficeLeftSidePaneWidthKey) UserDefaults.standard.synchronize() } if (UserDefaults.standard.object(forKey: CPDFOfficeRightSidePaneWidthKey) != nil) { UserDefaults.standard.set(256, forKey: CPDFOfficeRightSidePaneWidthKey) UserDefaults.standard.synchronize() } let position = mianSplitView.maxPossiblePositionOfDivider(at: 1) mianSplitView.setPosition(position, ofDividerAt: 0) mianSplitView.setPosition(mianSplitView.minPossiblePositionOfDivider(at: 0), ofDividerAt: 0) pdfSplitView.setPosition(mianSplitView.maxPossiblePositionOfDivider(at: 1), ofDividerAt: 0) self.locationPageView.wantsLayer = true; self.locationPageView.layer?.backgroundColor = NSColor(red: 189.0/255.0, green: 223.0/255.0, blue: 253.0/255.0, alpha: 1).cgColor self.tipLabel.stringValue = NSLocalizedString("Please use the scroll bar, thumbnail tool to locate the target page, click or box the area to select the target range.", comment: "") if (KMPreferenceManager.shared.openLastUnlockedDocumentWhenAppStart) { if (self.listView.document != nil) { let pageNumber = KMPreferenceManager.shared.getPageNumber(forKey: self.listView.document?.documentURL.path ?? "") let pageScale = KMPreferenceManager.shared.getPageScale(forKey: self.listView.document?.documentURL.path ?? "") if (pageNumber != nil && pageNumber! >= 0 && pageNumber! < (self.listView.document?.pageCount ?? 0)) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { if (pageScale != nil) { self.listView.scaleFactor = CGFloat(pageScale!) } self.listView.go(toPageIndex: pageNumber!, animated: false) } } else { self._goToFirstPageForFristAppear() } } } else { self._goToFirstPageForFristAppear() } //阅读页面 readModelView.delegate = self pageNumberDisplayView.delegate = self tipCurrentPageBox.moveCallback = { [unowned self] mouseEntered, mouseBox in if !isReadMode { if mouseEntered { self.pageNumberDisplayView.hover = true } else { self.pageNumberDisplayView.hover = false } } } NotificationCenter.default.addObserver(self, selector: #selector(rename(_:)), name: NSNotification.Name.init(rawValue: "KMTabControllerRename"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(closeTab(_:)), name: NSNotification.Name.init(rawValue: "KMTabControllerCloseTabs"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(showInFinder(_:)), name: NSNotification.Name.init(rawValue: "KMTabControllerShowInFinder"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(preferenceDidChangeNotification), name: KMPreferenceManager.didChangeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(documentDidUnlockNotification), name: Notification.Name("CPDFDocumentDidUnlockNotification"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(annotationsAttributeHasChange), name: NSNotification.Name.CPDFListViewAnnotationsAttributeHasChange, object:nil) NotificationCenter.default.addObserver(self, selector: #selector(applicationWillTerminateNotification), name: NSApplication.willTerminateNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(KMPDFViewCurrentPageDidChangedNotification), name: NSNotification.Name.init(rawValue: "KMPDFViewCurrentPageDidChanged"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(CPDFDocumentPageCountChangedNotification), name: NSNotification.Name.init(rawValue: "CPDFDocumentPageCountChangedNotification"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(CEditPDFToolModeChangeStateUnkownNotification), name: Notification.Name.init("CEditPDFToolModeChangeStateUnkown"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handlePageChangedNotification), name: NSNotification.Name.CPDFViewPageChanged, object: self.listView) NotificationCenter.default.addObserver(self, selector: #selector(handleDisplayBoxChangedNotification), name: NSNotification.Name.CPDFViewDisplayBoxChanged, object: self.listView) // 互动模式 NotificationCenter.default.addObserver(self, selector: #selector(willEnterInteractionModeNotification), name: NSWindow.willEnterInteractionModeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(didEnterInteractionModeNotification), name: NSWindow.didEnterInteractionModeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(willShowFullScreenNotification), name: NSWindow.willShowFullScreenNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(didShowFullScreenNotification), name: NSWindow.didShowFullScreenNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(didAddContentViewNotification), name: NSWindow.didAddContentViewNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(addAutoSaveEvent), name: AutoSaveManager.kTimeValueChangedNotificationName, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(didRemoveAnnotationNotification), name: NSNotification.Name.CPDFPageDidRemoveAnnotation, object: nil) Task { self.addAutoSaveEvent() } self.toolbarController.selectItem(KMDocumentAnnotationToolbarItemIdentifier) self.closeRightPane() self.addKeyEventMonitor() self.addAdsBannerView() //检测OCR包是否需要更新 #if VERSION_DMG // KMResourceDownloadManager.manager.checkDocumentAIVersion() #endif // Open snapshots? var snapshotSetups: NSArray? // if (hasWindowSetup) // snapshotSetups = [savedNormalSetup objectForKey:SNAPSHOTS_KEY]; // else if ([sud boolForKey:SKRememberSnapshotsKey]) if KMPreferenceManager.shared.rememberSnapshot { // snapshotSetups = [[SKBookmarkController sharedBookmarkController] snapshotsForRecentDocumentAtURL:[(NSDocument *)[self document] fileURL]]; if let fileUrl = (self.myDocument as? KMMainDocument)?.fileURL { snapshotSetups = SKBookmarkController.shared().snapshotsForRecentDocument(at: fileUrl) as NSArray? } } if let cnt = snapshotSetups?.count, cnt > 0 { if let data = self.listView?.document?.isLocked, data { self.savedNormalSetup.setObject(snapshotSetups as Any, forKey: "snapshots" as NSCopying) } else { self.showSnapshots(setups: snapshotSetups) } } let readModel = UserDefaults.standard.bool(forKey: "kKMPDFViewIsReadMode") if readModel == true { self.openReadModel() } let hasWindowSetup = savedNormalSetup.count > 0 if UserDefaults.standard.dictionary(forKey: KMDefaultPDFDisplaySettingsKey) != nil { let pdfSettings: NSDictionary = hasWindowSetup ? savedNormalSetup : UserDefaults.standard.dictionary(forKey: KMDefaultPDFDisplaySettingsKey)! as NSDictionary self.applyPDFSettings(pdfSettings) } else { self.applyPDFSettings(savedNormalSetup) } //文字 let fontManager = NSFontManager.shared fontManager.target = self fontManager.action = #selector(changeFont(_:)) } //MARK: - PDFListView func initPDFLeftViewVC() { var frame = self.leftView.frame frame.size.width += 44 self.leftView.frame = frame leftSideViewController.isFirst = true leftSideViewController.listView = self.listView leftSideViewController.view.frame = CGRect(x: 0, y:0 , width: self.leftView.frame.size.width, height: self.leftView.frame.size.height) leftSideViewController.view.autoresizingMask = [.height,.width] leftSideViewController.delegate = self self.leftView.addSubview(leftSideViewController.view) } func initRightSideView() { self.rightSideViewController = KMRightSideViewController.init() self.rightSideViewController.view.frame = CGRect(x: 0, y: 0, width: self.rightView.frame.width, height: self.rightView.frame.size.height) self.rightSideViewController.view.autoresizingMask = [.height,.width] self.rightSideViewController.listView = self.listView // self.rightSideViewController.view.isHidden = true self.rightSideViewController.isHidden = true self.rightSideViewController.delegate = self self.rightView.addSubview(self.rightSideViewController.view) self.rightSideViewController.mainController = self self.rightSideViewController.propertyDidChange = { [weak self] model in if let anno = model as? CSelfSignAnnotation { self?.leftSideViewController.refreshUIForAnnoAttributeDidChange(anno, attributes: nil) } } } func addAdsBannerView() { #if VERSION_FREE if !KMMemberInfo.shared.isMemberAllFunction { guard let document = self.listView.document else { return } if !document.isLocked { KMAdsManager.defaultManager.beginSheetModalForView(self.readContentView, directions: .down, adPosY: 30, animated: false) { pageIndex in } } NotificationCenter.default.addObserver(self, selector: #selector(purchaseStateUpdateNoti), name: NSNotification.Name(rawValue: "KMIAPProductPurchasedNotification"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(purchaseStateUpdateNoti), name: NSNotification.Name(rawValue: "kDeviceActivateNotification"), object: nil) } #endif } // MARK: Private Methods // 是否阿拉伯语言 private func _isArabicLanguage() -> Bool { return NSLocalizedString("Right click a color and select “Change Color...“.", comment: "") == "انقر بزر الماوس الأيمن فوق اللون وحدد \"تغيير اللون...\"." } internal func removeNotifications() { NotificationCenter.default.removeObserver(self) self.leftSideViewController.clearAnnotationFilterData() self.leftSideViewController.clearNotification() } func checkShouldAutoOpenLeftVC() { if KMPreference.shared.showLeftSideBar == false { return } if self.model.leftPanelOpen { return } let readModel = UserDefaults.standard.bool(forKey: "kKMPDFViewIsReadMode") if readModel == true { return } DispatchQueue.main.async { self.leftSideViewController.showThumbnail() self.toolbarController.findItem(KMLeftControlToolbarItemIdentifier)?.isSelected = true } } func applyLeftSideWidth(_ leftSideWidth: CGFloat, rightSideWidth: CGFloat) -> Void { mianSplitView.setPosition(leftSideWidth, ofDividerAt: 0) mianSplitView.setPosition(mianSplitView.maxPossiblePositionOfDivider(at: 1) - mianSplitView.dividerThickness - rightSideWidth, ofDividerAt: 1) self.model.lastLeftPanWidth = leftSideWidth self.model.lastRightPanWidth = rightSideWidth } internal var removeAllAnnotationsStore = KMPDFViewRemoveAllAnnotationsStore() internal func removeAllAnnotations() { let alert = NSAlert() alert.messageText = NSLocalizedString("This will permanently remove all annotations. Are you sure to continue?", comment: "") alert.addButton(withTitle: NSLocalizedString("Yes", comment:"")) alert.addButton(withTitle: NSLocalizedString("No", comment:"")) if (alert.runModal() != .alertFirstButtonReturn) { return } DispatchQueue.main.async { self.removeAllAnnotationsStore.store(t: self.listView) } } @objc func cancelMeasureType() { self.hideMeasureFloatingWindows() self.toolbarController?.findItem(KMToolbarMeasureItemIdentifier)?.isSelected = false } func hideMeasureFloatingWindows() { if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.hideFloatingWindow() } else if perimeterMeasureInfoWindowController?.window?.isVisible == true { perimeterMeasureInfoWindowController?.hideFloatingWindow() } else if areaMeasureInfoWindowController?.window?.isVisible == true { areaMeasureInfoWindowController?.hideFloatingWindow() } } func showMeasureFloatingWindowsIfNeed() { let toolMode = self.listView?.toolMode ?? .none if toolMode != .measureToolMode { return } let type = self.listView?.annotationType ?? .none if type == .line { self.distanceMeasureInfoWindowController?.window?.orderFront(nil) } else if type == .polyLine { self.perimeterMeasureInfoWindowController?.window?.orderFront(nil) } else if type == .polyGon { self.areaMeasureInfoWindowController?.window?.orderFront(nil) } else if type == .square { self.areaMeasureInfoWindowController?.window?.orderFront(nil) } } // MARK: Set Methods var setDocument: CPDFDocument? { get { return document } set { if document != newValue { document = newValue } listView.document = document listView.document?.delegate = self self.listView.layoutDocumentView() self.leftSideViewController.refreshUIForDocumentChanged() } } var setPageNumber: UInt { get { return pageNumber! } set { let pageCount = listView.document?.pageCount ?? 0 var value = newValue if value > pageCount { value = pageCount } if value > 0 && listView.currentPage().pageIndex() != value-1 { listView.go(to: listView.document?.page(at: value-1)) } if pageNumber != value { pageNumber = value } } } // MARK: - 标记密文 func enterRedact() { if KMMemberInfo.shared.isMemberAllFunction == false { let winC = KMProductCompareWC.shared winC.kEventName = "Reading_Redact_BuyNow" KMMemberInfo.shared.advancedFunctionUsage() return } if self.listView.document?.allowsPrinting == false || self.listView.document?.allowsCopying == false { Task { _ = await KMAlertTool.runModel(message: KMLocalizedString("This is a secured document. Editing is not permitted.", nil)) } return } if self.hasEnterRedact() { self.exitRedact() return } self.commitEditingIfNeed() self.leftSideViewController.thumbnailTableView.isEnabled = false self.leftSideViewController.tocOutlineView.isEnabled = false self.leftSideViewController.noteOutlineView.isEnabled = false self.leftSideViewController.findTableView.isEnabled = false self.leftSideViewController.groupedFindTableView.isEnabled = false self.leftSideViewController.snapshotTableView.isEnabled = false let ttsWindowC = KMTTSWindowController.share if ttsWindowC.pdfView?.document?.documentURL.path == self.listView.document?.documentURL.path { if let data = ttsWindowC.window?.isVisible, data { ttsWindowC.stopSpeaking() ttsWindowC.close() } } NSColorPanel.shared.showsAlpha = false redactController = KMPDFRedactViewController(url: self.listView.document!.documentURL, password: self.listView.document?.password) self.addChild(redactController) self.PDFContendView.addSubview(redactController.view) redactController.view.frame = self.PDFContendView.bounds redactController.view.autoresizingMask = [.width, .height] self.listView.isHidden = true redactController.scaleFactor = self.listView.scaleFactor redactController.titleBack = { [weak self] title in self?.view.window?.title = title } redactController.callback = { [weak self] result, currentPageIndex, saveResult, saveUrl in self?.listView.go(toPageIndex: self!.redactController.redactPdfView.currentPageIndex, animated: false) if result == false { // 退出 self?.exitRedact() return } let controller = self?._getPDFRedactController() controller?.redactPdfView.newAddAnnotation.removeAll() self?.exitRedact() if saveResult { let newDocument = CPDFDocument(url: saveUrl) if let data = newDocument?.isLocked, data { newDocument?.unlock(withPassword: self?.listView.document?.password ?? "") } self?.document = newDocument self?.listView.document = newDocument self?.listView.layoutDocumentView() } } redactController.setCurrentPageIndex(self.listView.currentPageIndex) } func exitRedact() { self.leftSideViewController.thumbnailTableView.isEnabled = true self.leftSideViewController.tocOutlineView.isEnabled = true self.leftSideViewController.noteOutlineView.isEnabled = true self.leftSideViewController.findTableView.isEnabled = true self.leftSideViewController.groupedFindTableView.isEnabled = true self.leftSideViewController.snapshotTableView.isEnabled = true let controller = self._getPDFRedactController() if let data = controller { if data.redactPdfView.newAddAnnotation.count > 0 { KMAlertTool.runModel(message: "", informative: KMLocalizedString("There are unapplied redactions in this file. Exit will not save redaction.", nil), buttons: [KMLocalizedString("Exit", nil), KMLocalizedString("Cancel", nil)]) { response in if response == .alertFirstButtonReturn { controller?.redactPdfView.newAddAnnotation.removeAll() self.exitRedact() } } return } } NSColorPanel.shared.showsAlpha = true self.toolbarController.findItem(KMDocumentRedactToolbarItemIdentifier)?.isSelected = false // self.toolbarController.toolbarType = .None // self.listView.toolMode = .moveToolMode controller?.redactPdfView.resignMonitor() controller?.view.removeFromSuperview() controller?.removeFromParent() self.listView.isHidden = false // self.listView.layoutDocumentView() // self.view.window?.makeFirstResponder(self.listView) self.listView.annotationType = .unkown } func hasEnterRedact() -> Bool { return self._getPDFRedactController() != nil } //MARK: - AI func showAITypeChooseView(aiConfigType: AIConfigType) -> Void { if (self.document != nil) { AIChatInfoManager.defaultManager.currentFilePath = (self.document?.documentURL.path)! } else { AIChatInfoManager.defaultManager.currentFilePath = "" } let windowVC: AINewConfigWindowController = AINewConfigWindowController.currentWC() windowVC.chooseCurFileHandle = {[unowned self] windowVC in if AIChatInfoManager.defaultManager.currentFilePath.isEmpty == false { let documentArray = NSDocumentController.shared.documents var didFileEdit: Bool = false var curDoc: KMMainDocument! for document in documentArray { if document.fileURL?.path == AIChatInfoManager.defaultManager.currentFilePath { didFileEdit = document.isDocumentEdited curDoc = document as! KMMainDocument break } } if didFileEdit { let tempFileURL = FileManager.default.temporaryDirectory.appendingPathComponent(AIChatInfoManager.defaultManager.currentFilePath.lastPathComponent) if FileManager.default.fileExists(atPath: tempFileURL.path) { do { try FileManager.default.removeItem(at: tempFileURL) } catch { } } if curDoc != nil { curDoc.mainViewController?.SaveTempPDFDocumentToURLPath(tempPath: tempFileURL.path) } } windowVC.window?.becomeMain() } } if windowVC.window?.isVisible == true && windowVC.didSetOriginFrame == true { } else { var windowRect = windowVC.window?.frame windowRect!.origin.x = NSMaxX(self.view.window!.frame) - (windowRect?.size.width)! windowRect!.origin.y = NSMaxY(self.view.window!.frame) - (windowRect?.size.height)! - 64 windowVC.window?.setFrame(windowRect!, display: true) windowVC.didSetOriginFrame = true } windowVC.eventLabel = "AITools_Tbr" windowVC.showWindow(nil) if (aiConfigType != .none) { windowVC.eventLabel = "AITools_Start" if self.listView.currentSelection?.string()?.isEmpty == false { windowVC.setCurrentPDFSelection(self.listView.currentSelection.string()) } windowVC.chooseAIFunctionWithType(aiConfigType) } } @objc func aiTipIconViewShowStateChangeNoti() { } //MARK: - 引导 func loadFunctionGuide() -> Void { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { if self.view.window != nil { self.loadOpenFileFunctionGuide(.openFileNormal) } } } func loadOpenFileFunctionGuide(_ showType: KMGuideInfoType) -> Void { if showType == .openFileNormal && KMGuideInfoWindowController.availableShow(.openFileNormal) { let leftPanelItem:KMToolbarItemView = self.toolbarController.findItem("KMLeftControlToolbarItemIdentifier")! self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .openFileNormal guideWC.openPanelRect = (self.view.window?.contentView?.convert(leftPanelItem.frame, from: leftPanelItem.superview)) ?? .zero guideWC.window?.collectionBehavior = [.canJoinAllSpaces] guideWC.normalGuideFinishHandle = { [weak self] windowVC in let rightPanelItem = self?.toolbarController.findItem(KMRightControlToolbarItemIdentifier) let digitalPanelItem = self?.toolbarController.findItem(KMDocumentSignToolbarItemIdentifier) if let data = rightPanelItem, data.isHidden { let view = self?.toolbarController.mainToolBarView?.toolbar?.moreButton windowVC.rightPanelRect = (self?.view.window?.contentView?.convert(view?.frame ?? .zero, from: view?.superview)) ?? .zero } else { windowVC.rightPanelRect = (self?.view.window?.contentView?.convert(rightPanelItem?.frame ?? .zero, from: rightPanelItem?.superview)) ?? .zero } guideWC.digitalBoxRect = (self?.view.window?.contentView?.convert(digitalPanelItem?.frame ?? .zero, from: digitalPanelItem?.superview)) ?? .zero } guideWC.finishHandle = { [weak self] windowVC, type in if type == .windowNewFinish || type == . windowDigitalFinish { self?.checkFirstTrialController() } } guideWC.openFileToggleHandle = { [weak self] windowVC, type in self?.checkFirstTrialController() } var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } else if showType == .digitalSignGuide && KMGuideInfoWindowController.availableShow(.digitalSignGuide) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .digitalSignGuide guard let digitalPanelItem = self.toolbarController.findItem(KMDocumentSignToolbarItemIdentifier) else { return } guideWC.digitalBoxRect = (self.view.window?.contentView?.convert(digitalPanelItem.frame, from: digitalPanelItem.superview))! guideWC.window?.collectionBehavior = [.canJoinAllSpaces] guideWC.finishHandle = { [weak self] windowVC, type in self?.checkFirstTrialController() } var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } else if showType == .pdfCompareGuide && KMGuideInfoWindowController.availableShow(.pdfCompareGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .pdfCompareGuide guard let digitalPanelItem = self.toolbarController.findItem(KMDocumentSignToolbarItemIdentifier) else { return } guard let win = self.view.window else { return } guideWC.digitalBoxRect = (win.contentView?.convert(digitalPanelItem.frame, from: digitalPanelItem.superview)) ?? .zero let compareItem = self.toolbarController.findItem(KMToolbarComparisonItemIdentifier) guideWC.compareItemRect = (win.contentView?.convert(compareItem?.frame ?? .zero, from: compareItem?.superview)) ?? .zero guideWC.finishHandle = { [weak self] winC, type in if type == .windowNewFinish { DispatchQueue.main.async { self?.loadOpenFileFunctionGuide(.measureGuide) } return } } guideWC.window?.collectionBehavior = [.canJoinAllSpaces] var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } } else if showType == .measureGuide && KMGuideInfoWindowController.availableShow(.measureGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guard let _ = self.view.window else { return } guideWC.type = .measureGuide guard let digitalPanelItem = self.toolbarController.findItem(KMDocumentSignToolbarItemIdentifier) else { return } guideWC.digitalBoxRect = (self.view.window?.contentView?.convert(digitalPanelItem.frame, from: digitalPanelItem.superview)) ?? .zero let compareItem:KMToolbarItemView = self.toolbarController.findItem(KMToolbarMeasureItemIdentifier)! guideWC.compareItemRect = (self.view.window?.contentView?.convert(compareItem.frame, from: compareItem.superview)) ?? .zero guideWC.window?.collectionBehavior = [.canJoinAllSpaces] var rect = self.view.window?.frame ?? .zero rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } } else if showType == .convertGuide && KMGuideInfoWindowController.availableShow(.convertGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .convertGuide guard let digitalPanelItem = self.toolbarController.findItem(KMDocumentSignToolbarItemIdentifier) else { return } guard let win = self.view.window else { return } guideWC.digitalBoxRect = (self.view.window?.contentView?.convert(digitalPanelItem.frame, from: digitalPanelItem.superview)) ?? .zero guideWC.purchaseHandle = { [weak self] windowVC in #if VERSION_DMG if KMMemberInfo.shared.isMemberAllFunction { if KMMemberInfo.shared.isPermitConvert { //Convert: self?.showAllConvertWindow(convertT: .Word) } else { let limitWC = KMPurchaseLimitWindowController.currentLimitWC() limitWC.continueBlock = { windowController in } limitWC.window?.center() limitWC.showWindow(nil) } } else { KMProductCompareWC.shared.orientation = false KMProductCompareWC.shared.showWindow(nil) } #else if KMMemberInfo.shared.isMemberAllFunction == true { if KMMemberInfo.shared.isPermitConvert == true { } else { var vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 1) vc.showWindow(nil) } } else { KMMemberInfo.shared.advancedFunctionUsage() } #endif } guideWC.window?.collectionBehavior = [.canJoinAllSpaces] var rect = self.view.window?.frame ?? .zero rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } } else { } } func checkFirstTrialController() -> Void { #if VERSION_DMG //打开文档后引导相关 if VerificationManager.default().status == .none { let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" let lastVersion = UserDefaults.standard.object(forKey: "SKLastTrialVersionMainDocumentLaunchedKey") as? String ?? "" if lastVersion.isEmpty || lastVersion != appVersion { UserDefaults.standard.setValue(appVersion, forKey: "SKLastTrialVersionMainDocumentLaunchedKey") UserDefaults.standard.synchronize() KMProductCompareWC.shared.orientation = false KMProductCompareWC.shared.showWindow(nil) } } #endif } // MARK: - 页面编辑 open func enterPageEdit(_ pages: [Int] = []) { if let doc = self.listView?.document { if doc.allowsCopying == false || doc.allowsPrinting == false { KMBaseWindowController.checkPassword(url: doc.documentURL, type: .owner) { result, pwd in if result && pwd.isEmpty == false { self.listView?.document?.unlock(withPassword: pwd) Task { @MainActor in self.enterPageEdit(pages) } } else { self.exitPageEdit() } } return } } //选中page var tPages = pages if tPages.count == 0 { if self.leftSideViewController.type.methodType == .Thumbnail { tPages = self.leftSideViewController.thumb_fetchSelectedRows() ?? [self.listView.currentPageIndex] } } if (hasEnterPageEdit()) { exitPageEdit() return } if (self.toolbarController != nil && self.toolbarController.mainToolBarView != nil) { let toolBarView: KMToolbarViewController = self.toolbarController.mainToolBarView! for (key, value) in toolBarView.toolbarItems { if (key == KMRightControlToolbarItemIdentifier || key == KMLeftControlToolbarItemIdentifier) { (value as! KMToolbarItemView).unEnabled = true } } } self.editPDFHanddler.clearData() let controller = KMPDFEditViewController(self.listView.document) controller.selectedPages = tPages controller.listView = self.listView self.addChild(controller) self.PDFContendView.addSubview(controller.view) controller.view.frame = self.PDFContendView.bounds controller.view.autoresizingMask = [.width,.height] self.listView.isHidden = true controller.itemClick = { [weak self] index, params in if (index == 1) { /// 双击退出 self?.enterEditMode(self!.leftSideViewController, []) DispatchQueue.main.async { let pageIndex: Int = params.first as! Int self?.listView.go(toPageIndex: pageIndex, animated: true) } } else if (index == 2) { // 打印 self?.showPrintWindow(pageRange: KMPrintPageRange(type: .custom, selectPages: params.first as! [Int])) } } controller.documentEditedCallback = { [weak self] params in self?.recordIsPDFDocumentEdited() } controller.selectionDidChange = { selectedIndexs in var indexSet = IndexSet() for indexPath in selectedIndexs { indexSet.insert(indexPath.item) } if indexSet.count != 0 { // self?.leftSideViewController.thumbnailViewController.selectPages(indexs: indexSet, needScroll: true) // self?.listView.go(toPageIndex: indexSet.first!, animated: false) } } } open func exitPageEdit() { if (self.toolbarController != nil && self.toolbarController.mainToolBarView != nil) { let toolBarView: KMToolbarViewController = self.toolbarController.mainToolBarView! for (key, value) in toolBarView.toolbarItems { if (key == KMRightControlToolbarItemIdentifier || key == KMLeftControlToolbarItemIdentifier) { (value as! KMToolbarItemView).unEnabled = false } } } self.toolbarController.findItem(KMDocumentPageToolbarItemIdentifier)?.isSelected = false let editController = getPDFEditController() if (editController == nil) { return } self.listView.annotationType = .highlight // FIXME: - sdk修复插入特定文档crash后,这行代码可以去掉 self.leftSideViewController.model.insertedDocumentSet.formUnion(editController?.model.insertedDocumentSet ?? []) editController?.view.removeFromSuperview() editController?.removeFromParent() self.listView.isHidden = false self.listView.layoutDocumentView() self.view.window?.makeFirstResponder(self.listView) self.listView.annotationType = .unkown self.listView.go(toPageIndex: editController!.listViewCurrentIndex, animated: false) if let data = editController?.isEdited, data { self.leftSideViewController.reloadThumbnailDataIfNeed() self.leftSideViewController.note_reloadDataIfNeed() self.leftSideViewController.refreshUIOfOutlineIfNeed() self.leftSideViewController.refreshUIOfSeachListIfNeed() self.leftSideViewController.refreshUIOfBookmarkIfNeed() } } open func hasEnterPageEdit() -> Bool { return self.getPDFEditController() != nil } // MARK: - Edit PDF func enterEditPDF() { self.editPDFHanddler.enterEditPDF() } // MARK: - 数字签名 func hasShowDigitalSign() -> Bool { return self.digitalSignController?.view.superview != nil } func canEnterDigitalSign() -> Bool { guard let doc = self.listView?.document else { return false } return doc.allowsPrinting && doc.allowsCopying } func enterDigitalSign() { self.listView.toolMode = .textToolMode if self.hasShowDigitalSign() { self.exitDigitalSign() } else { if self.needSaveDocument() { self.saveDocumentWithProgressAlert { [unowned self] params in if (self.listView.document != nil) { self.showDigitalSignWindow(withFilePathURL: self.listView.document.documentURL) } } return } if (self.listView.document != nil) { self.showDigitalSignWindow(withFilePathURL: self.listView.document.documentURL) } } } func exitDigitalSign() { self.digitalSignController?.view.removeFromSuperview() // self.digitalSignController = nil // KMDocumentDigitalSignToolbarItemIdentifier self.toolbarController.findItem(KMDocumentSignToolbarItemIdentifier)?.isSelected = false } func showDigitalSignWindow(withFilePathURL fileURL: URL) { if KMMemberInfo.shared.isMemberAllFunction == false { let winC = KMProductCompareWC.shared winC.kEventName = "Reading_DigitalSign_BuyNow" KMMemberInfo.shared.advancedFunctionUsage() return } if hasShowDigitalSign() { self.exitDigitalSign() } var currentPageIndex = listView.document?.index(for: listView.currentPage()) ?? 0 var password: String = "" self.toolbarController.toolbarType = .None // if digitalSignController == nil { password = listView.document?.password ?? "" digitalSignController = KMPDFDigitalSignViewController() // } digitalSignController?.currentPageIndex = Int(currentPageIndex) digitalSignController?.url = listView.document?.documentURL digitalSignController?.password = password digitalSignController?.scaleFactor = listView.scaleFactor digitalSignController?.titleChangeBlock = { title, index in currentPageIndex = UInt(index) } digitalSignController?.buttonActionBlock = { [weak self] type, isChanged in if type == .cancel { if let page = self?.listView?.document?.page(at: currentPageIndex) { self?.listView.go(to: page) } self?.exitDigitalSign() } } if let digitalSignView = digitalSignController?.view, let splitViewSuperview = mianSplitView.superview { digitalSignView.frame = splitViewSuperview.bounds digitalSignView.autoresizingMask = [.width, .height] splitViewSuperview.addSubview(digitalSignView) digitalSignController?.setCurrentPageIndex(Int(currentPageIndex)) } } // MARK: - Toolbar func toolbarItemClickForExitMode(_ toolbarItem: KMToolbarItemView) { if(toolbarItem.itemIdentifier != KMDocumentPageToolbarItemIdentifier) { if (hasEnterPageEdit()) { self.exitPageEdit() } } if toolbarItem.itemIdentifier != KMDocumentRedactToolbarItemIdentifier { if self.hasEnterRedact() { self.exitRedact() } } if toolbarItem.itemIdentifier != KMDocumentDigitalSignToolbarItemIdentifier { if self.hasShowDigitalSign() { self.exitDigitalSign() } } if toolbarItem.itemIdentifier != KMDocumentEditToolbarItemIdentifier && toolbarItem.itemIdentifier != KMRightControlToolbarItemIdentifier && toolbarItem.itemIdentifier != KMLeftControlToolbarItemIdentifier { // self.editPDFHanddler.clearData() self.commitEditingIfNeed() } } // MARK: - Private Methods private func getPDFEditController() -> KMPDFEditViewController? { var editController: KMPDFEditViewController? for controller in self.children { if (controller.isKind(of: KMPDFEditViewController.self)) { editController = (controller as! KMPDFEditViewController) break } } return editController } private func _getPDFRedactController() -> KMPDFRedactViewController? { var controller: KMPDFRedactViewController? for childC in self.children { if (childC.isKind(of: KMPDFRedactViewController.self)) { controller = (childC as! KMPDFRedactViewController) break } } return controller } private func addBackgroundMaskView() { self.removeBackgroundMaskView() if let superview = self.mianSplitView.superview { let view = NSView() superview.addSubview(view) view.frame = superview.bounds view.autoresizingMask = [.width, .height] view.wantsLayer = true view.layer?.backgroundColor = .white self.background_mask = view } } private func removeBackgroundMaskView() { self.background_mask?.removeFromSuperview() self.background_mask = nil } private func _goToFirstPageForFristAppear() { DispatchQueue.main.asyncAfter(wallDeadline: .now()+0.1) { self.listView.go(toPageIndex: 0, animated: false) } } func isPDFPageCountExceedsLimit(filePath: String) -> Bool { let url = URL(fileURLWithPath: filePath) guard let document = PDFDocument(url: url) else { return false } let pageCount = document.pageCount return pageCount > 30 } // MARK: - Redact 【标记密文】 func exeRedactConfirm(_ type: KMRedactConfirmType, callback: @escaping () -> ()?) { let windowController = KMRedactConfirmWindowController(type) self.currentWindowController = windowController self.view.window?.beginSheet(windowController.window!) windowController.itemClick = { [weak self] index in if (index == 2) { /// 取消 self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil callback() return } self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil let panel = NSSavePanel() panel.nameFieldStringValue = "[新文件]"+((self?.listView.document?.documentURL.lastPathComponent) ?? "") let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.isExtensionHidden = true panel.beginSheetModal(for: (self?.view.window!)!) { response in if response != .OK { callback() return } if (type == .redactOne) { let anno = self!.listView.activeAnnotation if (anno == nil || (anno?.isKind(of: CPDFRedactAnnotation.self)) == false) { callback() return } (anno as! CPDFRedactAnnotation).applyRedaction() } else if (type == .redactAll) { self?.listView.document?.applyRedactions() } else if (type == .eraserOne) { let anno = self!.listView?.activeAnnotation if (anno == nil || (anno?.isKind(of: CPDFRedactAnnotation.self)) == false) { callback() return } anno?.page.erasureRedact(from: anno!.bounds) } else if (type == .eraserAll) { KMRedactTools.eraserDocument((self?.listView.document)!) { result, errorAnno in if (result == false) { callback() return } } } self!.listView.document?.write(to: panel.url) if (button.state == .on) { NSDocumentController.shared.openDocument(withContentsOf: panel.url!, display: true) { document, alreadyOpen, error in } } else { NSWorkspace.shared.activateFileViewerSelecting([panel.url!]) } callback() } } } // MARK: - Secure 【安全】 public func showSecureLimitTip() { self.hiddenSecureLimitTip() if self.secureAlertView == nil { self.secureAlertView = KMSecureAlertView() self.secureAlertView?.show(in: self.listView) self.secureAlertView?.closeAction = { [unowned self] view in self.hiddenSecureLimitTip() self.removeFromAlertView() self.showFormAlertView() } self.secureAlertView?.passwordAction = { [unowned self] view in self.removeOwnerPassword() self.removeFromAlertView() self.showFormAlertView() } } } func removeOwnerPassword() { guard let doc = self.listView?.document else { NSSound.beep() return } if doc.allowsCopying && doc.allowsPrinting { NSSound.beep() return } _ = KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: doc.documentURL) { [weak self] result, password in if result == .cancel { /// 关闭 return } /// 解密成功 self?.hiddenSecureLimitTip() self?.model.isSaveKeyChain = false self?.listView.document?.unlock(withPassword: password) } } public func hiddenSecureLimitTip() { self.secureAlertView?.removeFromSuperview() self.secureAlertView = nil } //MARK: - Form func showFormAlertView() { if (formAlertView == nil) { formAlertView = KMFormAlertView() formAlertView?.isCloseSecureView = self.secureAlertView != nil ? false : true formAlertView?.showInView(self.listView) } else { self.removeFromAlertView() } } func removeFromAlertView() { formAlertView?.removeFromSuperview() formAlertView = nil } override func mouseMoved(with event: NSEvent) { self.view.window?.mouseMoved(with: event) } func savePageNumberIfNeed() { if (KMPreferenceManager.shared.openLastUnlockedDocumentWhenAppStart) { let scaleFactor = self.listView?.scaleFactor ?? 0 if scaleFactor <= 0 { return } if self.listView.document != nil { KMPreferenceManager.shared.setPageNumber(self.listView.currentPageIndex, forKey: self.listView.document.documentURL.path) KMPreferenceManager.shared.setPageScale(Float(self.listView.scaleFactor), forKey: self.listView.document.documentURL.path) } } } // MARK: - 显示合并窗口 public func showMergeWindow(url: URL? = nil, _ password: String?) { DispatchQueue.main.async { var documentURL = url if documentURL == nil { documentURL = self.listView.document?.documentURL } guard let _url = documentURL else { return } guard let document = PDFDocument(url: _url) else { return } self.mergeWindowController = KMMergeWindowController(document: document, password: password ?? "") self.mergeWindowController!.oriDucumentUrl = self.listView.document?.documentURL self.mergeWindowController!.pageIndex = self.listView.currentPageIndex self.mergeWindowController!.cancelAction = { [unowned self] controller in self.view.window?.endSheet(mergeWindowController!.window!) } self.mergeWindowController!.mergeAction = { [unowned self] controller, filePath in self.view.window?.endSheet(mergeWindowController!.window!) } self.toolbarController.cancelSelected(KMToolbarToolMergeItemIdentifier) self.view.window?.beginSheet(self.mergeWindowController!.window!) } } // MARK: - 显示加密弹窗 public func showSecureWindow(_ url: URL) { self.securityWindowController = KMSecurityWindowController(windowNibName: "KMSecurityWindowController") guard let securityWindowController = securityWindowController else { return } securityWindowController.documentURL = self.listView.document?.documentURL securityWindowController.batchAction = { [unowned self] controller, files in self.view.window?.endSheet((securityWindowController.window)!) self.toolbarController.cancelSelected(KMToolbarToolCompressItemIdentifier) let batchWindowController = KMBatchOperateWindowController.sharedWindowController let batchOperateFile = KMBatchOperateFile(filePath: self.document?.documentURL.path ?? "", type: .AddPassword) batchWindowController.switchToOperateType(.AddPassword, files: [batchOperateFile]) batchWindowController.window?.makeKeyAndOrderFront("") } securityWindowController.doneAction = { [unowned self] controller, options, attribute in let openPanel = NSOpenPanel() openPanel.canChooseFiles = false openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.beginSheetModal(for: NSWindow.currentWindow()) { (result) in if result == NSApplication.ModalResponse.OK { for fileURL in openPanel.urls { let document = CPDFDocument(url: self.document?.documentURL) if document != nil { document!.setDocumentAttributes(attribute) let path = fileURL.path.stringByAppendingPathComponent(url.deletingPathExtension().lastPathComponent) + "_SetPassword" + "." + url.pathExtension let success = document!.write(to: NSURL(fileURLWithPath: path) as URL, withOptions: options) if success { self.view.window?.endSheet((securityWindowController.window)!) NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)]) } } } } } } securityWindowController.cancelAction = { [unowned self] controller in self.view.window?.endSheet((securityWindowController.window)!) } NSWindow.currentWindow().beginSheet(securityWindowController.window!) } // MARK: - 保存文档 internal func needSaveDocument() -> Bool { if (self.isPDFDocumentEdited) { return self.isPDFDocumentEdited } if (self.needSave) { return self.needSave } let document: KMMainDocument? = self.myDocument as? KMMainDocument if (document?.isDocumentEdited == nil || document?.isDocumentEdited == false) { return false } return true } internal func saveDocument(overlookDocumentIfEdited overlook: Bool = false) { let document: KMMainDocument? = self.myDocument as? KMMainDocument if (overlook) { document?.save(nil) return } if (self.isPDFDocumentEdited) { self.clearIsPDFDocumentEdited() self.needSave = false document?.save(nil) return } if (document?.isDocumentEdited == nil || document?.isDocumentEdited == false) { return } document?.save(nil) } internal func asyncSaveDocument(overlookDocumentIfEdited overlook: Bool = false, callback:@escaping KMCommonBlock) { let document: KMMainDocument? = self.myDocument as? KMMainDocument if (overlook) { DispatchQueue.main.async { document?.save(nil) callback() } return } if (self.isPDFDocumentEdited) { self.clearIsPDFDocumentEdited() self.needSave = false DispatchQueue.main.async { document?.save(nil) callback() } return } if (document?.isDocumentEdited == nil || document?.isDocumentEdited == false) { callback() return } DispatchQueue.main.async { document?.save(nil) callback() } } internal func saveDocumentWithProgressAlert(callback:@escaping KMCommonBlock) { // 显示进度 AutoSaveManager.manager.isSaving = true self.showProgressWindow(message: NSLocalizedString("Save", comment: "") + "PDF") self.progressC?.maxValue = 3.0 self.progressC?.increment(by: 1.0) // 保存文档 self.asyncSaveDocument { [weak self] params in // 执行进度 [假进度] self?.progressC?.increment(by: 1.0) self?.progressC?.increment(by: 1.0) // DispatchQueue.main.async { DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { // 隐藏进度 self?.hiddenProgressWindow() DispatchQueue.main.asyncAfter(deadline: .now()+1) { AutoSaveManager.manager.isSaving = false } // 回调 callback() } } } func SaveTempPDFDocumentToURLPath(tempPath: String) { self.document?.write(toFile: tempPath) } // MARK: - 定时保存 func addAutoSaveEvent() { if (self.autoSaveTimer != nil) { self.autoSaveTimer?.invalidate() self.autoSaveTimer = nil } if self.document != nil { self.autoSaveTimer = Timer.scheduledTimer(withTimeInterval: AutoSaveManager.manager.timeInterval * 60, repeats: true, block: { [weak self] timer in self?.autoSaveTimerAction(timer) }) } self.checkAutoSaveInfo() } func checkAutoSaveInfo() { guard let cnt = AutoSaveManager.manager.autoSavePaths?.count, cnt > 0 else { return } if AutoSaveManager.manager.autoSaveAlertShow { return } AutoSaveManager.manager.autoSaveDidEndAction = false AutoSaveManager.manager.autoSaveAlertShow = true let blockSaveWindow = AutoSavePopController() blockSaveWindow.cancelHandle = { [weak self] windowController in AutoSaveManager.manager.autoSaveDidEndAction = true AutoSaveManager.manager.clearCache() self?.km_quick_endSheet() } blockSaveWindow.confirmHandle = { [weak self] windowController in self?.km_quick_endSheet() self?.saveAutoSaveInfo() } self.km_beginSheet(windowC: blockSaveWindow) } func saveAutoSaveInfo() { let openPanel = NSOpenPanel() openPanel.canChooseDirectories = true openPanel.canChooseFiles = false openPanel.allowsMultipleSelection = false let win = NSApp.keyWindow != nil ? NSApp.keyWindow : self.view.window openPanel.beginSheetModal(for: win!) { result in if (result == .OK) { let folderPath = openPanel.url?.path ?? openPanel.url?.absoluteString for path in AutoSaveManager.manager.opendPaths ?? [] { let _path = path as? String var newPath = "\(folderPath ?? "")/\(_path?.lastPathComponent ?? "")" newPath = self.getValidFilePath(newPath) do { try FileManager.default.moveItem(atPath: _path ?? "", toPath: newPath) } catch { NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: newPath)]) } } AutoSaveManager.manager.clearCache() } AutoSaveManager.manager.autoSaveDidEndAction = true } } func autoSaveTimerAction(_ timer: Timer) { if (self.document == nil || self.listView?.document?.documentURL.path == nil) { return } if AutoSaveManager.manager.autoSaveDidEndAction == false { //防止提示弹窗出现后,未进行任何操作又进入自动保存的机制 return } if let data = self.document?.isLocked, data { return } if AutoSaveManager.manager.autoSaveEnabled == false { return } let documentArray = NSDocumentController.shared.documents var didFileEdit = false for doc in documentArray { if doc.fileURL?.path == self.document?.documentURL.path { didFileEdit = doc.isDocumentEdited break } } if (didFileEdit == false) { return } AutoSaveManager.manager.isSaving = true let savePath = AutoSaveManager.manager.autoSaveWithPath(self.listView?.document?.documentURL.path ?? "") if (!self.document!.isLocked) { self.document?.write(to: URL(fileURLWithPath: savePath)) } DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { AutoSaveManager.manager.isSaving = false } } func removeAutoSaveInfo() { if self.autoSaveTimer != nil { self.autoSaveTimer?.invalidate() self.autoSaveTimer = nil } if AutoSaveManager.manager.autoSaveDidEndAction == false { //防止提示弹窗出现后,未进行任何操作又进入自动保存的机制 return } if AutoSaveManager.manager.autoSaveEnabled == false { return } if self.document == nil || self.listView?.document?.documentURL.path == nil { return } AutoSaveManager.manager.removeAutoSavePath(self.listView?.document?.documentURL.path ?? "") } // MARK: - 选择 PDFDisplay 模式 @objc public func selectDisplay(display: KMPDFDisplayType, viewSettingIsReload: Bool = true) { let toolModel = self.listView.toolMode self.isReadMode = false switch display { case .singlePage: self.listView.setDisplay(.singlePage) break case .singlePageContinuous: self.listView.setDisplay(.singlePageContinuous) break case .twoUp: self.listView.setDisplay(.twoUp) break case .twoUpContinuous: self.listView.setDisplay(.twoUpContinuous) break case .bookMode: self.listView.displaysAsBook = true self.listView.displayTwoUp = true self.listView.displayDirection = .horizontal break case .bookContinuous: self.listView.displaysAsBook = true self.listView.displayTwoUp = true self.listView.displayDirection = .vertical break case .readModel: self.openReadModel() break case .readContinuous: self.openReadModel() break } self.listView.layoutDocumentView() // if (viewSettingIsReload && self.leftSideViewController.panelSetViewController.isViewLoaded) { // self.leftSideViewController.panelSetViewController.reloadListViewModel() // } if (toolModel == .editPDFToolMode) { if self.rightSideViewController.eidtPDFImageProperty != nil { self.rightSideViewController.eidtPDFImageProperty?.cancelCutImageAction("") self.rightSideViewController.isHidden = true self.closeRightPane() } } } // MARK: - 选择缩放模式 @objc public func selectZoom(_ type: KMPDFZoomType) { switch type { case .width: self.listView.autoScales = true // self.listView.autoScales = false break case .fit: // self.listView.autoScales = !self.listView.autoScales if let pageHeight = self.listView.currentPage()?.size.height, pageHeight > 0 { let pdfviewHeight = self.listView.bounds.size.height self.listView.scaleFactor = pdfviewHeight/pageHeight self.listView.autoScales = false } break case .actualSize: if self.listView.scaleFactor != 1.0 { self.listView.scaleFactor = 1.0 self.listView.autoScales = false } break } } internal func createPdf(index:Int) { if index == 1 { self.homeVC?.openBlankPage() } else if index == 4 { self.homeVC?.importFromCamera() } else if index == 5 { self.homeVC?.importFromScanner() } else if index == 3 { self.homeVC?.importFromWebPage() } else if index == 2 { self.homeVC?.newFromImages() } } // MARK - Event 监听 private func addEventMonitor() { if (self.eventMonitor != nil) { self.removeEventMonitor() } // KMPrint("已添加事件监听") self.eventMonitor = NSEvent.addLocalMonitorForEvents(matching: [.scrollWheel, .leftMouseDown]) { [weak self] event in if (event.type == .scrollWheel && event.modifierFlags.contains(.option)) { // Alt + 鼠标滚轮 self?.listView.magnifyWheel(event) return nil } else if event.type == .leftMouseDown { let point = event.locationInView(self?.listView ?? NSView()) let presentationDrawView = self?.listView.presentationDrawView if let data = self?.interactionMode, data == .presentation,CGRectContainsPoint(self?.listView.frame ?? .zero, point),presentationDrawView?.isHidden == true { // 幻灯片模式下 if point.x >= (self?.listView.frame.maxX ?? 0) / 2 { let can = self?.listView?.canGoToNextPage() ?? false if can { self?.listView.goToNextPage(nil) } } else { let can = self?.listView?.canGoToPreviousPage() ?? false if can { self?.listView.goToPreviousPage(nil) } } return nil } } return event } } func addKeyEventMonitor() { if (self.keyEventMonitor != nil) { self.removeKeyEventMonitor() } keyEventMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in // print(event.keyCode) if event.keyCode == 53 { if let data = self?.interactionMode, data == .presentation { // 幻灯片模式下 if let data = self?.canExitPresentation(), data { let mainDocument = self?.myDocument as? KMMainDocument let browserWindowController = mainDocument?.browser?.windowController as? KMBrowserWindowController browserWindowController?.exitFullscreen() } return nil } if self?.listView.toolMode == .editPDFToolMode { if self != nil { //使用editingSelectionString获取内容文字 if self!.listView.editingAreas() != nil { if self!.listView.editingAreas().count > 0 && self!.listView.isEditable() { self!.listView.clearEditingSelectCharItem() } else if self!.listView.editingAreas().count > 0 { if self?.listView.annotationType == .addImage || self?.listView.annotationType == .addText { let textItem = self?.toolbarController.findItem(KMToolbarAddTextEditPDFItemIdentifier) let imageItem = self?.toolbarController.findItem(KMToolbarAddImageEditPDFItemIdentifier) textItem?.isSelected = false imageItem?.isSelected = false } self?.rightSideViewController.isHidden = true self?.listView.endEditIsRemoveBlock(with: self!.listView.editingAreas().first as? CPDFEditArea) self?.listView.updateEditing([]) self?.listView.isEditImage = false self?.listView.setNeedsDisplayPageViewFor(self!.listView.currentPage()) if self?.listView.annotationType == .addImage { self?.listView.change([.text, .image]) } self?.listView.annotationType = .editTextImage self?.closeRightPane() } else if(self?.listView.annotationType == .addImage || self!.listView.annotationType == .addText) { if self?.listView.annotationType == .addImage || self?.listView.annotationType == .addText { let textItem = self?.toolbarController.findItem(KMToolbarAddTextEditPDFItemIdentifier) let imageItem = self?.toolbarController.findItem(KMToolbarAddImageEditPDFItemIdentifier) textItem?.isSelected = false imageItem?.isSelected = false } self?.rightSideViewController.isHidden = true self?.listView.setShouAddEdit([]) self?.listView.change([.text, .image]) self?.listView.annotationType = .editTextImage self?.closeRightPane() } } else { if self?.listView.annotationType == .addImage || self?.listView.annotationType == .addText { let textItem = self?.toolbarController.findItem(KMToolbarAddTextEditPDFItemIdentifier) let imageItem = self?.toolbarController.findItem(KMToolbarAddImageEditPDFItemIdentifier) textItem?.isSelected = false imageItem?.isSelected = false } } } } } else { if let data = self?.interactionMode, data == .presentation { // 幻灯片模式下 self?.listView.keyDown(with: event) return nil } else { let cmd = event.modifierFlags.contains(.command) let shift = event.modifierFlags.contains(.shift) if event.keyCode == 6 { // z let editPDFIng = self?.editPDFHanddler.isEditing ?? false if cmd && shift { // 恢复 let can = self?.editPDFHanddler.listView?.canEditTextRedo() ?? false if can == false { return event } if editPDFIng { _ = CustomAlertView.alertView(message: NSLocalizedString("Redo", comment: ""), fromView: self!.view, withStyle: .black) // if let data = self?.listView.canEditTextRedo(), data { // self?.listView.editTextRedo() // } } } else if cmd { // 撤回 let can = self?.editPDFHanddler.listView?.canEditTextUndo() ?? false if can == false { return event } if editPDFIng { _ = CustomAlertView.alertView(message: NSLocalizedString("Undo", comment: ""), fromView: self!.view, withStyle: .black) // if let data = self?.listView.canEditTextUndo(), data { // self?.listView.editTextUndo() // } } } } } } return event } } func removeKeyEventMonitor() { if (self.keyEventMonitor != nil) { KMPrint("removeKeyEventMonitor 已移除事件监听") NSEvent.removeMonitor(self.keyEventMonitor as Any) self.keyEventMonitor = nil } } private func removeEventMonitor() { if (self.eventMonitor != nil) { KMPrint("已移除事件监听") NSEvent.removeMonitor(self.eventMonitor as Any) self.eventMonitor = nil } } // MARK: - Tools func pdfViewCanHorizontalScroll() -> Bool { let scroll = self.listView.scroll() if (scroll == nil) { return false } return scroll?.horizontalScroller?.isHidden == nil ? false : !(scroll!.horizontalScroller!.isHidden) } func pdfViewCanVerticalScroll() -> Bool { let scroll = self.listView.scroll() if (scroll == nil) { return false } return scroll?.verticalScroller?.isHidden == nil ? false : !(scroll!.verticalScroller!.isHidden) } // MARK: - Public Methods // 清理数据 [eg. 通知] public func clearData() { KMThumbnailCache.shared.clearCache() self.removeNotifications() if (self.listView.spellingTag() > 0) { NSSpellChecker.shared.closeSpellDocument(withTag: self.listView.spellingTag()) } self.removeAutoSaveInfo() KMAdsManager.defaultManager.dismissSheetModal(for: self.readContentView) self.myDocument = nil } public func clearSecureOptions() { self._secureOptions = nil self.documentAttribute = nil } public func recordRemoveSecureFlag() { self._removeSecureFlag = true self.clearSecureOptions() self.recordIsPDFDocumentEdited(type: .removePassword) self._needSave = true } public func clearRemoveSecureFlag() { self._removeSecureFlag = false } public func clearSaveWatermarkFlag() { km_synchronized(self) { self._saveWatermarkFlag = false } } public func recordIsPDFDocumentEdited(type: KMSubscribeWaterMarkType = .none) { km_synchronized(self) { self.model.isPDFDocumentEdited = true if type == .editText || type == .editImage { self.leftSideViewController.updateThumbnail(at: self.listView.currentPageIndex) } if let _document = self.myDocument { KMTools.setDocumentEditedState(document: _document) } } } public func clearIsPDFDocumentEdited() { km_synchronized(self) { self.model.isPDFDocumentEdited = false } } func showSnapshots(setups: NSArray?) { if self.listView.document != nil { for setup in setups ?? [] { let swc = KMSnapshotWindowController() swc.delegate = self swc.setPdfDocument(self.listView.document, setup: setup as? NSDictionary) swc.setForceOnTop(self.interactionMode != .normal) self.myDocument?.addWindowController(swc) } } } func dealDocumentDidLoaded() { self.removeBackgroundMaskView() if (!self.listView.document!.allowsCopying || !self.listView.document!.allowsPrinting) { self.showSecureLimitTip() } // let readModel = UserDefaults.standard.bool(forKey: "kKMPDFViewIsReadMode") // if readModel == true { // self.openReadModel() // } if self.model.needConvertNotes { self.showConvertNotesProgress() } if (self._documentFirstLoad) { self.checkShouldAutoOpenLeftVC() if (KMPreferenceManager.shared.openLastUnlockedDocumentWhenAppStart) { let pageNumber = KMPreferenceManager.shared.getPageNumber(forKey: self.listView.document?.documentURL.path ?? "") let pageScale = KMPreferenceManager.shared.getPageScale(forKey: self.listView.document?.documentURL.path ?? "") if (pageScale != nil) { self.listView.scaleFactor = CGFloat(pageScale!) } if (pageNumber != nil && pageNumber! >= 0 && pageNumber! < (self.listView.document?.pageCount ?? 0)) { self.listView.go(toPageIndex: pageNumber!, animated: false) } else { self._goToFirstPageForFristAppear() } } else { self._goToFirstPageForFristAppear() } self._documentFirstLoad = false } } func tabViewIsDragging() -> Bool { let level = self.view.window?.level ?? .normal return level == .floating } // MARK: - Noti Actions internal func documentDidUnlockNotification(_ sender: Notification) { if (self.listView.document != nil && self.listView.document.isEqual(to: sender.object)) { if (self.myDocument == nil) { return } if (self.listView.document.allowsPrinting && self.listView.document.allowsCopying) { self.hiddenSecureLimitTip() } let isUnlockFromKeychain = (self.myDocument as? KMMainDocument)?.isUnlockFromKeychain ?? false if (isUnlockFromKeychain || self.model.isSaveKeyChain == false) { return } let type = KMPreferenceManager.shared.savePasswordType if (type == .never) { return } if (type == .always) { self.myDocument?.savePasswordInKeychain(self.listView.document.password, self.listView.document) return } // 保存到钥匙串 let alert = NSAlert() alert.messageText = NSLocalizedString("Remember Password?", comment: "") alert.informativeText = NSLocalizedString("Do you want to save this password in your Keychain?", comment: "") alert.addButton(withTitle: NSLocalizedString("Yes", comment: "")) alert.addButton(withTitle: NSLocalizedString("No", comment: "")) if (alert.runModal() == .alertFirstButtonReturn) { // 保存密码 self.myDocument?.savePasswordInKeychain(self.listView.document.password, self.listView.document) return } } } func annotationsAttributeHasChange(_ sender: Notification) { guard let dict = sender.object as? [String : Any] else { return } if let anno = dict["object"] as? CPDFAnnotation { let value = dict["keyPath"] as? String ?? "" let didEnd = dict["didEnd"] as? Bool ?? false if didEnd { if value == CPDFAnnotationBoundsKey { if anno is CPDFSquareAnnotation || anno is CPDFCircleAnnotation { anno.contents = anno.page?.string(for: anno.bounds) ?? "" } } if anno.km_isMeasure() && anno.contents == nil { anno.contents = anno.string() ?? "" } self.leftSideViewController.refreshUIForAnnoAttributeDidChange(anno, attributes: ["keyPath" : value]) } else { if value != CPDFAnnotationBoundsKey && value != CPDFAnnotationStartPointKey && value != CPDFAnnotationEndPointKey && value != CPDFAnnotationPathsKey { // 改变bounds(箭头、直线注释 开始点和结束点, 手绘注释的paths)的操作会卡顿,比如移动 self.leftSideViewController.refreshUIForAnnoAttributeDidChange(anno, attributes: ["keyPath" : value]) } } } } internal func applicationWillTerminateNotification(_ sender: Notification) { self.savePageNumberIfNeed() self.saveDocument() } func KMPDFViewCurrentPageDidChangedNotification(_ sender: Notification) { if self.isReadMode { self.readModelView.currentPageIndex = self.listView.currentPageIndex } //刷新前一页后一页按钮 self.updateNextAndPreViousButtonState() } func CPDFDocumentPageCountChangedNotification(_ sender: Notification) { if self.isReadMode { self.readModelView.totalPagesCount = Int(self.listView.document?.pageCount ?? 0) } //刷新前一页后一页按钮 self.updateNextAndPreViousButtonState() self.leftSideViewController.refreshUIForAnnoAttributeDidChange(nil, attributes: nil) } func CEditPDFToolModeChangeStateUnkownNotification(_ sender: Notification) { var editSelectd = false if (self.listView.annotationType == .addText || self.listView.annotationType == .addImage) && self.listView.toolMode == .editPDFToolMode { editSelectd = true } if self.listView.toolMode == .editPDFToolMode { if editSelectd { self.toolbarController.cancelSelected(KMToolbarAddTextEditPDFItemIdentifier) } } } @objc func handlePageChangedNotification(_ sender: Notification) { // When the PDFView is changing scale, or when view settings change when switching fullscreen modes, // a lot of wrong page change notifications may be send, which we better ignore. // Full screen switching and zooming should not change the current page anyway. if self.mwcFlags.isSwitchingFullScreen > 0 { // if ([pdfView isZooming] || mwcFlags.isSwitchingFullScreen) { // [self updatePageNumber]; // [self updateLeftStatus]; return } // let page = self.listView.currentPage() let pageIndex = page?.pageIndex() ?? 0 // // if ([lastViewedPages count] == 0) { // [lastViewedPages addPointer:(void *)pageIndex]; // } else if ((NSUInteger)[lastViewedPages pointerAtIndex:0] != pageIndex) { // [lastViewedPages insertPointer:(void *)pageIndex atIndex:0]; // if ([lastViewedPages count] > 5) // [lastViewedPages setCount:5]; // } self.leftSideViewController.thumb_selectRowIndexsIfNeed(IndexSet(integer: IndexSet.Element(pageIndex))) self.leftSideViewController.thumbnailTableView.needsDisplay = true self.leftSideViewController.tocOutlineView.needsDisplay = true // // [self updatePageNumber]; // [self updatePageLabel]; // // [self updateOutlineSelection]; // [self updateNoteSelection]; // [self updateThumbnailSelection]; // // if (beforeMarkedPageIndex != NSNotFound && [[pdfView currentPage] pageIndex] != markedPageIndex) // beforeMarkedPageIndex = NSNotFound; // // [self synchronizeWindowTitleWithDocumentName]; // [self updateLeftStatus]; // if ([[NSUserDefaults standardUserDefaults] boolForKey:SKDisplayPageBoundsKey]) // [self updateRightStatus]; // if ([self interactionMode] == SKPresentationMode) // [[self presentationNotesDocument] setCurrentPage:[[[self presentationNotesDocument] pdfDocument] pageAtIndex:[page pageIndex]]]; } @objc func handleDisplayBoxChangedNotification(_ sender: Notification) { self.leftSideViewController.reloadThumbnailDataIfNeed() // if ([[NSUserDefaults standardUserDefaults] boolForKey:SKDisplayPageBoundsKey]) // [self updateRightStatus]; } @objc func willEnterInteractionModeNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } let interactionMode = sender.userInfo?[NSWindow.UserInfo.interactionModeKey] as? KMInteractionMode if interactionMode == .presentation { let backgroundColor = NSColor.black let level = UserDefaults.standard.bool(forKey: "SKUseNormalLevelForPresentationKey") ? NSWindow.Level.normal : NSWindow.Level.popUpMenu let wasInteractionMode = self.interactionMode if wasInteractionMode == .normal { self.savedNormalSetup.setDictionary(self.currentPDFSettings() as! [AnyHashable : Any]) } // if findController.view().window() != nil { // findController.toggleAboveView(nil, animate: false) // } if wasInteractionMode == .legacyFullScreen { self.enterPresentationMode() // updatePresentationOptions(for: self.view.window!) self.pdfSplitView.frame = CGRect(x: 0, y: 0, width: NSWidth(centerContentView.bounds), height: NSHeight(centerContentView.bounds)-1) self.centerContentView.addSubview(pdfSplitView) self.listView.frame = (self.view.window?.contentView?.bounds)! self.view.window?.contentView?.addSubview(listView) self.view.window?.backgroundColor = backgroundColor self.view.window?.level = level self.listView.layoutDocumentView() self.listView.requiresDisplay() self.forceSubwindowsOnTop(false) self.hideLeftSideWindow() self.hideRightSideWindow() self.removeBlankingWindows() } } else { KMPrint("2") } } @objc func didEnterInteractionModeNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } if self.interactionMode == .presentation { // if self.pdfView().currentPage()?.isEqual(page) == false { // self.pdfView().go(to: page) // } // pdfView().setInteractionMode(SKPresentationMode) self.listView?.layoutDocumentView() self.listView?.requiresDisplay() } } @objc func willShowFullScreenNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } if self.interactionMode == .presentation { let view = self.view.window?.firstResponder as? NSView if let data = view?.isDescendant(of: self.pdfSplitView), data { self.view.window?.makeFirstResponder(nil) } } } @objc func didShowFullScreenNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } if self.interactionMode == .presentation { self.enterPresentationMode() } } @objc func didAddContentViewNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } if self.interactionMode == .presentation { } } @objc func purchaseStateUpdateNoti() { if KMMemberInfo.shared.isMemberAllFunction { KMAdsManager.defaultManager.dismissSheetModal(for: self.readContentView) } } //!!!: - CPDFFreeTextAnnotation 空注释时会删除,删除时sdk内部删除的,只能接受通知来刷选UI【正常的注释删除会走两遍】 @objc func didRemoveAnnotationNotification(_ sender: Notification) { guard let anno = sender.object as? CPDFAnnotation else { return } if anno.page?.document != self.listView.document { return } self.leftSideViewController.annoList_refreshUIForDeleteAnnotations(annos: [anno], page: anno.page) } // MARK: Split View func changePDFDocument(isChange: Bool, replaceBlock: @escaping (String) -> Void) { let openPanel = NSOpenPanel() openPanel.allowedFileTypes = ["pdf", "PDF"] openPanel.allowsMultipleSelection = false guard let mainWindow = NSApp.mainWindow else { return } openPanel.beginSheetModal(for: mainWindow) { [weak self] response in if response == NSApplication.ModalResponse.OK { guard let url = openPanel.url else { return } if let document = CPDFDocument(url: url) { self?.secondaryPdfView?.document = nil self?.secondaryPdfView?.document = document if isChange { self!.openSecondaryPdfView!.view.removeFromSuperview() } replaceBlock(document.documentURL?.path ?? "") } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() } } } } } extension KMMainViewController { func currentSetup() -> [String: Any] { var setup: [String: Any] = [:] var point = NSZeroPoint // var rotated = listView.currentPage().rotation if listView == nil { return setup } let pageIndex = listView.currentPageIndexAndPoint(&point, rotated: nil) setup[kWindowFrameKey] = NSStringFromRect(mainWindow?.frame ?? NSZeroRect) setup[KMMainModel.Key.kLeftSidePaneWidth] = self.model.lastLeftPanWidth setup[KMMainModel.Key.kRightSidePaneWidth] = self.model.lastRightPanWidth setup[KMMainModel.Key.pageIndex] = pageIndex // if rotated != 0 { // setup[SCROLLPOINT_KEY] = NSStringFromPoint(point) // } // if !snapshots.isEmpty { // setup[SNAPSHOTS_KEY] = snapshots.map { $0[SKSnapshotCurrentSetupKey] } // } // if interactionMode == SKNormalMode { // setup.merge(currentPDFSettings(), uniquingKeysWith: { $1 }) // } else { // setup.merge(savedNormalSetup, uniquingKeysWith: { $1 }) // ["HASHORIZONTALSCROLLER_KEY", "HASVERTICALSCROLLER_KEY", "AUTOHIDESSCROLLERS_KEY", "LOCKED_KEY"].forEach { setup.removeValue(forKey: $0) } // } return setup } // MARK: - Recommond活动 func loadRecommondPopWindow() { if KMMemberInfo.shared.isMemberAllFunction { return } if let info = KMAdvertisementManager.manager.info.popWindowContent?.content?.first { if recommondPopWindowVC == nil { recommondPopWindowVC = KMRecommondPopWindow.default() } recommondPopWindowVC?.recommondInfo = info guard let windowFrame = self.view.window?.frame, let popWindowFrame = recommondPopWindowVC?.window?.frame else { return } let x = windowFrame.minX + (windowFrame.size.width - popWindowFrame.size.width) / 2.0 let y = windowFrame.minY + (windowFrame.size.height - popWindowFrame.size.height) / 2.0 recommondPopWindowVC?.window?.setFrame(NSRect(x: x, y: y, width: popWindowFrame.size.width, height: popWindowFrame.size.height), display: true) recommondPopWindowVC?.window?.orderFront((Any).self) recommondPopWindowVC?.window?.becomeMain() UserDefaults.standard.set("Show", forKey: info.version ?? "") UserDefaults.standard.synchronize() } } } extension KMMainViewController { func changeFont(_ sender: NSFontManager) { KMPrint("changeFont ...") if ((self.listView.activeAnnotation?.isKind(of: CPDFFreeTextAnnotation.self)) != nil) { let annotation: CPDFFreeTextAnnotation = self.listView.activeAnnotation as! CPDFFreeTextAnnotation var font = NSFont(name: annotation.fontName() ?? "Helvetica", size: (annotation.fontSize()) ) font = sender.convert(font!) annotation.fontSize = font?.pointSize ?? 12 self.listView.commitEditAnnotationFreeText(annotation) self.listView.setNeedsDisplay(annotation) // self.listView.setNeedsDisplayAnnotationViewFor(annotation.page) } } }