// // KMMainViewController.swift // PDF Reader Pro // // Created by wanjun on 2022/12/15. // import Cocoa let MAINWINDOWFRAME_KEY = "windowFrame" let LEFTSIDEPANEWIDTH_KEY = "leftSidePaneWidth" let RIGHTSIDEPANEWIDTH_KEY = "rightSidePaneWidth" let SNAPSHOTS_KEY = "snapshots" let DISPLAYSPAGEBREAKS_KEY = "displaysPageBreaks" let DISPLAYSASBOOK_KEY = "displaysAsBook" let DISPLAYMODE_KEY = "displayMode" let DISPLAYBOX_KEY = "displayBox" let HASHORIZONTALSCROLLER_KEY = "hasHorizontalScroller" let HASVERTICALSCROLLER_KEY = "hasVerticalScroller" let AUTOHIDESSCROLLERS_KEY = "autoHidesScrollers" let SCALEFACTOR_KEY = "scaleFactor" let AUTOSCALES_KEY = "autoScales" let PAGEINDEX_KEY = "pageIndex" let SCROLLPOINT_KEY = "scrollPoint" let LOCKED_KEY = "locked" @objcMembers class KMMainViewController: NSViewController,CPDFViewDelegate,CPDFListViewDelegate,NSTextFieldDelegate { @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! var isReadMode: Bool = false 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 //页码显示器 @IBOutlet weak var pageNumberDisplayView: KMPageNumberDisplayView! @IBOutlet weak var tipCurrentPageBoxWidthConstraint: NSLayoutConstraint! //自动滚动 var autoFlowOptionsSheetController: KMAutoFlowOptionsSheetController? //AI相关 var aiTipView: AITipIconView! var aiTypeChooseView: AITypeChooseView! //Search var searchIndex: Int = 0 //Form var formAlertView: KMFormAlertView? //对比 var isCompareModel: Bool = false { didSet { self.toolbarController.updataItemVisible() } } //密码弹窗 var passwordWindow: KMPasswordInputWindow? private var _needSave = false var needSave: Bool { set { _needSave = newValue if (_needSave == false) { self.clearIsPDFDocumentEdited() self.hiddenSecureSuccessTip() } } get { return _needSave } } // 标识 pdf 已编辑 fileprivate var _isPDFDocumentEdited = false // 标识 pdf文字图片已编辑 internal var isPDFTextImageEdited = false var isPDFDocumentEdited: Bool { get { return _isPDFDocumentEdited } } var password: String? var leftSideViewController: KMLeftSideViewController = KMLeftSideViewController.init(type: KMLeftMethodMode()) var rightSideViewController: KMRightSideViewController! var searchResults: [KMSearchMode] = [] var mwcFlags: MwcFlags = MwcFlags() var isShowQuickTour: Bool = false var document: CPDFDocument? var myDocument: NSDocument? weak var browserWindowController: KMBrowserWindowController? var cropSettingWindowController: KMCropSettingWindowController! var currentWindowController: NSWindowController! // var interactionMode: SKInteractionMode = .SKNormalMode var savedNormalSetup: NSMutableDictionary = NSMutableDictionary() //数字签名 var digitalSignController: KMPDFDigitalSignViewController? let CPDFOfficeLeftSidePaneWidthKey = "CPDFOfficeLeftSidePaneWidthKey" let CPDFOfficeRightSidePaneWidthKey = "CPDFOfficeRightSidePaneWidthKey" @IBOutlet weak var topTipBox: NSBox! @IBOutlet weak var exitFullButton: NSButton! var hasAddRedact: Bool = false var functionWidth: Double { get { if self.isReadMode { if !self.isShowBOTA { return 0 } } return 48-4 } } var isShowBOTA: Bool = false let panelWidth = 212.0 let defaultRightWidth = 260.0 var lastLeftPanWidth = 0.0 var lastRightPanWidth = 0.0 var leftPanelOpen: Bool = false var rightPanelIsOpen = false var pageNumber: UInt? var openSecondaryPdfView: KMSecondaryViewController? var secondaryPdfContentView: NSView? var lastSplitPDFHeight: Float = 0.0 internal var isSaveKeyChain = true var rightMouseEventing = false var pdfEditController: KMPDFEditViewController? { get { return self.getPDFEditController() } } var autoSaveTimer: Timer? var progressController: SKProgressController? 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 } } var beforeMarkedPageIndex = NSNotFound var markedPageIndex = NSNotFound var beforeMarkedPagePoint = NSPoint.zero var markedPagePoint = NSPoint.zero var repeatTrialLoad: Bool = false var _mainWindow: NSWindow? var mainWindow: NSWindow? { get { return self._mainWindow } set { self._mainWindow = newValue } } deinit { NotificationCenter.default.removeObserver(self) self.stopAutoSaveTimer() self.removeEventMonitor() self.removeKeyEventMonitor() } override func awakeFromNib() { super.awakeFromNib() self.addBackgroundMaskView() // pdfSplitView.frame = NSMakeRect(0, 0, NSWidth(centerContentView.bounds), NSHeight(centerContentView.bounds)-1) // centerContentView.addSubview(pdfSplitView) 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 { listView.document = document // } 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() //刷新前一页后一页按钮 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) if (self.document == nil) { return } if (self.document == nil || self.document!.isLocked == false) { self.loadFunctionGuide() self.loadAIIconView() } if (self.document?.isLocked == false) { return } if (self.view.window == nil) { return } if (self.password != nil) { self.isSaveKeyChain = false self.listView.document.unlock(withPassword: self.password) return } DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { if self.passwordWindow == nil { self.passwordWindow = KMPasswordInputWindow.openWindow(window: NSWindow.currentWindow(), url: self.document!.documentURL) { [unowned self] result , password in self.passwordWindow = nil if (result == .cancel) { self.browserWindowController?.browser.closeTab() return } self.isSaveKeyChain = true self.listView.document = self.document self.document?.unlock(withPassword: password) } } else { self.passwordWindow = nil } } } override func viewWillAppear() { super.viewWillAppear() // self.reStartAutoSaveTimer() //是否弹出登录窗口 // self.needShowRegisterView() } override func viewWillDisappear() { super.viewWillDisappear() // KMPreferenceManager.shared.setPageNumber(self.listView.currentPageIndex, forKey: self.listView.document.documentURL.path) // self.pauseAutoSaveTimer() self.removeEventMonitor() } 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 } } override func viewDidLoad() { super.viewDidLoad() leftSideViewController.mainVC = self mwcFlags.settingUpWindow = 1 toolbarController.delegate = self //TODO: 先让项目运行,看后面怎么调整这段逻辑,目前最外层是 KMBrowserWindowController toolbarBox.contentView = toolbarController.view // self.childToolbarController.updateType(newType: .Annatiton) // self.showChildToolbar(showToolbar: true) // self.toolbarController.editPDFButtonAction(item: NSMenuItem()) 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) { 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 mouseEntered { self.pageNumberDisplayView.hover = true // self.updatePageIndicatoreType() } else { self.pageNumberDisplayView.hover = false // self.updatePageIndicatoreType() } } 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(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) self.autoSaveTimeStartOrStopIfNeed() 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, forKey: "snapshots" as NSCopying) } else { self.showSnapshots(setups: snapshotSetups) } } // [self applyPDFSettings:hasWindowSetup ? savedNormalSetup : [sud dictionaryForKey:SKDefaultPDFDisplaySettingsKey]]; // self.applyPDFSettings((KMDataManager.ud_dictionary(forKey: SKDefaultPDFDisplaySettingsKey) as? NSDictionary) ?? [:]) } //MARK: - KMToolbarViewControllerDelegate //MARK: - PDFListView func initPDFLeftViewVC() { var frame = self.leftView.frame frame.size.width += 44 self.leftView.frame = frame leftSideViewController.listView = self.listView ?? CPDFListView() 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.propertyDidChange = { [weak self] (model: AnyObject?) in let topBarView = self?.toolbarController.fetchTopBarView() if (topBarView == nil || ((topBarView?.isKind(of: KMWatermarkAdjectiveTopBarView.self)) == false)) { return } /// Bates码、页眉页脚、背景、水印 if (model == nil) { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: false) } else { if ((model?.isKind(of: KMBatesModel.self))!) { if ((model as! KMBatesModel).hasVaild) { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: true) } else { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: false) } } else if ((model?.isKind(of: KMHeaderFooterObject.self))!) { if ((model as! KMHeaderFooterObject).hasVaild) { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: true) } else { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: false) } } else if ((model?.isKind(of: KMBackgroundModel.self))!) { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: true) } else if ((model?.isKind(of: KMWatermarkModel.self))!) { (topBarView as! KMWatermarkAdjectiveTopBarView).isCanApply(can: true) } } } } func addAdsBannerView() { #if VERSION_FREE if !IAPProductsManager.default().isAvailableAllFunction(){ guard let document = self.listView.document else { return } if !document.isLocked { KMAdsManager.defaultManager.beginSheetModalForView(self.readContentView, directions: .down, adPosY: 30, animated: false) { pageIndex in } } } #endif //加载底部banner // - (void)loadingAdsManager { // #if VERSION_FREE // if(![self.pdfDocument isLocked]) { // if (![IAPProductsManager defaultManager].isAvailableAllFunction) { // [[KMAdsManager defaultManager] beginSheetModalForView:self.pdfView // directions:KMADViewDirectionsDown // animated:NO // completionHandler:nil]; // } // [[NSNotificationCenter defaultCenter] addObserverForName:KMIAPProductPurchasedNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note){ // if ([IAPProductsManager defaultManager].isAvailableAllFunction) { // [[KMAdsManager defaultManager] dismissSheetModalForView:self.pdfView]; // } // }]; // [[NSNotificationCenter defaultCenter] addObserverForName:kDeviceActivateStatusChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note){ // if ([IAPProductsManager defaultManager].isAvailableAllFunction) { // [[KMAdsManager defaultManager] dismissSheetModalForView:self.pdfView]; // } // }]; // } // #endif // } } // MARK: Private Methods internal func removeNotifications() { NotificationCenter.default.removeObserver(self) self.leftSideViewController.clearAnnotationFilterData() self.leftSideViewController.clearNotification() } func checkShouldAutoOpenLeftVC() { if KMPreference.shared.showLeftSideBar == false { return } if self.leftPanelOpen { return } Task { @MainActor in 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) lastLeftPanWidth = leftSideWidth lastRightPanWidth = rightSideWidth } //MARK: 动画 暂未接入 func animateSplitView(to position: CGFloat) { let frame1 = NSRect(x: 0, y: 0, width: position, height: mianSplitView.frame.height) let frame2 = NSRect(x: position, y: 0, width: mianSplitView.frame.width - position, height: mianSplitView.frame.height) // 创建一个新的动画上下文 let animationContext = NSAnimationContext.current animationContext.duration = 0.5 animationContext.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) // 启用隐式动画 NSAnimationContext.current.allowsImplicitAnimation = true // 移动分隔条 mianSplitView.setPosition(position, ofDividerAt: 0) mianSplitView.subviews[0].frame = frame1 mianSplitView.subviews[1].frame = frame2 } 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) } } // 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() } } var setPageNumber: UInt { get { return pageNumber! } set { let pageCount = listView.document.pageCount 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 !IAPProductsManager.default().isAvailableAllFunction(){ KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) 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 } 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 let controller = KMPDFRedactViewController(url: self.listView.document!.documentURL, password: self.listView.document.password) self.addChild(controller) self.PDFContendView.addSubview(controller.view) controller.view.frame = self.PDFContendView.bounds controller.view.autoresizingMask = [.width, .height] self.listView.isHidden = true controller.scaleFactor = self.listView.scaleFactor controller.titleBack = { [weak self] title in self?.view.window?.title = title } controller.callback = { [weak self] result, currentPageIndex, saveResult, saveUrl in 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() } } } func exitRedact() { 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 { data.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 loadAIIconView() -> Void { NotificationCenter.default.addObserver(self, selector: #selector(aiTipIconViewShowStateChangeNoti), name: NSNotification.Name(rawValue: "kAIIconShowStateChangeNotification"), object: nil) self.aiTipView = AITipIconView.createFromNib() self.aiTipView.clickHandle = { [weak self] view in self?.showAITypeChooseView() } self.aiTipView.rightClickHandle = { [weak self] view in AIInfoManager.default().showAIIcon = false NotificationCenter.default.post(name: NSNotification.Name(rawValue: "kAIIconShowStateChangeNotification"), object: nil) } self.aiTipView.frame = CGRectMake(CGRectGetWidth(self.view.frame)-84, CGRectGetHeight(self.view.frame)-84-64-50, 72, 72) self.aiTipView.autoresizingMask = [.minXMargin, .minYMargin] self.view.addSubview(self.aiTipView) self.updateAITipViewShowState() } func updateAITipViewShowState() { if AIInfoManager.default().showAIIcon { if self.isReadMode || KMTools.isFullScreen(self.view.window!) { self.aiTipView.isHidden = true } else { self.aiTipView.isHidden = false } } else { self.aiTipView.isHidden = true } } func showAITypeChooseView() -> Void { if AIInfoManager.default().aiInfo.infoDict.isEmpty == true { #if VERSION_DMG KMPurchaseCompareWindowController.dmgPurchaseInstance().showWindow(nil) #else AIPurchaseWindowController.currentWC().showWindow(nil) #endif return } let controller = NSViewController.init() let view = NSView.init() controller.view = view var string: String = NSLocalizedString("AI Summarize", comment: "") if string.count < NSLocalizedString("AI Rewrite", comment: "").count { string = NSLocalizedString("AI Rewrite", comment: "") } if string.count < NSLocalizedString("AI Proofread", comment: "").count { string = NSLocalizedString("AI Proofread", comment: "") } if string.count < NSLocalizedString("AI Translate", comment: "").count { string = NSLocalizedString("AI Translate", comment: "") } let font = NSFont.SFProTextRegularFont(13) var style = NSMutableParagraphStyle.init() style.alignment = .center style.lineBreakMode = .byCharWrapping let size: NSSize = string.boundingRect(with: NSSize(width: 1000, height: 100), options: NSString.DrawingOptions(rawValue: 3), attributes: [NSAttributedString.Key.font : NSFont.SFProTextRegularFont(13), NSAttributedString.Key.paragraphStyle : style]).size controller.view.frame = CGRectMake(0, 0, size.width+80, 160) if self.aiTypeChooseView == nil { self.aiTypeChooseView = AITypeChooseView.createFromNib() } self.aiTypeChooseView.clickHandle = { [weak self] view, type in DispatchQueue.main.async { self?.loadAIConfigWindowWithType(type) } } self.aiTypeChooseView.frame = controller.view.bounds self.aiTypeChooseView.autoresizingMask = [.width, .height] controller.view.addSubview(self.aiTypeChooseView) let popover = NSPopover.init() popover.contentViewController = controller popover.animates = true popover.behavior = .transient var rect = self.aiTipView.bounds rect.origin.y += 20 popover.show(relativeTo: rect, of: self.aiTipView, preferredEdge: .minY) } func loadAIConfigWindowWithType(_ type: AIConfigType) -> Void { if AIInfoManager.default().aiInfo.infoDict.isEmpty == true { #if VERSION_DMG KMPurchaseCompareWindowController.dmgPurchaseInstance().showWindow(nil) #else AIPurchaseWindowController.currentWC().showWindow(nil) #endif return } let windowVC = AIConfigWindowController.currentWC() windowVC.configType = type if type == .summarize { windowVC.window?.setFrame(CGRectMake(0, 0, 800, 500), display: true) } else if type == .reWriting { windowVC.window?.setFrame(CGRectMake(0, 0, 800, 460), display: true) } else if type == .proofreading { windowVC.window?.setFrame(CGRectMake(0, 0, 800, 460), display: true) } else if type == .translate { windowVC.window?.setFrame(CGRectMake(0, 0, 800, 545), display: true) } windowVC.cancelHandle = { [weak self] windowVC in self?.view.window?.endSheet(windowVC.window!) } windowVC.refreshUI() self.view.window?.beginSheet(windowVC.window!) windowVC.refreshUI() } @objc func aiTipIconViewShowStateChangeNoti() { self.updateAITipViewShowState() } //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")! let guideWC = KMGuideInfoWindowController.currentWC() guideWC.type = .openFileNormal guideWC.openPanelRect = (self.view.window?.contentView?.convert(leftPanelItem.frame, from: leftPanelItem.superview)) ?? CGRectZero guideWC.window?.collectionBehavior = [.canJoinAllSpaces] guideWC.normalGuideFinishHandle = { [weak self] windowVC in let rightPanelItem = self?.toolbarController.findItem(KMRightControlToolbarItemIdentifier) let digitalPanelItem = self?.toolbarController.findItem(KMDocumentDigitalSignToolbarItemIdentifier) 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) { let guideWC = KMGuideInfoWindowController.currentWC() guideWC.type = .digitalSignGuide let digitalPanelItem:KMToolbarItemView = self.toolbarController.findItem(KMDocumentDigitalSignToolbarItemIdentifier)! 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() + 1) { let guideWC = KMGuideInfoWindowController.currentWC() guideWC.type = .pdfCompareGuide let digitalPanelItem:KMToolbarItemView = self.toolbarController.findItem(KMDocumentDigitalSignToolbarItemIdentifier)! guideWC.digitalBoxRect = (self.view.window?.contentView?.convert(digitalPanelItem.frame, from: digitalPanelItem.superview))! let compareItem:KMToolbarItemView = self.toolbarController.findItem(KMToolbarComparisonItemIdentifier)! guideWC.compareItemRect = (self.view.window?.contentView?.convert(compareItem.frame, from: compareItem.superview))! 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 == .convertGuide && KMGuideInfoWindowController.availableShow(.convertGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { let guideWC = KMGuideInfoWindowController.currentWC() guideWC.type = .convertGuide let digitalPanelItem:KMToolbarItemView = self.toolbarController.findItem(KMDocumentDigitalSignToolbarItemIdentifier)! guideWC.digitalBoxRect = (self.view.window?.contentView?.convert(digitalPanelItem.frame, from: digitalPanelItem.superview))! guideWC.purchaseHandle = { [weak self] windowVC in #if VERSION_DMG if IAPProductsManager.default().isAvailableAllFunction() { if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { //Convert: self?.showAllConvertWindow(convertT: .Word) } else { let limitWC = KMPurchaseLimitWindowController.currentLimitWC() limitWC.continueBlock = { [weak self] windowController in } limitWC.window?.center() limitWC.showWindow(nil) } } else { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) } #else if IAPProductsManager.default().isAvailableAllFunction() { if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { //Convert: } else { var vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 1) vc.showWindow(nil) } } else { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) } #endif } 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 { } } 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 == nil || lastVersion != appVersion { UserDefaults.standard.setValue(appVersion, forKey: "SKLastTrialVersionMainDocumentLaunchedKey") UserDefaults.standard.synchronize() KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) } } #endif } // MARK: - 页面编辑 open func enterPageEdit(_ pages: [Int] = []) { //选中page var tPages = pages if tPages.count == 0 { tPages = self.leftSideViewController.selectPages ?? [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 } } } // #if VERSION_DMG // let controller = KMPDFEditViewController_dmg(self.listView.document) // #else let controller = KMPDFEditViewController(self.listView.document) // #endif 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() // self?.needSave = true if let data = params.first as? KMPageEditType { self?.recordSaveWatermarkFlag(type: data.toSubscribeWaterMarkType()) } else { self?.recordSaveWatermarkFlag() } } controller.selectionDidChange = { [weak self] 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 } } } let editController = getPDFEditController() if (editController == nil) { return } self.listView.annotationType = .highlight 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() } } open func hasEnterPageEdit() -> Bool { return self.getPDFEditController() != nil } // 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 isFileGreaterThan10MB(atPath filePath: String) -> Bool { let fileManager = FileManager.default do { let fileAttributes = try fileManager.attributesOfItem(atPath: filePath) if let fileSize = fileAttributes[.size] as? UInt64 { let megabyteSize = fileSize / (1024 * 1024) return megabyteSize >= 10 } } catch { KMPrint("Error: \(error)") } return 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 showSecureSuccessTip() { let view: NSView = self.view let tip = KMSecureEncryptSuccessTipView() let size = NSSize(width: 379, height: 176) tip.frame = NSMakeRect(view.frame.size.width-size.width-16, view.frame.size.height-size.height-88, size.width, size.height) tip.autoresizingMask = [.minXMargin, .minYMargin] view.addSubview(tip) tip.itemClick = { [weak self] in self!.hiddenSecureSuccessTip() } } public func hiddenSecureSuccessTip() { let view: NSView = self.view var tip: KMSecureEncryptSuccessTipView? for subview in view.subviews { if (subview.isKind(of: KMSecureEncryptSuccessTipView.self)) { tip = (subview as! KMSecureEncryptSuccessTipView) break } } if (tip == nil) { return } tip?.removeFromSuperview() } public func showSecureLimitTip() { self.hiddenSecureLimitTip() let tip = KMSecureAlertView() tip.show(in: self.listView) tip.closeAction = { [unowned self] view in self.hiddenSecureLimitTip() } tip.passwordAction = { [unowned self] view in self.removeOwnerPassword() } } 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?.isSaveKeyChain = false self?.listView.document.unlock(withPassword: password) } } public func hiddenSecureLimitTip() { let view: NSView = self.view var tip: KMSecureAlertView? for subview in view.subviews { if (subview.isKind(of: KMSecureAlertView.self)) { tip = (subview as! KMSecureAlertView) break } } if (tip == nil) { return } tip?.removeFromSuperview() } 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: - // MARK: 退出全屏 @IBAction func exitFullScreen(_ sender: Any) { if (self.view.window == nil) { return } if (KMTools.isFullScreen(self.view.window!)) { self.view.window?.toggleFullScreen(nil) } } // MARK: - // 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 } let document = PDFDocument(url: _url) let windowController = KMMergeWindowController(document: document!, password: password ?? "") windowController.oriDucumentUrl = self.listView.document.documentURL windowController.pageIndex = self.listView.currentPageIndex self.currentWindowController = windowController windowController.cancelAction = { [unowned self] controller in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil } windowController.mergeAction = { [unowned self] controller, filePath in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil let newDocument = CPDFDocument(url: NSURL(fileURLWithPath: filePath) as URL) if let data = newDocument?.isLocked, data { newDocument?.unlock(withPassword: self.listView.document.password ?? "") } self.setDocument = newDocument if self.leftSideViewController.type.methodType == .Thumbnail { self.leftSideViewController.resetThumbnails() } } self.toolbarController.cancelSelected(KMToolbarToolMergeItemIdentifier) self.view.window?.beginSheet(windowController.window!) } } // MARK: - // MARR: 显示加密弹窗 public func showSecureWindow(_ url: URL) { // let windowController = KMSecureEncryptWindowController(windowNibName: "KMSecureEncryptWindowController") // windowController.documentURL = url // windowController.myDocument = self.listView.document // self.currentWindowController = windowController // // windowController.itemClick = { [weak self] index in // self?.view.window?.endSheet((self?.currentWindowController.window)!) // self?.currentWindowController = nil // } // // windowController.resultCallback = { [weak self] result in // let windowController_secure = self?.currentWindowController as! KMSecureEncryptWindowController // self?.view.window?.endSheet((self?.currentWindowController.window)!) // self?.currentWindowController = nil // // self?._secureOptions = windowController_secure.options // self?.needSave = true // self?.recordIsPDFDocumentEdited(type: .setPassword) // // if (result) { // self?.showSecureSuccessTip() // self?.recordSaveWatermarkFlag(type: .setPassword) // } else { // let alert = NSAlert() // alert.messageText = NSLocalizedString("Failure", comment: "") // alert.runModal() // } // } // // self.view.window?.beginSheet(windowController.window!) let controller = KMSecurityWindowController(windowNibName: "KMSecurityWindowController") controller.pdfDocument = self.document self.currentWindowController = controller controller.batchAction = { [unowned self] controller, files in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil self.toolbarController.cancelSelected(KMToolbarToolCompressItemIdentifier) let batchWindowController = KMBatchOperateWindowController.sharedWindowController batchWindowController.window?.makeKeyAndOrderFront("") let batchOperateFile = KMBatchOperateFile(filePath: files.first?.filePath ?? "") batchWindowController.switchToOperateType(.AddPassword, files: [batchOperateFile]) batchWindowController.window?.makeKeyAndOrderFront("") } controller.doneAction = { [unowned self] controller, options, attribute in // let windowController_secure = self.currentWindowController as! KMSecureEncryptWindowController 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.lastPathComponent) let success = document!.write(to: NSURL(fileURLWithPath: path) as URL, withOptions: options) if success { self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil NSWorkspace.shared.activateFileViewerSelecting([fileURL]) } } } } } // self._secureOptions = options // self.documentAttribute = attribute // self.needSave = true // self.recordIsPDFDocumentEdited(type: .setPassword) // // if (options.count != 0) { // self.showSecureSuccessTip() // self.recordSaveWatermarkFlag(type: .setPassword) // } else { // let alert = NSAlert() // alert.messageText = NSLocalizedString("Failure", comment: "") // alert.runModal() // } } controller.cancelAction = { [unowned self] controller in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil } NSWindow.currentWindow().beginSheet(controller.window!) } // MARK: - // 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) { // 显示进度 self.showProgressWindow(message: NSLocalizedString("Save PDF", comment: "")) self.progressController?.maxValue = 3.0 self.progressController?.increment(by: 1.0) // 保存文档 self.asyncSaveDocument { [unowned self] params in // 执行进度 [假进度] self.progressController?.increment(by: 1.0) self.progressController?.increment(by: 1.0) // DispatchQueue.main.async { DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { // 隐藏进度 self.hiddenProgressWindow() // 回调 callback() } } } // 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: - // 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 } } // MARK: - 自动保存 internal func autoSaveTimeStartOrStopIfNeed() { // if (KMPreferenceManager.shared.autoSave == false) { // self.stopAutoSaveTimer() // return // } // // self.startAutoSaveTimer(KMPreferenceManager.shared.autoSaveTimeInterval) // if (self.myDocument == nil) { // self.stopAutoSaveTimer() // return // } // // let browser = self.browserWindowController?.browser // guard let activeDocument = browser?.activeTabContents() else { // return // } // // if (self.myDocument!.isEqual(to: activeDocument) == false) { // self.pauseAutoSaveTimer() // return // } } private func startAutoSaveTimer(_ interval: TimeInterval) { if (self.autoSaveTimer != nil) { self.autoSaveTimer?.invalidate() self.autoSaveTimer = nil } self.autoSaveTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak self] timer in DispatchQueue.main.async { #if DEBUG Swift.debugPrint("文档已自动保存") if let _document = self?.myDocument { Swift.debugPrint(_document.fileURL as Any) } #endif self?.saveDocument() } } RunLoop.current.add(self.autoSaveTimer!, forMode: .common) } private func pauseAutoSaveTimer() { self.autoSaveTimer?.fireDate = Date.distantFuture } private func reStartAutoSaveTimer() { self.autoSaveTimer?.fireDate = Date()+KMPreferenceManager.shared.autoSaveTimeInterval } private func needShowRegisterView() { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { if KMLightMemberManager.manager.checkPopupRegister() { // Login & Logout let window = NSApp.mainWindow ?? self.view.window if KMLightMemberManager.manager.isLogin() { } else if window != nil { var email: String = UserDefaults.standard.value(forKey: "kLoginEmail") as? String ?? "" if email.count == 0 { KMLoginWindowController.show(window: window!, .Batch, .register) } else { KMLoginWindowController.show(window: window!, .Batch, .login) } } } } } private func stopAutoSaveTimer() { self.autoSaveTimer?.invalidate() self.autoSaveTimer = nil } 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: - // MARK: Progress func showProgressWindow(message: String = "") { if (self.progressController != nil) { self.hiddenProgressWindow() } let progress = SKProgressController() progress.window?.backgroundColor = NSColor.km_init(hex: "#36383B") progress.window?.contentView?.wantsLayer = true progress.window?.contentView?.layer?.backgroundColor = NSColor.km_init(hex: "#36383B").cgColor progress.progressField.textColor = NSColor.white progress.showClose = false progress.message = message self.progressController = progress self.view.window?.beginSheet(progress.window!) } func hiddenProgressWindow() { if (self.progressController != nil) { self.view.window?.endSheet((self.progressController?.window)!) self.progressController = nil } } // MARK - // MARK - Event 监听 private func addEventMonitor() { if (self.eventMonitor != nil) { self.removeEventMonitor() } KMPrint("已添加事件监听") self.eventMonitor = NSEvent.addLocalMonitorForEvents(matching: .scrollWheel) { [weak self] event in if (event.type == .scrollWheel && event.modifierFlags.contains(.option)) { // Alt + 鼠标滚轮 self?.listView.magnifyWheel(event) 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 { self?.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 } } 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: - // 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() { self.removeNotifications() if (self.listView.spellingTag() > 0) { NSSpellChecker.shared.closeSpellDocument(withTag: self.listView.spellingTag()) } self.removeAutoSaveInfo() } public func clearSecureOptions() { self._secureOptions = nil self.documentAttribute } public func recordRemoveSecureFlag() { self._removeSecureFlag = true self.clearSecureOptions() self.recordIsPDFDocumentEdited(type: .removePassword) self._needSave = true } public func clearRemoveSecureFlag() { self._removeSecureFlag = false } public func recordSaveWatermarkFlag(type: KMSubscribeWaterMarkType = .none) { // km_synchronized(self) { // self._saveWatermarkFlag = true // } // // if let _document = self.myDocument as? KMMainDocument { // _document.recordTrackEvent(type: type) // } } public func clearSaveWatermarkFlag() { km_synchronized(self) { self._saveWatermarkFlag = false } } public func recordIsPDFDocumentEdited(type: KMSubscribeWaterMarkType = .none) { km_synchronized(self) { self._isPDFDocumentEdited = true if let _document = self.myDocument { KMTools.setDocumentEditedState(document: _document) } } } public func clearIsPDFDocumentEdited() { km_synchronized(self) { self._isPDFDocumentEdited = false } } func showSnapshots(setups: NSArray?) { 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) } } // MARK: - Noti Actions internal func documentDidUnlockNotification(_ sender: Notification) { if (self.listView.document != nil && self.listView.document.isEqual(to: sender.object)) { self.loadAIIconView() if (self.myDocument == nil) { return } if (self.listView.document.allowsPrinting && self.listView.document.allowsCopying) { self.hiddenSecureLimitTip() } if ((self.myDocument as! KMMainDocument).isUnlockFromKeychain || self.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 } } } 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) } //刷新前一页后一页按钮 self.updateNextAndPreViousButtonState() } 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 page = self.listView.currentPage() 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: CGRectGetWidth(centerContentView.bounds), height: CGRectGetHeight(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 _isShowToolbar { // self.toolbarViewController.hiddenToolbar(true) // } // // 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 { } } //MARK: - PDFListViewDelegate func pdfViewDocumentDidLoaded(_ pdfView: CPDFView!) { // KMPrint("pdfViewDocumentDidLoaded") self.removeBackgroundMaskView() if (!self.listView.document!.allowsCopying || !self.listView.document!.allowsPrinting) { self.showSecureLimitTip() } 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) { self.listView.go(toPageIndex: pageNumber!, animated: false) } else { self._goToFirstPageForFristAppear() } } else { self._goToFirstPageForFristAppear() } self._documentFirstLoad = false } let notification = Notification(name: Notification.Name(rawValue: "pdfViewDocumentDidLoaded")) self.preferenceDidChangeNotification(notification:notification) let leftWidthNumber = UserDefaults.standard.object(forKey: CPDFOfficeLeftSidePaneWidthKey) as? NSNumber ?? NSNumber(value: panelWidth + functionWidth) let rightWidthNumber = UserDefaults.standard.object(forKey: CPDFOfficeRightSidePaneWidthKey) as? NSNumber ?? NSNumber(value: defaultRightWidth) applyLeftSideWidth(leftWidthNumber.doubleValue, rightSideWidth: rightWidthNumber.doubleValue) self.updatePageIndicatoreType() } func pdfViewCurrentPageDidChanged(_ pdfView: CPDFView!) { self.updatePageIndicatoreType() NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "KMPDFViewCurrentPageDidChanged"), object: self.document) // KMPrint("KMPDFViewCurrentPageDidChanged") } func pdfViewScaleDidChanged(_ pdfView: CPDFView!) { self.toolbarController.mainToolBarView?.zoomTextField.stringValue = "\(Int(self.listView.scaleFactor * 100))%" self.updateZoomInOutButtonState() // KMPrint("pdfViewScaleDidChanged") } func pdfViewDidClick(onLink pdfView: CPDFView!, withURL url: String!) { if let urlString = url, urlString == kKMPurchaseProductURLString { //跳转订阅比较表 let _ = KMComparativeTableViewController.show(window: NSApp.mainWindow ?? NSWindow()) return } KMTools.openURL(urlString: url) } func pdfViewPerformURL(_ pdfView: CPDFView!, withContent content: String!) { KMPrint("pdfViewPerformURL") } func pdfViewPerformPrint(_ pdfView: CPDFView!) { KMPrint("pdfViewPerformPrint") } func pdfViewPerformGo(toPage pdfView: CPDFView!) { KMPrint("pdfViewPerformGo") } func pdfViewOpenPDF(_ pdfView: CPDFView!, forRemoteGoTo action: CPDFAction!) { KMPrint("pdfViewOpenPDF") } func pdfViewPerformReset(_ pdfView: CPDFView!) { KMPrint("pdfViewPerformReset") } func pdfViewEditingBlockDidChanged(_ pdfView: CPDFView!) { KMPrint("pdfViewEditingBlockDidChanged") } func pdfViewAsBookBookmark() -> NSImage! { return NSImage(named: "KMImageNameUXIconPDFViewBookMark")! } func pdfViewEditingSelectionDidChanged(_ pdfView: CPDFView!) { self.recordSaveWatermarkFlag() if self.rightSideViewController != nil && self.rightSideViewController.subViewType == .EditPDFAddText { self.rightSideViewController.eidtPDFTextProperty.reloadData() self.rightSideViewController.eidtPDFTextProperty.updateTextTextPresuppositionState() } } func pdfViewEditingAreaDidChanged(_ pdfView: CPDFView!) { let areas = self.listView.editingAreas() if areas == nil || areas?.count ?? 0 == 0 { if self.listView.toolMode == .editPDFToolMode { if self.listView.annotationType == .addImage || self.listView.annotationType == .addText { if self.listView.isEditImage { self.menuItemEditingClick_CropImage(sender: NSMenuItem()) } else { // if self.listView.annotationType == .addImage { // self.closeRightPane() // } if self.listView.annotationType == .addImage { if self.rightSideViewController.eidtPDFImageProperty != nil { self.rightSideViewController.eidtPDFImageProperty.reloadData() } } // self.openRightPane() } } else { self.closeRightPane() } } else { self.rightSideViewController.isHidden = true self.closeRightPane() if self.rightSideViewController != nil && self.rightSideViewController.subViewType == .EditPDFAddText && self.listView.annotationType == .addText { self.rightSideViewController.eidtPDFTextProperty.initData() } } if self.listView.isEdited() { self.recordIsPDFDocumentEdited(type: .editText) } if self.listView.annotationType != .addText { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "kPDFViewEditingAreaDidChanged"), object: self.listView.document) } return } self.isPDFTextImageEdited = true if (self.listView.annotationType == .addImage) && areas!.count > 0 { var isImageArea = false for i in 0 ... areas!.count-1 { if areas![i] is CPDFEditImageArea { isImageArea = true } } if isImageArea { // self.rightSideViewController.view.isHidden = false self.rightSideViewController.isHidden = false if self.rightSideViewController != nil && self.rightSideViewController.subViewType == .EditPDFAddImage { self.rightSideViewController.subViewType = .EditPDFAddImage self.rightSideViewController.eidtPDFImageProperty.reloadData() } self.openRightPane() } else { // self.rightSideViewController.view.isHidden = true self.rightSideViewController.isHidden = true self.closeRightPane() } } else if self.rightSideViewController != nil && self.rightSideViewController.subViewType == .EditPDFAddText && self.listView.annotationType == .addText { // self.rightSideViewController.view.isHidden = false self.rightSideViewController.isHidden = false if self.listView.editingSelectionString().count != 0 { self.rightSideViewController.eidtPDFTextProperty.reloadData() } else { self.rightSideViewController.eidtPDFTextProperty.refreshSelectAreaProperty(needDefaultData: true) } self.openRightPane() } else { var textsAreas : [CPDFEditTextArea] = [] var imagesAreas : [CPDFEditImageArea] = [] if self.listView.editingAreas()?.count ?? 0 < 1 { return } for i in 0 ... areas!.count-1 { if areas![i] is CPDFEditTextArea { textsAreas.append(areas![i] as! CPDFEditTextArea) } if areas![i] is CPDFEditImageArea { imagesAreas.append(areas![i] as! CPDFEditImageArea) } } if textsAreas.count > 0 && textsAreas.count == areas!.count { // self.rightSideViewController.view.isHidden = false self.rightSideViewController.isHidden = false self.rightSideViewController.subViewType = .EditPDFAddText self.rightSideViewController.eidtPDFTextProperty?.reloadData() self.openRightPane() } else if imagesAreas.count > 0 { // self.rightSideViewController.view.isHidden = false self.rightSideViewController.isHidden = false self.rightSideViewController.subViewType = .EditPDFAddImage self.rightSideViewController.eidtPDFImageProperty?.reloadData() self.openRightPane() } } if self.listView.isEdited() { self.recordIsPDFDocumentEdited(type: .editText) if self.listView.annotationType != .addText { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "kPDFViewEditingAreaDidChanged"), object: self.listView.document) } } } func pdfViewEditingCropBoundsDidChanged(_ pdfView: CPDFView!, editing editArea: CPDFEditArea!) { self.recordSaveWatermarkFlag() if editArea != nil && (editArea is CPDFEditImageArea){ self.listView.cropAreas = editArea as? CPDFEditImageArea } } //编辑PDF 创建图片区域回调 func pdfViewEditingAddImageArea(_ pdfView: CPDFView!, add page: CPDFPage!, add rect: CGRect) { self.recordSaveWatermarkFlag(type: .editImage) if self.listView.isEditImage { self.menuItemEditingClick_CropImage(sender: NSMenuItem()) } else { let panel = NSOpenPanel() panel.allowsMultipleSelection = false panel.allowedFileTypes = ["png","jpg"] panel.beginSheetModal(for: NSApp.mainWindow!) { response in if response == .OK { var filePath = panel.url?.path var image = NSImage.init(contentsOf: panel.url!) //图片自适应范围 if image != nil { var imageRect = rect let imageSize = image!.size var previewSize = rect.size var isChangeSize = false if previewSize.width == 0 && previewSize.height == 0 { previewSize = CGSize(width: 500, height: 500) isChangeSize = true } let scale = min(previewSize.width / imageSize.width, previewSize.height / imageSize.height) let newSize = CGSize(width: imageSize.width * scale, height: imageSize.height * scale) if isChangeSize { imageRect.origin.x = imageRect.origin.x - newSize.width / 2 imageRect.origin.y = imageRect.origin.y - newSize.height / 2 } else { imageRect.origin.x = imageRect.origin.x + imageRect.width / 2 - newSize.width / 2 imageRect.origin.y = imageRect.origin.y + imageRect.height / 2 - newSize.height / 2 } imageRect.size = newSize let limitWidth = 1920.0 if imageSize.width > limitWidth || imageSize.height > limitWidth { filePath = KMImageOptimization.needCompressImageLosslessly(image: image!, targetSize: CGSize(width: limitWidth, height: limitWidth), maxSizeInBytes: 1024 * 1024 * 5, targetCompression: 1.0) } //自适应page let pageRect = self.listView.currentPage().bounds if imageRect.width > pageRect.width || imageRect.height > pageRect.height { let pageScale = min(pageRect.width / imageSize.width, pageRect.height / imageSize.height) imageRect = CGRect(x: imageRect.origin.x, y: imageRect.origin.y, width: imageRect.width * pageScale, height: imageRect.height * pageScale) } if imageRect.origin.x < 0 { imageRect.origin.x = 5 } if imageRect.origin.y < 0 { imageRect.origin.y = 5 } if imageRect.origin.x + imageRect.width > pageRect.width || imageRect.origin.y + imageRect.height > pageRect.height { let offsetX = imageRect.origin.x + imageRect.width - pageRect.width let offsetY = imageRect.origin.y + imageRect.height - pageRect.height imageRect.origin.x = imageRect.origin.x - offsetX - 5 imageRect.origin.y = imageRect.origin.y - offsetY - 5 } DispatchQueue.main.async { self.listView.createImagePath(filePath, rect: imageRect, page: pdfView.currentPage()) self.isPDFTextImageEdited = true self.recordIsPDFDocumentEdited(type: .editImage) // self.asyncSaveDocument { params in // // } } } } } } } func pdfViewEditingAddTextArea(_ pdfView: CPDFView!, add page: CPDFPage!, add rect: CGRect) { // print(rect) var newrect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: rect.size.height) if __CGSizeEqualToSize(rect.size, CGSize.zero) { newrect = CGRect(x: rect.origin.x, y: rect.origin.y - 12, width: 20, height: 12) } else { newrect = CGRect(x: rect.origin.x, y: rect.origin.y + rect.size.height - 12, width: rect.size.width, height: 12) } let model = KMEditPDFTextManager.manager.fetchUserDefaultData(type: .commonly) let fontName = KMEditPDFTextManager.manager.fetchFontName(fontName: model.fontName) let fontSize = model.fontSize let fontColor = model.color let fontAlign = model.alignment let fontStyle = KMEditPDFTextManager.manager.fetchFontStyle(fontName: model.fontName) NSColorPanel.shared.color = fontColor let font = KMEditPDFTextManager.manager.fetchFont(fontName: fontName, style: fontStyle, size: fontSize) let style = NSMutableParagraphStyle() style.alignment = fontAlign let attributes = [NSAttributedString.Key.font:font, NSAttributedString.Key.foregroundColor:fontColor,NSAttributedString.Key.paragraphStyle:style] as [NSAttributedString.Key : Any] self.listView.createEmptyStringBounds(newrect,withAttributes: attributes as [NSAttributedString.Key : Any], page: page) if self.rightSideViewController != nil && self.rightSideViewController.subViewType == .EditPDFAddText && self.listView.annotationType == .addText { self.rightSideViewController.eidtPDFTextProperty.refreshSelectAreaProperty(needDefaultData: true) } // self.asyncSaveDocument { params in // // } self.recordSaveWatermarkFlag(type: .editText) } // func pdfViewEditingDoubleClick(_ pdfView: CPDFView!, imageArea editArea: CPDFEditArea!) { // debugPrint("pdfViewEditingDoubleClick") // } func pdfViewEditingOperationDidChanged(_ pdfView: CPDFView!) { debugPrint("pdfViewEditingOperationDidChanged") if self.listView.isEdited() { self.recordSaveWatermarkFlag() } } // func pdfListViewEditAnnotation(_ pdfListView: CPDFListView!, for anotation: CPDFAnnotation!) { // debugPrint("pdfListViewEditAnnotation") // } func pdfListViewKeyDownIsContinue(_ pdfListView: CPDFListView!, theEvent: NSEvent!) -> Bool { let command = theEvent.modifierFlags.contains(.command) let control = theEvent.modifierFlags.contains(.control) KMPrint(theEvent.keyCode) if (theEvent.keyCode == 11 && command) { // command + B [添加书签] self.menuItemBookMarkClick_add(sender: NSMenuItem()) return false } else if (command && control && theEvent.keyCode == 14) { // command + control + E [注释 橡皮擦] return false } else if (theEvent.keyCode == 123) { // 向左 if(self.listView.isEditing() && !self.listView.isSelecteditAreaNotEdit()) { return false } else { if (self.pdfViewCanHorizontalScroll() == false && self.listView.canGoToPreviousPage()) { self.listView.goToPreviousPage(nil) return false } } } else if (theEvent.keyCode == 126) { // 向上 if(self.listView.isEditing() && !self.listView.isSelecteditAreaNotEdit()) { return false } else { if (self.listView.isContinousScroll()) { return true } if (self.pdfViewCanVerticalScroll() == false && self.listView.canGoToPreviousPage()) { self.listView.goToPreviousPage(nil) return false } } } else if (theEvent.keyCode == 124) { // 向右 if(self.listView.isEditing() && !self.listView.isSelecteditAreaNotEdit()) { return false } else { if (self.pdfViewCanHorizontalScroll() == false && self.listView.canGoToNextPage()) { self.listView.goToNextPage(nil) return false } } } else if (theEvent.keyCode == 125) { // 向下 if(self.listView.isEditing() && !self.listView.isSelecteditAreaNotEdit()) { return false } else { if (self.listView.isContinousScroll()) { return true } if (self.pdfViewCanVerticalScroll() == false && self.listView.canGoToNextPage()) { self.listView.goToNextPage(nil) return false } } } else if (theEvent.keyCode == 36) { if self.listView.annotationType == .addImage || self.listView.annotationType == .addText { if self.listView.isEditImage { self.menuItemEditingClick_CropImage(sender: NSMenuItem()) } } } if theEvent.keyCode == 53 { if self.isReadMode { self.closeReadModel() } self.leftSideViewCancelSelect() if (self.toolbarController.toolbarType.isToolMode()) { self.toolbarController.selectItem(self.toolbarController.toolbarType.itemIdentifier()) } } return true } func pdfListViewMenuValidate(_ pdfListView: CPDFListView!, menuItem: NSMenuItem!, isTakesEffect: UnsafeMutablePointer!) -> Bool { guard let action = menuItem.action else { isTakesEffect.pointee = false return false } if (KMSystemMenu.isEditSelector(sel: action)) { if (KMSystemMenu.Edit.deleteSelector == action) { isTakesEffect.pointee = true return self.listView.activeAnnotations.count > 0 } else if (KMSystemMenu.Edit.copySelector == action) { isTakesEffect.pointee = true return true//self.listView.canCopy() } else if (KMSystemMenu.Edit.cutSelector == action) { isTakesEffect.pointee = true return self.listView.canCopy() } else if (KMSystemMenu.Edit.pasteSelector == action) { isTakesEffect.pointee = true return self.listView.canPaste() } } isTakesEffect.pointee = false return false } //MARK: -CPDFListViewDelegate func cPDFListView(_ pdfListView: CPDFListView, didDelete annotation: CPDFAnnotation, in pdfPage: CPDFPage) { self.leftSideViewController.updateThumbnail(at: Int(pdfPage.pageIndex())) } func pdfListViewChangeatioActiveAnnotations(_ pdfListView: CPDFListView!, forActiveAnnotations annotations: [CPDFAnnotation]!, isRightMenu: Bool) { self.view.window?.makeFirstResponder(self.listView) if isRightMenu { } else if annotations.count > 0 { if annotations.count > 1 { let fristAnnotation = annotations.first var isSameAnnotation = true let className = NSStringFromClass(fristAnnotation!.classForCoder) for annotation in annotations { let cunrrentClassName = NSStringFromClass(annotation.classForCoder) if (className == "CPDFSquareAnnotation") || (className == "CPDFCircleAnnotation") || (className == "CPDFLineAnnotation") { if (cunrrentClassName != "CPDFSquareAnnotation") && (cunrrentClassName != "CPDFCircleAnnotation") && (cunrrentClassName != "CPDFLineAnnotation") { isSameAnnotation = false } } else { if className != cunrrentClassName { isSameAnnotation = false } } } if isSameAnnotation == false { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: false) // self.closeRightPane() } else { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: true) self.openRightPane() } } else { let fristAnnotation = annotations.first let className = NSStringFromClass(fristAnnotation!.classForCoder) if self.isReadMode { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: false) self.closeRightPane() } else { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: true) if className != "CPDFStampAnnotation" && className != "CPDFSignatureAnnotation" && className != "CPDFListStampAnnotation" { self.openRightPane() } } } } else if (annotations.count == 0){ if pdfListView.annotationType == .unkown { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: false) self.closeRightPane() } else { if self.isReadMode { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: false) self.closeRightPane() } else { self.rightSideViewController?.reloadDataWithPDFView(pdfView: pdfListView, isShow: true) self.openRightPane() } } } } func pdfListViewChangedAnnotationType(_ pdfListView: CPDFListView!, for annotationType: CAnnotationType) { if(annotationType == .unkown) { // self.rightSideViewController.view.isHidden = true self.rightSideViewController.isHidden = true self.closeRightPane() } } ///开始定位链接注释 func pdfListViewLinkDestinationStart(_ pdfListView: CPDFListView!, withActiveAnnotation annotation: CPDFAnnotation!) { if self.locationPageView.superview == nil { self.locationPageView.frame = CGRect(x: 0, y: pdfListView.frame.maxY-32, width: pdfListView.frame.width, height: 32) pdfListView.addSubview(self.locationPageView) } } ///刷新链接注释 func pdfListViewLinkDestinationEnd(_ pdfListView: CPDFListView!, withActiveAnnotation annotation: CPDFAnnotation!) { if self.locationPageView.superview != nil { self.locationPageView.removeFromSuperview() } if self.rightSideViewController.subViewType == .AnnotationProperts && pdfListView.annotationType == .link { self.rightSideViewController.reloadDataWithPDFView(pdfView: pdfListView, isShow: true) } } func pdfListViewMenuItemsEditing(at point: CGPoint, for page: CPDFPage!, menuItems: [NSMenuItem]!) -> [NSMenuItem]! { if (listView.toolMode != CToolMode.editPDFToolMode) { return menuItems } var tMenuItems = menuItems; if(listView.isSelectEditCharRange() || listView.isSelecteditArea(with: point)) { tMenuItems?.append(NSMenuItem.separator()) // tMenuItems?.append(self.fontColorMenuItem()) // tMenuItems?.append(self.fontSizeMenuItem()) } let areas = self.listView.editingAreas() ?? [] if areas.count == 1 { let fristAreas = areas.first if fristAreas is CPDFEditImageArea { self.listView.selectImageAreas = fristAreas as? CPDFEditImageArea if self.listView.isEditImage { tMenuItems?.removeAll() tMenuItems?.append(self.corpImageMenuItem()) tMenuItems?.append(self.cancelCorpImageMenuItem()) tMenuItems?.append(self.restoreCorpImageMenuItem()) } else { tMenuItems?.append(NSMenuItem.separator()) tMenuItems?.append(self.cutImageArea()) tMenuItems?.append(self.replaceImageArea()) tMenuItems?.append(self.exportImageArea()) } } else { tMenuItems?.swapAt(0, 1) } } else if areas.count == 0 { tMenuItems?.append(NSMenuItem.separator()) tMenuItems?.append(self.addText()) tMenuItems?.append(self.addImage()) } return tMenuItems } func tableMenu(_ menu: NSMenu, withTable table: KMTableAnnotation, point: CGPoint) -> NSMenu { if table.currentCell.row >= 0 && table.currentCell.column >= 0 { let itemTitles = ["Edit", "", "Add Row Above", "Add Row Below", "", "Add Column Before", "Add Column After", "", "Delete Row", "Delete Column", "Delete Table", "Cut", "Copy", "Paste", "Paste and Match Style", "Delete Cell Contents", "Clear All"] let actions = ["formAnnotTextEdit:", "", "addRowAbove:", "addRowBelow:", "", "addColumnBefore:", "addColumnAfter:", "", "deleteRow:", "deleteColumn:", "deleteTabel", "cutCell:", "copyCell:", "pasteCell:", "pasteAndMatchStyle:", "deleteCellContents:", "clearAll:"] for i in 0..= 5 { item!.action = nil } else if path2.lineJoinStyle == NSBezierPath.LineJoinStyle.bevel && table.footerCount() >= 5 { item!.action = nil } } item!.title = NSLocalizedString(item!.title, comment: "") item!.representedObject = NSValue(point: point) menu.insertItem(item!, at: i) } } } else { let itemTitles = ["Cut", "Copy", "Paste", "Delete"] let actions = ["cut:", "copy:", "paste:", "delete:"] for i in 0..!, isMoveSelectAnno: Bool) { self.mouseRightMenuEvent = theEvent var currentMenu : NSMenu = menu.pointee! if let activeAnno = listView.activeAnnotation as? KMTableAnnotation {//Table var pagePoint = NSPoint() _ = self.listView.pageAndPoint(&pagePoint, for: theEvent, nearest: true) currentMenu.removeAllItems() let annotation = activeAnno annotation.completeEditCellText() if !(NSIsEmptyRect(annotation.drawRect)) { annotation.drawLine(point: pagePoint) NotificationCenter.default.post(name: NSNotification.Name.KMPDFViewTableAnnotationDidChange, object: self, userInfo: ["point": NSValue(point: pagePoint)]) } if (annotation.rowNumber - annotation.currentCell.row - 1) < 0 { return } currentMenu = tableMenu(currentMenu, withTable: listView.activeAnnotation as! KMTableAnnotation, point: pagePoint) listView.needsDisplay = true return } if (listView.toolMode == .selectToolMode){ currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.printingMenu(), at: 3) currentMenu.insertItem(self.setTTSStype(), at: 3) currentMenu.insertItem(self.setCropStype(), at: 3) currentMenu.insertItem(self.setSnapshotStype(), at: 3) let export = NSMenuItem(title: NSLocalizedString("Export", comment: ""), action: nil, target: self) export.submenu = self.exportMenu() currentMenu.insertItem(export, at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.setAnnotationToolStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) return } if (listView.toolMode == .moveToolMode || listView.toolMode == .magnifyToolMode){ currentMenu.insertItem(NSMenuItem.separator(), at: 0) currentMenu.insertItem(self.setTTSStype(), at: 0) currentMenu.insertItem(self.setCropStype(), at: 0) currentMenu.insertItem(self.setSnapshotStype(), at: 0) currentMenu.insertItem(NSMenuItem.separator(), at: 0) currentMenu.insertItem(self.addOutlineStype(), at: 0) currentMenu.insertItem(self.addBookmarkMenu(), at: 0) currentMenu.insertItem(NSMenuItem.separator(), at: 0) currentMenu.insertItem(self.setAnnotationToolStype(), at: 0) return } if currentMenu.items.count > 3 { currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 3) currentMenu.insertItem(self.addReadModelStype(), at: currentMenu.items.count - 3) } if listView.currentSelection != nil{ if listView.currentSelection.selectionType() == .text { currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.setSearchBaiduStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.setLookUpStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.addOutlineStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.setAnnotationToolStype(), at: 3) currentMenu.insertItem(self.setTTSStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) currentMenu.insertItem(self.setShareStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) } currentMenu.insertItem(self.enterAnnotationStype(), at: 3) currentMenu.insertItem(NSMenuItem.separator(), at: 3) if listView.currentSelection.selectionType() == .image{ currentMenu.insertItem(self.setCutStype(), at: 1) currentMenu.insertItem(self.setDeleteStype(), at: 4) currentMenu.insertItem(NSMenuItem.separator(), at: 6) currentMenu.insertItem(self.setEditNoteStype(), at: 6) currentMenu.insertItem(self.setRotateStype(), at: 6) currentMenu.insertItem(self.setLinesStype(), at: 6) currentMenu.insertItem(self.setColorsStype(), at: 6) } if listView.currentSelection.selectionType() == .text { currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count) currentMenu.insertItem(self.setTranslateStype(), at: currentMenu.items.count) currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count) // currentMenu.insertItem(self.setServicesStype(), at: currentMenu.items.count) } } if listView.activeAnnotation != nil || isMoveSelectAnno { if let data = self.listView?.activeAnnotation?.type?.lowercased(), data == "stamp"{ currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.enterAnnotationStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) }else{ currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.enterAnnotationStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.setAnnotationToolStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.addBookmarkMenu(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.addOutlineStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.setSnapshotStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.setCropStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(self.setTTSStype(), at: currentMenu.items.count - 15) currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count - 15) } } if listView.activeAnnotation == nil && listView.currentSelection == nil{ currentMenu.insertItem(NSMenuItem.separator(), at: currentMenu.items.count) if(listView.toolMode == .selectToolMode) { if NSIsEmptyRect(listView.currentSelectionRect()) { currentMenu.insertItem(self.zoomSelectionMenuItem(), at: 0) currentMenu.insertItem(NSMenuItem.separator(), at: 0) } currentMenu.insertItem(self.printingMenu(), at: 0) currentMenu.insertItem(self.setTTSStype(), at: 0) currentMenu.insertItem(self.setCropStype(), at: 0) currentMenu.insertItem(self.setSnapshotStype(), at: 0) let export = NSMenuItem(title: NSLocalizedString("Export", comment: ""), action: nil, target: self) export.submenu = self.exportMenu() currentMenu.insertItem(export, at: currentMenu.items.count) }else{ currentMenu.insertItem(NSMenuItem.separator(), at: 2) currentMenu.insertItem(self.setTTSStype(), at: 2) currentMenu.insertItem(self.setCropStype(), at: 2) currentMenu.insertItem(self.setSnapshotStype(), at: 2) currentMenu.insertItem(NSMenuItem.separator(), at: 2) currentMenu.insertItem(self.addOutlineStype(), at: 2) currentMenu.insertItem(NSMenuItem.separator(), at: 2) currentMenu.insertItem(self.enterAnnotationStype(), at: 2) currentMenu.insertItem(NSMenuItem.separator(), at: 2) if(currentMenu.items.count > 4) { currentMenu.insertItem(NSMenuItem.separator(), at: 5) } if(currentMenu.items.count > 5) { currentMenu.insertItem(self.addBookmarkMenu(), at: 6) } // if (currentMenu.items.count > 6 && self.isReadMode) { // currentMenu.removeItem(currentMenu.item(withTitle: "Zoom")!) // } // currentMenu.insertItem(self.findStringMenu(), at: currentMenu.items.count) currentMenu.insertItem(self.setAutoScrollStype(), at: currentMenu.items.count) } currentMenu.insertItem(self.setAnnotationToolStype(), at: 5) } currentMenu.insertItem(NSMenuItem.separator(), at: 0) currentMenu.insertItem(self.setAITranslateStype(), at: 0) currentMenu.insertItem(self.setAIProofreadStype(), at: 0) currentMenu.insertItem(self.setAIRewriteStype(), at: 0) for item in currentMenu.items { if (item.action == NSSelectorFromString("menuItemClick_HidenorShowNote:")) { // 显示与隐藏注释 item action 截取 item.action = #selector(menuItemClick_HidenorShowNote) item.target = self break } } } func pdfListViewAddAnnotations(_ pdfListView: CPDFListView!, forAdd annotations: [CPDFAnnotation]!, in pdfPage: CPDFPage!) { var addRedact = false var saveWatermark = false var saveWatermarkType: KMSubscribeWaterMarkType = .none for anno in annotations { if (anno.isKind(of: CPDFRedactAnnotation.self)) { addRedact = true // break } else if (anno.isKind(of: CPDFLinkAnnotation.self)) { // link 注释 saveWatermark = true saveWatermarkType = .link } else if (anno.isKind(of: CPDFListStampAnnotation.self)) { // 图章注释 saveWatermark = true saveWatermarkType = .stamp } else if (anno.isKind(of: CPDFListSignatureAnnotation.self)) { // 签名注释 saveWatermark = true saveWatermarkType = .sign } } if (saveWatermark) { self.recordSaveWatermarkFlag(type: saveWatermarkType) } self.hasAddRedact = addRedact if self.isReadMode || self.listView.toolMode == .moveToolMode { self.listView.toolMode = .textToolMode self.listView.annotationType = .unkown self.toolbarController.toolbarType = .Annatiton } if (self.rightMouseEventing) { self.rightMouseEventing = false if (self.toolbarController.ignoreCurrentAnnotationTypeChange && self.listView.annotationType == .ink) { self.listView.toolMode = .textToolMode self.listView.annotationType = .unkown } } self.toolbarController.ignoreCurrentAnnotationTypeChange = false self.leftSideViewController.updateThumbnail(at: Int(pdfPage?.pageIndex() ?? 0)) } func pdfListViewDidSelectionEnd(_ pdfListView: CPDFListView!) { if (!self.listView.isEqual(to: pdfListView)) { return } if (self.listView.toolMode != .selectToolMode) { return } if (self.topTipBox.isHidden || self.topTipBox.contentView?.subviews.count == 0) { return } let tipView = self.topTipBox.contentView?.subviews.first if (tipView?.isKind(of: KMCropTipView.self) == false) { return } (tipView as! KMCropTipView).setString(string: "请按 Enter 键确定裁剪区域") } func pdfListViewKeyDowClosePanel(_ speedy: CPDFViewSidebarSpeedMode, event theEvent: NSEvent!) { if(speedy == .right) { self.toggleRightPane() } else if (speedy == .left) { self.menuItemAction_hiddenLeftSide(speedy) } } func pdfListViewEventMarkupColor(with annotation: CPDFAnnotation!) -> [NSColor]! { if (annotation.isKind(of: CPDFMarkupAnnotation.self)) { if (annotation as! CPDFMarkupAnnotation).markupType() == .highlight { return KMAnnotationPropertiesColorManager.manager.markHighlightColors } else { return KMAnnotationPropertiesColorManager.manager.markOtherColors } } else { return KMAnnotationPropertiesColorManager.manager.markOtherColors } } func pdfListViewHaveDocumentAttribute() -> Bool { if(!self.listView.document.allowsCopying) { self.removeOwnerPassword() return false } return true } func addTopTip(_ view: NSView?) { if (Thread.isMainThread) { if (view == nil) { let contentView: NSView = self.topTipBox.contentView! for subview in contentView.subviews { subview.removeFromSuperview() } self.topTipBox.isHidden = true return } let contentView: NSView = self.topTipBox.contentView! for subview in contentView.subviews { subview.removeFromSuperview() } self.topTipBox.isHidden = false self.topTipBox.contentView?.addSubview(view!) } else { DispatchQueue.main.async { if (view == nil) { let contentView: NSView = self.topTipBox.contentView! for subview in contentView.subviews { subview.removeFromSuperview() } self.topTipBox.isHidden = true return } let contentView: NSView = self.topTipBox.contentView! for subview in contentView.subviews { subview.removeFromSuperview() } self.topTipBox.isHidden = false self.topTipBox.contentView?.addSubview(view!) } } } func pdfListView(_ sender: CPDFListView!, showSnapshotAtPageNumber pageNum: Int, for rect: NSRect, scaleFactor: CGFloat, autoFits: Bool) { let swc = KMSnapshotWindowController(windowNibName: "SnapshotWindow") swc.delegate = self swc.setPdfDocument(self.listView.document, goToPageNumber: pageNum, rect: rect, scaleFactor: scaleFactor, autoFits: autoFits) swc.forceOnTop = self.interactionMode != .normal self.myDocument?.addWindowController(swc) } // 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() } } } } } // MARK: - CPDFDocumentDelegate extension KMMainViewController: CPDFDocumentDelegate { func documentDidBeginDocumentFind(_ document: CPDFDocument!) { self.leftSideViewController.documentDidBeginFind() // [statusBar setProgressIndicatorStyle:SKProgressIndicatorBarStyle]; // [[statusBar progressIndicator] setMaxValue:[[note object] pageCount]]; // [[statusBar progressIndicator] setDoubleValue:0.0]; // [statusBar startAnimation:self]; // [self willChangeValueForKey:SEARCHRESULTS_KEY]; // [self willChangeValueForKey:GROUPEDSEARCHRESULTS_KEY]; } func documentDidEndDocumentFind(_ document: CPDFDocument!) { self.leftSideViewController.documentDidEndFind() // [self didChangeValueForKey:GROUPEDSEARCHRESULTS_KEY]; // [self didChangeValueForKey:SEARCHRESULTS_KEY]; // [statusBar stopAnimation:self]; // [statusBar setProgressIndicatorStyle:SKProgressIndicatorNone]; // NSArray *highlights = [[NSArray alloc] initWithArray:searchResults copyItems:YES]; // [highlights setValue:[NSColor yellowColor] forKey:@"color"]; // [self.pdfView setHighlightedSelections:highlights]; // [highlights release]; } } extension KMMainViewController: KMEditImagePropertyViewControllerDelegate { func editImagePropertyViewControllerDidChanged(controller: KMEditImagePropertyViewController, type: KMEditImagePropertyViewControllerChangeType) { self.isPDFTextImageEdited = true } } extension KMMainViewController: KMSnapshotWindowControllerDelegate { func snapshotControllerWillClose(_ controller: KMSnapshotWindowController) { self.leftSideViewController.snapshotControllerWillClose(controller) } func snapshotController(_ controller: KMSnapshotWindowController, miniaturizedRect isMiniaturize: Bool) -> NSRect { if isMiniaturize && self.interactionMode != .presentation { if self.interactionMode != .legacyFullScreen && self.leftPanelOpen == false { self.toggleLeftPane() } else if self.interactionMode == .legacyFullScreen { // else if ([self interactionMode] == SKLegacyFullScreenMode && ([rightSideWindow state] == NSDrawerClosedState || [rightSideWindow state] == NSDrawerClosingState)) { // [rightSideWindow expand]; // [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(hideRightSideWindow:) userInfo:NULL repeats:NO]; } var row = NSNotFound for (i,sp) in self.leftSideViewController.snapshots.enumerated() { if controller.isEqual(sp.windowC) { row = i } } if (row != NSNotFound) { self.leftSideViewController.leftView.segmentedControl.selectedSegment = 3 self.leftSideViewController.snapshotTableView.scrollRowToVisible(row) } } return self.leftSideViewController.snapshotController(controller, miniaturizedRect: isMiniaturize) } func snapshotControllerDidFinishSetup(_ controller: KMSnapshotWindowController) { self.leftSideViewController.snapshotControllerDidFinishSetup(controller) } } //MARK: document数据保存 extension KMMainViewController { func currentSetup() -> [String: Any] { var setup: [String: Any] = [:] var point = NSZeroPoint // var rotated = listView.currentPage().rotation let pageIndex = listView.currentPageIndexAndPoint(&point, rotated: nil) setup[MAINWINDOWFRAME_KEY] = NSStringFromRect(mainWindow?.frame ?? NSZeroRect) setup[LEFTSIDEPANEWIDTH_KEY] = lastLeftPanWidth setup[RIGHTSIDEPANEWIDTH_KEY] = lastRightPanWidth setup[PAGEINDEX_KEY] = 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 } }