// // KMMainViewController.swift // PDF Reader Pro // // Created by wanjun on 2022/12/15. // import Cocoa import KMComponentLibrary let MIN_SIDE_PANE_WIDTH: NSNumber = 264 // 最小值 let CPDFViewIsReadModeKey = "kKMPDFViewIsReadMode" let CPDFViewLeftSidePaneWidthKey = "CPDFOfficeLeftSidePaneWidthKey" struct KMNMWCFlags { var settingUpWindow: Bool = true } @objcMembers class KMMainViewController: KMNBaseViewController, NSTextFieldDelegate { @IBOutlet var contendBox: NSBox! @IBOutlet var toolbarBox: NSBox! //工具栏Box @IBOutlet var bottomContendBox: NSBox! // @IBOutlet var sidebarBox: NSBox! //左侧边栏Box @IBOutlet var infoContendSplitView: NSSplitView! @IBOutlet var infoSplitLeftView: NSView! @IBOutlet var infoSplitRightView: NSView! @IBOutlet var infoSplitCenterView: NSView! @IBOutlet var pdfSplitView: NSSplitView! @IBOutlet var pdfSplitTopView: NSView! @IBOutlet var pdfSplitBottomView: NSView! @IBOutlet var toolbarBoxHeightConst: NSLayoutConstraint! @IBOutlet var infoSplitViewLeftConst: NSLayoutConstraint! @IBOutlet var infoSplitViewRightConst: NSLayoutConstraint! var viewManager: KMPDFViewManager = KMPDFViewManager.init() var toolbarManager: KMPDFToolbarManager = KMPDFToolbarManager.init() var listView: CPDFListView = CPDFListView.init() var document: CPDFDocument? var myDocument: NSDocument? var isFirstOpen: Bool = true var insertDocuments: Set<CPDFDocument> = [] //插入新文档时,SDK会出现崩溃,临时记录 //工具栏 private var pdfToolbarController: KMPDFToolbarController? //BOTA SideBar private var sideBarController: KMPDFSideBarController? //页面编辑 private var pageEditViewController: KMNPageEditViewController? //DisplaySetting private var displaySettingController: KMNDisplayViewController? //SPlitPDF分屏视图 private var splitPDFController: KMSplitPDFViewController? private var pageNumberToolbar: KMPageNumberPromptView? //PPT操作界面 var presentationTopViewController: KMPresentationTopViewController? //Edit var editToolbarView: KMEditToolbarView? //水印 var watermarkViewController: KMWatermarkController? //背景 var backgroundViewController: KMBackgroundController? //Header&Footer var headerFooterViewController: KMHeaderFooterController? //Bates var batesViewController: KMBatesController? //Crop var cropController: KMCropController? //左边 var botaViewController: KMNLeftSideViewController? //右边 var rightSideController: KMRightSideController? let alertTipViewController: KMNAlertTipViewController = KMNAlertTipViewController(nibName: "KMNAlertTipViewController", bundle: nil) //合并 var mergeWindowController: KMMergeWindowController? //春季活动 var recommondPopWindowVC: KMRecommondPopWindow? //数字签名状态 var signaturestateVC: CDSignatureCertificateStateViewController = CDSignatureCertificateStateViewController.init() //MARK: - 旧代码,有需要用到的拿出来,写好备注 @IBOutlet weak var leftView: NSView! var model = KMMainModel() //自动滚动 var autoFlowOptionsSheetController: KMAutoFlowOptionsSheetController? //Search var searchIndex: Int = 0 //Secure var secureAlertView: KMSecureAlertView? //对比 var isCompareModel: Bool = false { didSet { } } //密码弹窗 var passwordWindow: KMPasswordInputWindow? //对比 var compressWindowController: KMCompressWindowController? // var securityWindowController: KMSecurityWindowController? //引导 var guideInfoWindowController: KMGuideInfoWindowController? var removeAllAnnotationsStore = KMPDFViewRemoveAllAnnotationsStore() private var _needSave = false var needSave: Bool { set { _needSave = newValue if (_needSave == false) { self.clearIsPDFDocumentEdited() } } get { return _needSave } } var isPDFDocumentEdited: Bool { get { return self.model.isPDFDocumentEdited } } var newMwcFlags = KMNMWCFlags(settingUpWindow: true) var searchResults: [KMSearchMode] = [] var mwcFlags: MwcFlags = MwcFlags() weak var browserWindowController: KMBrowserWindowController? //慎直接使用这个方法 var currentWindowController: NSWindowController! var savedNormalSetup: NSMutableDictionary = NSMutableDictionary() var redactController: KMPDFRedactViewController! let CPDFOfficeLeftSidePaneWidthKey = "CPDFOfficeLeftSidePaneWidthKey" let CPDFOfficeRightSidePaneWidthKey = "CPDFOfficeRightSidePaneWidthKey" var extract: KMExtractImageWindowController? var functionWidth: Double { get { if self.viewManager.isPDFReadMode { if !self.model.isShowBOTA { return 0 } } return 48-4 } } var pageNumber: UInt? var pdfEditController: KMPDFEditViewController? { get { return self.getPDFEditController() } } var autoSaveTimer: Timer? private var _documentFirstLoad: Bool = true var eventMonitor: Any? var keyEventMonitor: Any? var mouseRightMenuEvent: NSEvent? lazy private var homeVC: KMNHomeViewController? = { let vc = KMNHomeViewController() return vc }() fileprivate var _secureOptions: [CPDFDocumentWriteOption : Any]? var secureOptions: [CPDFDocumentWriteOption : Any]? { get { return self._secureOptions } } var documentAttribute: [CPDFDocumentAttribute : Any]? fileprivate var _removeSecureFlag = false var removeSecureFlag: Bool { get { return self._removeSecureFlag } } fileprivate var _saveWatermarkFlag = false var saveWatermarkFlag: Bool { get { return self._saveWatermarkFlag } } private var mainWindow_: NSWindow? var mainWindow: NSWindow? { get { return self.mainWindow_ } set { self.mainWindow_ = newValue } } var setDocument: CPDFDocument? { get { return document } set { if document != newValue { document = newValue } listView.document = document botaViewController?.changeDocument(document: document) } } var setPageNumber: UInt { get { return pageNumber! } set { let pageCount = listView.document?.pageCount ?? 0 var value = newValue if value > pageCount { value = pageCount } if value > 0 && listView.currentPage().pageIndex() != value-1 { listView.go(to: listView.document?.page(at: value-1)) } if pageNumber != value { pageNumber = value } } } var distanceMeasureInfoWindowController: CDistanceMeasureInfoWindowController? var perimeterMeasureInfoWindowController: CPerimeterMeasureInfoWindowController? var areaMeasureInfoWindowController: CAreaMeasureInfoWindowController? //MARK: - func deinit { NotificationCenter.default.removeObserver(self) self.listView.delegate = nil self.listView.document?.delegate = nil self.removeEventMonitor() self.removeKeyEventMonitor() } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. setupData() setupUI() NotificationCenter.default.addObserver(self, selector: #selector(pdfViewScrollViewDidScroll), name: NSScrollView.didLiveScrollNotification, object: listView.documentView()) NotificationCenter.default.addObserver(self, selector: #selector(pageCountChangedNotification), name: NSNotification.Name.CPDFDocumentPageCountChanged, object: listView.document) loadUserDefaultsData() } override func viewDidAppear() { super.viewDidAppear() reloadPopUIWindow() } override func viewDidDisappear() { super.viewDidDisappear() toggleClosePopUIWindow() } override func initContentView() { super.initContentView() } override func updateUIThemeColor() { super.updateUIThemeColor() } override func updateUILanguage() { super.updateUILanguage() } //MARK: - private func setupUI() { initPDFView() initToolbar() initSideBar() setUpSplitView() } func setupData() { toolbarManager.pdfViewManager = viewManager if (UserDefaults.standard.object(forKey: CPDFViewLeftSidePaneWidthKey) != nil) { UserDefaults.standard.set(MIN_SIDE_PANE_WIDTH, forKey: CPDFViewLeftSidePaneWidthKey) UserDefaults.standard.synchronize() } newMwcFlags.settingUpWindow = true } //MARK: - document load成功 private func documentLoadComplete() { loadUserDefaultsData() initLeftSideController() addNotificationCenter() activityLoadMethod() let readModel = UserDefaults.standard.bool(forKey: CPDFViewIsReadModeKey) if readModel == true { self.openPDFReadMode() } toggleCloseLeftSide() //根据偏好设置显示左边栏状态 reloadDigitalSigns() alertTipViewController.showInView(listView) alertTipViewController.formFieldHighlightCallback = { [weak self] in let highlightFormFiled = CPDFKitConfig.sharedInstance().enableFormFieldHighlight() CPDFKitConfig.sharedInstance().setEnableFormFieldHighlight(!highlightFormFiled) self?.listView.setNeedsDisplayForVisiblePages() } alertTipViewController.enterPasswordCallback = { [weak self] in self?.removeOwnerPassword() } alertTipViewController.digitalDetailsCallback = { [weak self] in } alertTipViewController.redactApplyCallback = { [weak self] in let returnCode = KMAlertTool.runModelForMainThread_r(message: "", informative: KMLocalizedString("This will permanently remove the redacted information from this document. Once you save this document, you won’t be able to retrieve the redacted information."), buttons: [KMLocalizedString("Apply"), KMLocalizedString("Cancel")]) if returnCode == .alertFirstButtonReturn { DispatchQueue.main.async { self?.saveAsPath() } } } newMwcFlags.settingUpWindow = false } private func saveAsPath() { let saveAccessCtr = KMSavePanelAccessoryController() var fileName = listView.document.documentURL.deletingPathExtension().lastPathComponent fileName = String(format: "%@_%@.pdf", fileName, "Redact") let outputSavePanel = NSSavePanel() outputSavePanel.allowedFileTypes = ["pdf"] outputSavePanel.nameFieldStringValue = fileName outputSavePanel.accessoryView = saveAccessCtr.view outputSavePanel.beginSheetModal(for: NSApp.mainWindow!) { result in if result == .OK { self.listView.document.applyRedactions() self.showProgressWindow(message: KMLocalizedString("Save") + "PDF") self.progressC?.maxValue = 3.0 self.progressC?.increment(by: 1.0) let savePDFPath = outputSavePanel.url!.path // 执行进度 [假进度] self.progressC?.increment(by: 1.0) self.progressC?.increment(by: 1.0) let isSuccess = self.listView.document.write(toFile: savePDFPath) if (isSuccess) { if (saveAccessCtr.openAutomaticButton.state == .on) { NSDocumentController.shared.km_safe_openDocument(withContentsOf: outputSavePanel.url!, display: true) { _, _, _ in } } else { let url = URL(fileURLWithPath: savePDFPath) NSWorkspace.shared.activateFileViewerSelecting([url]) } } self.hiddenProgressWindow() } } } private func reloadDigitalSigns() { let signatures = listView.document.signatures() for i in 0 ..< (signatures?.count ?? 0) { let signature:CPDFSignature = signatures?[i] ?? CPDFSignature() if signature.signers.count > 0 { signature.verifySignature(with: listView.document)//耗时,注意 } } listView.signatures = signatures } //MARK: - 活动加载相关 private func activityLoadMethod() { } private func addNotificationCenter() { NotificationCenter.default.addObserver(self, selector: #selector(annotationsAttributeHasChange), name: NSNotification.Name.CPDFListViewAnnotationsAttributeHasChange, object:nil) NotificationCenter.default.addObserver(self, selector: #selector(signatureStateChangeNoti), name: NSNotification.Name(rawValue: "CSignatureTrustCerDidChangeNotification"), object: nil) } private func loadUserDefaultsData() { applyLeftSideWidth(0, rightSideWidth: 0) //初始打开左边栏 } func applyLeftSideWidth(_ leftSideWidth: CGFloat, rightSideWidth: CGFloat) -> Void { infoContendSplitView.setPosition(infoContendSplitView.maxPossiblePositionOfDivider(at: 1) - infoContendSplitView.dividerThickness - rightSideWidth, ofDividerAt: 1) infoContendSplitView.setPosition(leftSideWidth, ofDividerAt: 0) } //MARK: - PDFView func initPDFView() { listView.autoresizingMask = [.width, .height] listView.autoScales = true listView.delegate = self listView.pdfListViewDelegate = self listView.document = self.document listView.pageBreakMargins = NSEdgeInsetsMake(10, 0, 10, 10) reloadPDFSplitInfo() } func updatePDFViewAnnotationMode() { let toolbarMode = viewManager.toolMode let subToolMode = viewManager.subToolMode listView.isHidden = false if toolbarMode == .None { listView.annotationType = .unkown } else if toolbarMode == .Markup { if subToolMode == .None { listView.toolMode = .CTextToolMode } else { listView.toolMode = .CNoteToolMode } //MARK: -Markup if subToolMode == .None { listView.annotationType = .unkown } else if subToolMode == .Highlight { listView.annotationType = .highlight } else if subToolMode == .Underline { listView.annotationType = .underline } else if subToolMode == .Waveline { listView.annotationType = .squiggly } else if subToolMode == .Strikethrough { listView.annotationType = .strikeOut } else if subToolMode == .Text { listView.annotationType = .freeText } else if subToolMode == .Note { listView.annotationType = .anchored } else if subToolMode == .Pen { listView.annotationType = .ink } else if subToolMode == .Eraser { listView.annotationType = .eraser } else if subToolMode == .Rectangle { listView.annotationType = .square } else if subToolMode == .Circle { listView.annotationType = .circle } else if subToolMode == .Arrow { listView.annotationType = .arrow } else if subToolMode == .Line { listView.annotationType = .line } else if subToolMode == .Measure { listView.annotationType = .measureLine } else if subToolMode == .Stamp { listView.annotationType = .stamp } else if subToolMode == .Sign { listView.annotationType = .signSignature } } else if toolbarMode == .Edit { //MARK: -编辑 if subToolMode == .None { if listView.toolMode != .CEditPDFToolMode { listView.toolMode = .CEditPDFToolMode listView.configPDFEditingInfo() } listView.setShouAddEdit([]) listView.change([.text, .image]) } else if subToolMode == .Edit_text { if listView.toolMode != .CEditPDFToolMode { listView.toolMode = .CEditPDFToolMode listView.configPDFEditingInfo() } listView.setShouAddEdit([.text]) listView.change(.text) } else if subToolMode == .Edit_Image { if listView.toolMode != .CEditPDFToolMode { listView.toolMode = .CEditPDFToolMode listView.configPDFEditingInfo() } listView.setShouAddEdit([.image]) listView.change(.image) } else if subToolMode == .Edit_Link { listView.toolMode = .CEditLinkToolMode listView.annotationType = .link } else if subToolMode == .Edit_Crop { listView.isHidden = true listView.toolMode = .CCropToolMode } if viewManager.editType == .watermark || viewManager.editType == .background || viewManager.editType == .header_Footer || viewManager.editType == .bates { listView.isHidden = true listView.toolMode = .CTextToolMode } if subToolMode != .Edit_Crop { removeCropController() } } else if toolbarMode == .Form { //MARK: -Form表单 listView.toolMode = .CFormToolMode if subToolMode == .None { listView.annotationType = .unkown } else if subToolMode == .Form_text { listView.annotationType = .textField } else if subToolMode == .Form_checkbox { listView.annotationType = .checkBox } else if subToolMode == .Form_radio { listView.annotationType = .radioButton } else if subToolMode == .Form_list { listView.annotationType = .listMenu } else if subToolMode == .Form_dropdown { listView.annotationType = .comboBox } else if subToolMode == .Form_OK { listView.annotationType = .actionButton } else if subToolMode == .Form_digitalSign { listView.annotationType = .signature } } else if toolbarMode == .Fill { //MARK: -填充 if subToolMode == .None { listView.toolMode = .CTextToolMode } else { listView.toolMode = .CNoteToolMode } if subToolMode == .None { } else if subToolMode == .Fill_tick { listView.annotationType = .signTure } else if subToolMode == .fill_fork { listView.annotationType = .signFalse } else if subToolMode == .fill_rectangle { listView.annotationType = .signCircle } else if subToolMode == .fill_line { listView.annotationType = .signLine } else if subToolMode == .fill_dot { listView.annotationType = .signDot } else if subToolMode == .fill_date { listView.annotationType = .signDate } else if subToolMode == .fill_sign { listView.annotationType = .signSignature } } else if toolbarMode == .Convert { //MARK: -转档 listView.toolMode = .CTextToolMode } else if toolbarMode == .Protect { //MARK: -Protect listView.toolMode = .CTextToolMode /* let properties = KMRedactPropertiesWindowController() self.km_beginSheet(windowC: properties) */ if subToolMode == .Redact { //密文 listView.annotationType = .redact listView.toolMode = .CRedactToolMode } else if subToolMode == .Digital_Sign { //数字签名 listView.annotationType = .digitalSign listView.toolMode = .CDigitalSignToolMode } } else if toolbarMode == .Tools { //MARK: -工具 if subToolMode == .Tool_OCR { listView.toolMode = .COCRToolMode } else { listView.toolMode = .CTextToolMode } } } func showOrHideNotes() { self.listView.hideNotes = !self.listView.hideNotes if self.listView.hideNotes { listView.annotationType = .unkown } for note in self.listView.notes as? [CPDFAnnotation] ?? [] { if note.isForm() { note.setAnnotationShouldDisplay(true) note.setHidden(false) } } self.listView.setNeedsDisplayAnnotationViewForVisiblePages() } //MARK: - SplitView func setUpSplitView() { infoContendSplitView.wantsLayer = true infoContendSplitView.layer?.backgroundColor = NSColor.clear.cgColor infoContendSplitView.delegate = self infoContendSplitView.layer?.masksToBounds = true } func setupSplitPDFController() { if splitPDFController == nil { splitPDFController = KMSplitPDFViewController.init() } splitPDFController?.view.frame = pdfSplitBottomView.bounds splitPDFController?.view.autoresizingMask = [.height, .width] splitPDFController?.viewManager = self.viewManager splitPDFController?.delegate = self splitPDFController?.reloadData() pdfSplitBottomView.addSubview(splitPDFController!.view) } //MARK: - 工具栏 func initToolbar() { toolbarBox.borderWidth = 0 if pdfToolbarController == nil { pdfToolbarController = KMPDFToolbarController.init() } pdfToolbarController?.view.frame = toolbarBox.bounds pdfToolbarController?.view.autoresizingMask = [.width, .height] pdfToolbarController?.delegate = self toolbarBox.contentView = pdfToolbarController?.view pdfToolbarController?.viewManager = viewManager pdfToolbarController?.toolbarManager = toolbarManager pdfToolbarController?.pdfView = listView pdfToolbarController?.setUpData() refreshToolbarViewHeightInfo() if listView.showFormFieldName { toolbarManager.form_ShowName_Property.righticon = NSImage(named: "tick_Green") } else { toolbarManager.form_ShowName_Property.righticon = nil } DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.15) { self.pdfToolbarController?.clickWithIdentify(KMPDFToolbar_Markup_Identifier) } } func refreshToolbarViewHeightInfo() { let _viewManager = viewManager if viewManager.isPageEditMode { toolbarBoxHeightConst.constant = 80 } else if viewManager.editType == .watermark || viewManager.editType == .background || viewManager.editType == .header_Footer || viewManager.editType == .bates { toolbarBoxHeightConst.constant = 40 } else if _viewManager.toolMode == .Markup || _viewManager.toolMode == .Edit || _viewManager.toolMode == .Form || _viewManager.toolMode == .Fill || _viewManager.toolMode == .Convert || _viewManager.toolMode == .Protect || _viewManager.toolMode == .Tools { toolbarBoxHeightConst.constant = 80 if _viewManager.subToolMode == .Redact { toolbarBoxHeightConst.constant = 40 } } else { toolbarBoxHeightConst.constant = 40 } } func toolbarViewModeChanged() { updatePDFViewAnnotationMode() if viewManager.showRightSide == true { toggleOpenRightSide() } else { toggleCloseRightSide() } if viewManager.toolMode != .Edit && viewManager.subToolMode != .Edit_Crop { removeCropController() } } //MARK: - 侧边工具栏 func initSideBar() { sidebarBox.borderWidth = 0 if sideBarController == nil { sideBarController = KMPDFSideBarController.init() } sideBarController?.view.frame = sidebarBox.bounds sideBarController?.view.autoresizingMask = [.width, .height] sidebarBox.contentView = sideBarController?.view sideBarController?.pdfView = listView sideBarController?.delegate = self sideBarController?.pdfViewManager = viewManager sideBarController?.reloadData() } //MARK: - 左边侧边栏 func initLeftSideController() { if botaViewController == nil { botaViewController = KMNLeftSideViewController(listView.document) } botaViewController?.leftSideViewDelegate = self botaViewController?.view.frame = infoSplitLeftView.bounds botaViewController?.view.autoresizingMask = [.width, .height] if botaViewController != nil { infoSplitLeftView?.addSubview(botaViewController!.view) } } private func leftSidePaneIsOpen() -> Bool { return !infoContendSplitView.isSubviewCollapsed(infoSplitLeftView) //第一次点击时存在问题,待解决 } private func toggleOpenLeftSide(pdfSideBarType: KMPDFSidebarType) { if(leftSidePaneIsOpen() == false) { let leftWidthNumber = UserDefaults.standard.object(forKey: CPDFViewLeftSidePaneWidthKey) as? NSNumber ?? MIN_SIDE_PANE_WIDTH infoContendSplitView.setPosition(MIN_SIDE_PANE_WIDTH.doubleValue, ofDividerAt: 0) //暂时无法记录上一次打开的宽度 } if pdfSideBarType == .search { botaViewController?.searchViewC.handdler.pdfView = listView botaViewController?.leftsideType = .search } else if pdfSideBarType == .thumbnail { botaViewController?.leftsideType = pdfSideBarType botaViewController?.thumnailViewController?.reloadDatas() botaViewController?.currentPageDidChangedAction(listView: listView) } else if pdfSideBarType == .outline { botaViewController?.outlineViewC.handdler.pdfView = listView botaViewController?.leftsideType = pdfSideBarType } else if pdfSideBarType == .bookmark { botaViewController?.bookmarkViewC.handdler.pdfView = listView botaViewController?.leftsideType = pdfSideBarType } else if pdfSideBarType == .annotation { // botaViewController?.annoController.handdler.pdfView = listView // botaViewController?.leftsideType = .annotation } } private func toggleCloseLeftSide() { if(leftSidePaneIsOpen() == true) { infoContendSplitView.setPosition(0, ofDividerAt: 0) } } //MARK: - 右侧属性栏 func initRightSideController() { if rightSideController == nil { rightSideController = KMRightSideController.init() rightSideController?.delegate = self } rightSideController?.view.frame = CGRectMake(0, 0, MIN_SIDE_PANE_WIDTH.doubleValue, 680) rightSideController?.view.autoresizingMask = [.height, .maxXMargin] } func removeRightSideController() { rightSideController?.view.removeFromSuperview() rightSideController = nil } @objc func toggleOpenRightSide() -> Void { if rightSideController != nil { return } initRightSideController() rightSideController?.view.frame = infoSplitRightView.bounds rightSideController?.view.autoresizingMask = [.width, .height] infoSplitRightView.addSubview(rightSideController!.view) infoContendSplitView.setPosition(CGRectGetWidth(view.frame)-MIN_SIDE_PANE_WIDTH.doubleValue, ofDividerAt: 1) rightSideController?.viewManager = self.viewManager rightSideController?.reloadDataWithPDFView(pdfView: listView) } @objc func toggleCloseRightSide() -> Void { removeRightSideController() infoContendSplitView.setPosition(CGRectGetWidth(view.frame), ofDividerAt: 1) } func refreshRightSide() -> Void { if let rightVC = rightSideController, let _ = rightSideController?.view.superview { rightVC.reloadDataWithPDFView(pdfView: listView) } } //MARK: - PDFDisplayView func updatePDFDisplaySettingView() { if viewManager.showDisplayView { infoSplitViewLeftConst.constant = MIN_SIDE_PANE_WIDTH.doubleValue } else { infoSplitViewLeftConst.constant = 44 } if viewManager.showDisplayView { if displaySettingController == nil { displaySettingController = KMNDisplayViewController.init() } displaySettingController?.view.frame = CGRectMake(0, 0, MIN_SIDE_PANE_WIDTH.doubleValue, CGRectGetHeight(bottomContendBox.frame)) displaySettingController?.view.autoresizingMask = [.height, .maxXMargin] bottomContendBox.addSubview(displaySettingController!.view) displaySettingController?.pdfView = self.listView displaySettingController?.viewManager = self.viewManager displaySettingController?.delegate = self displaySettingController?.reloadData() } else { displaySettingController?.view.removeFromSuperview() displaySettingController = nil } } //MARK: - 页面编辑 func enterPageEditMode() { pageEditViewController = KMNPageEditViewController(self.document) if(pageEditViewController != nil) { bottomContendBox.addSubview(pageEditViewController!.view) pageEditViewController?.view.frame = bottomContendBox.bounds pageEditViewController?.thumbnailBaseViewDelegate = self pageEditViewController?.selectionIndexPaths = [IndexPath(item: listView.currentPageIndex, section: 0)] pageEditViewController?.view.autoresizingMask = [.width,.height] pageEditViewController?.currentUndoManager = listView.undoManager toolbarManager.page_pageInfo_Property.text = String(listView.currentPageIndex + 1) pdfToolbarController?.refreshSecondToolbarItemsState() listView.isHidden = true } } func exitPageEditMode() { if pageEditViewController != nil { pageEditViewController?.view.removeFromSuperview() pageEditViewController = nil } listView.isHidden = false if listView.document?.isModified() == true { listView.layoutDocumentView() botaViewController?.thumnailViewController?.reloadDatas() } } //MARK: - 阅读模式 func openPDFReadMode() { if viewManager.showDisplayView { viewManager.showDisplayView = false pdfToolbarController?.reloadLeftIconView() updatePDFDisplaySettingView() } infoSplitViewLeftConst.constant = 0 toolbarBoxHeightConst.constant = 0 view.window?.makeFirstResponder(listView) let readModeMessage: ComponentMessage = ComponentMessage() readModeMessage.properties = ComponentMessageProperty(messageType: .normal_custom, title: KMLocalizedString("Read Mode On")) readModeMessage.frame = CGRectMake((CGRectGetWidth(self.view.frame) - readModeMessage.properties.propertyInfo.viewWidth)/2, CGRectGetHeight(self.view.frame) - readModeMessage.properties.propertyInfo.viewHeight - 8, readModeMessage.properties.propertyInfo.viewWidth, readModeMessage.properties.propertyInfo.viewHeight) readModeMessage.reloadData() readModeMessage.show(inView: self.view, autoHideSeconde: 2) setUpPDFPageNumberToolbar() } func exitPDFReadMode() { viewManager.isPDFReadMode = false if viewManager.showDisplayView == false { viewManager.showDisplayView = true pdfToolbarController?.reloadLeftIconView() } updatePDFDisplaySettingView() refreshToolbarViewHeightInfo() reloadPDFPageNumberToolbar() let readModeMessage: ComponentMessage = ComponentMessage() readModeMessage.properties = ComponentMessageProperty(messageType: .normal_custom, title: KMLocalizedString("Read Mode Off")) readModeMessage.frame = CGRectMake((CGRectGetWidth(self.view.frame) - readModeMessage.properties.propertyInfo.viewWidth)/2, CGRectGetHeight(self.view.frame) - readModeMessage.properties.propertyInfo.viewHeight - 8, readModeMessage.properties.propertyInfo.viewWidth, readModeMessage.properties.propertyInfo.viewHeight) readModeMessage.reloadData() readModeMessage.show(inView: self.view, autoHideSeconde: 2) } //MARK: - PPT func togglePresentation(_ sender: Any?) { if self.canExitPresentation() { exitFullScreen() } else if self.canEnterPresentation() { 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) view.window?.enterPresentation(provider: self) } } func enterPresentationMode() { let scrollView = listView.documentView().enclosingScrollView savedNormalSetup.setValue(scrollView?.hasHorizontalScroller, forKey: KMMainModel.Key.kHasHorizontalScroller) savedNormalSetup.setValue(scrollView?.hasVerticalScroller, forKey: KMMainModel.Key.kHasVerticalsCroller) savedNormalSetup.setValue(scrollView?.autohidesScrollers, forKey: KMMainModel.Key.kAutoHidesScrollers) listView.backgroundColor = NSColor.clear listView.setDisplay(.singlePage) listView.autoScales = true listView.displayBox = .cropBox listView.displaysPageBreaks = false scrollView?.autohidesScrollers = true scrollView?.hasHorizontalScroller = false scrollView?.hasVerticalScroller = false listView.setCurrentSelection(nil, animate: true) } func exitPresentationMode() { NotificationCenter.default.removeObserver(self, name: NSWindow.willEnterInteractionModeNotification, object: nil) NotificationCenter.default.removeObserver(self, name: NSWindow.didEnterInteractionModeNotification, object: nil) NotificationCenter.default.removeObserver(self, name: NSWindow.willShowFullScreenNotification, object: nil) NotificationCenter.default.removeObserver(self, name: NSWindow.willShowFullScreenNotification, object: nil) } func exitFullScreen() { if self.canExitPresentation() == true { let mainDocument = self.myDocument as? KMMainDocument let browserWindowController = mainDocument?.browser?.windowController as? KMBrowserWindowController browserWindowController?.exitFullscreen() } } func exitFullscreenMode() { if self.interactionMode == .presentation { self.exitPresentationMode() } self.applyPDFSettings(self.savedNormalSetup) self.savedNormalSetup.removeAllObjects() listView.layoutDocumentView() listView.requiresDisplay() if let backgroundColor = UserDefaults.standard.color(forKey: KMBackgroundColorKey) { listView.backgroundColor = backgroundColor } } func applyPDFSettings(_ setup: NSDictionary) { if let data = setup.object(forKey: KMMainModel.Key.kAutoScales) as? NSNumber { self.listView.autoScales = data.boolValue } if self.listView.autoScales == false { if let data = setup.object(forKey: KMMainModel.Key.kScaleFactor) as? NSNumber { self.listView.scaleFactor = data.floatValue.cgFloat } } if let data = setup.object(forKey: KMMainModel.Key.kDisplayMode) as? NSNumber { self.listView.setDisplay(CPDFDisplayViewMode(rawValue: data.intValue) ?? .singlePage) } if let data = setup.object(forKey: KMMainModel.Key.kDisplaysAsBook) as? NSNumber { self.listView.displaysAsBook = data.boolValue } if let data = setup.object(forKey: KMMainModel.Key.kDisplaysPageBreaks) as? NSNumber { self.listView.displaysPageBreaks = data.boolValue } if let data = setup.object(forKey: KMMainModel.Key.kDisplayBox) as? NSNumber { } self.listView.layoutDocumentView() } func currentPDFSettings() -> NSDictionary { let setup = NSMutableDictionary() setup[KMMainModel.Key.kDisplaysPageBreaks] = NSNumber(value: listView.displaysPageBreaks) setup[KMMainModel.Key.kDisplaysAsBook] = NSNumber(value: listView.displaysAsBook) setup[KMMainModel.Key.kDisplayBox] = NSNumber(value: listView.displayBox.rawValue) setup[KMMainModel.Key.kScaleFactor] = NSNumber(value: listView.scaleFactor) setup[KMMainModel.Key.kAutoScales] = NSNumber(value: listView.autoScales) setup[KMMainModel.Key.kDisplayMode] = NSNumber(value: listView.fetchDisplayViewMode().rawValue) return setup } func canEnterFullscreen() -> Bool { if (mwcFlags.isSwitchingFullScreen != 0) { return false } if useNativeFullScreen() { return interactionMode == .normal || interactionMode == .presentation } else { return !self.listView.document.isLocked && (interactionMode == .normal || interactionMode == .presentation) && self.view.window?.tabbedWindows?.count ?? 0 < 2 } } override func canEnterPresentation() -> Bool { let can = super.canEnterPresentation() if can == false { return false } guard let doc = self.listView.document, doc.isLocked == false else { return false } return can } func fadeOutFullScreenWindow() { guard let fullScreenWindow = self.view.window as? KMFullScreenWindow else { NSSound.beep() return } let mainWindow = fullScreenWindow.interactionParent let collectionBehavior = mainWindow?.collectionBehavior mainWindow?.alphaValue = 0 if let data = mainWindow?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data { mainWindow?.animationBehavior = .none } // trick to make sure the main window shows up in the same space as the fullscreen window fullScreenWindow.addChildWindow(mainWindow!, ordered: .below) fullScreenWindow.removeChildWindow(mainWindow!) fullScreenWindow.level = .popUpMenu // these can change due to the child window trick mainWindow?.level = .normal mainWindow?.alphaValue = 1.0 mainWindow?.collectionBehavior = collectionBehavior! mainWindow?.display() mainWindow?.makeFirstResponder(self.listView) mainWindow?.recalculateKeyViewLoop() // mainWindow?.delegate = self mainWindow?.makeKey() if let data = mainWindow?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data { mainWindow?.animationBehavior = .default } NSApp.removeWindowsItem(fullScreenWindow) fullScreenWindow.fadeOut() } //MARK: - PDF分屏视图 func reloadPDFSplitInfo() { if listView.viewSplitMode == .disable { pdfSplitView.isHidden = true listView.frame = infoSplitCenterView.bounds infoSplitCenterView.addSubview(listView) if splitPDFController != nil { splitPDFController = nil } } else { pdfSplitView.isHidden = false listView.frame = pdfSplitTopView.bounds pdfSplitTopView.addSubview(listView) setUpPDFPageNumberToolbar() setupSplitPDFController() if listView.viewSplitMode == .horizontal { pdfSplitView.isVertical = false } else if listView.viewSplitMode == .vertical { pdfSplitView.isVertical = true } } } func setUpPDFPageNumberToolbar() { if pageNumberToolbar != nil { pageNumberToolbar?.removeFromSuperview() pageNumberToolbar = nil } if pageNumberToolbar == nil { pageNumberToolbar = KMPageNumberPromptView.init() } pageNumberToolbar?.frame = CGRectMake(CGRectGetWidth(listView.frame)/2-144, 20, 288, 40) pageNumberToolbar?.autoresizingMask = [.minXMargin, .maxXMargin, .maxYMargin] pageNumberToolbar?.pdfView = self.listView pageNumberToolbar?.reloadData() pageNumberToolbar?.isHidden = true listView.addSubview(pageNumberToolbar!) reloadPDFPageNumberToolbar() } func reloadPDFPageNumberToolbar() { if viewManager.isPDFReadMode == true || (viewManager.splitShowBottomBar && listView.viewSplitMode != .disable) { pageNumberToolbar?.isHidden = false pageNumberToolbar?.reloadData() } else { pageNumberToolbar?.isHidden = true } } //MARK: - Edit模式 func showEditToolbarView() { if editToolbarView == nil { editToolbarView = KMEditToolbarView() } editToolbarView?.frame = toolbarBox.bounds editToolbarView?.delegate = self editToolbarView?.autoresizingMask = [.width, .height] toolbarBox.contentView = editToolbarView } func exitEditToolbarView() { viewManager.editType = .none viewManager.subToolMode = .None editToolbarView?.removeFromSuperview() editToolbarView = nil watermarkViewController?.view.removeFromSuperview() watermarkViewController = nil backgroundViewController?.view.removeFromSuperview() backgroundViewController = nil headerFooterViewController?.view.removeFromSuperview() headerFooterViewController = nil batesViewController?.view.removeFromSuperview() batesViewController = nil refreshToolbarViewHeightInfo() toolbarBox.contentView = pdfToolbarController?.view updatePDFViewAnnotationMode() } func updateEditModeDocumentWhenPageChanged() { if viewManager.editType == .watermark { updateWatermarkDocument() } else if viewManager.editType == .background { updateBackgroundDocument() } else if viewManager.editType == .header_Footer { updateHeaderFooterDocument() } else if viewManager.editType == .bates { updateBatesDocument() } else if viewManager.subToolMode == .Edit_Crop { updateCropDocument() } } //MARK: - 数字签名 func writeSignatureToWidget(_ widget: CPDFSignatureWidgetAnnotation, _ path: String, _ password: String, _ config: CPDFSignatureConfig, _ isLock: Bool) ->() { let fileName = listView.document.documentURL?.lastPathComponent let fileNameWithoutExtension = URL(fileURLWithPath: fileName!).deletingPathExtension().lastPathComponent let outputSavePanel = NSSavePanel() outputSavePanel.directoryURL = listView.document.documentURL.deletingLastPathComponent() outputSavePanel.title = NSLocalizedString("", comment: "Save as PDF") outputSavePanel.allowedFileTypes = ["pdf"] outputSavePanel.nameFieldStringValue = fileNameWithoutExtension + "_" + NSLocalizedString("Signed", comment: "") let result = outputSavePanel.runModal() if result == .OK { let contentArr = NSMutableArray() var locationStr = "" var reasonStr = NSLocalizedString("none", comment: "") for item in config.contents { if item.key == NSLocalizedString("Reason", comment: "") { if item.value == NSLocalizedString("<your signing reason here>", comment: "") { item.value = " " + NSLocalizedString("none", comment: "") } reasonStr = item.value } else if item.key == NSLocalizedString("Location", comment: "") { if item.value == NSLocalizedString("<your signing location here>", comment: "") { item.value = " " } locationStr = item.value } contentArr.add(item) } config.contents = contentArr as? [CPDFSignatureConfigItem] widget.signAppearanceConfig(config) let success = listView.document.writeSignature(to: outputSavePanel.url, withWidget: widget, pkcs12Cert: path, password: password, location: locationStr, reason: reasonStr, permissions: .forbidChange) widget.removeSignature() if success { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { NSDocumentController.shared.openDocument(withContentsOf: outputSavePanel.url!, display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) return } } } } else { let alert = NSAlert.init() alert.messageText = NSLocalizedString("Save failed!", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } widget.page.removeAnnotation(widget) listView.setNeedsDisplayAnnotationViewFor(widget.page) } else { widget.page.removeAnnotation(widget) listView.setNeedsDisplayAnnotationViewFor(widget.page) } } func popUpSignatureWidgetState(_ signature: CPDFSignature, _ pdfListView: CPDFListView) ->(){ signaturestateVC.signature = signature signaturestateVC.pdfListView = pdfListView signaturestateVC.actionBlock = { [weak self, weak signaturestateVC] stateVCSelf, actionType in guard let weakSelf = self, let stateVC = signaturestateVC else { return } if actionType == .cancel { stateVC.dismiss(stateVCSelf) } else if actionType == .confirm { if let signer = signature.signers.first, let data = signer.certificates { let signatureDetail = DSignatureDetailsViewController.init() signatureDetail.certificates = data signatureDetail.signature = signature signatureDetail.pdfListView = pdfListView stateVCSelf.presentAsSheet(signatureDetail) } else { NSSound.beep() } } } self.presentAsSheet(signaturestateVC) signaturestateVC.reloadData() } // MARK: - 显示合并窗口 public func showMergeWindow(url: URL? = nil, _ password: String?) { DispatchQueue.main.async { var documentURL = url if documentURL == nil { documentURL = self.listView.document?.documentURL } guard let _url = documentURL else { return } guard let document = PDFDocument(url: _url) else { return } self.mergeWindowController = KMMergeWindowController(document: document, password: password ?? "") self.mergeWindowController!.oriDucumentUrl = self.listView.document?.documentURL self.mergeWindowController!.pageIndex = self.listView.currentPageIndex self.mergeWindowController!.cancelAction = { [unowned self] controller in self.view.window?.endSheet(mergeWindowController!.window!) } self.mergeWindowController!.mergeAction = { [unowned self] controller, filePath in self.view.window?.endSheet(mergeWindowController!.window!) } self.view.window?.beginSheet(self.mergeWindowController!.window!) } } //MARK: - Crop裁剪 func showCropController() { if cropController == nil { cropController = KMCropController.init() cropController?.view.frame = infoSplitCenterView.bounds cropController?.view.autoresizingMask = [.width, .height] cropController?.delegate = self infoSplitCenterView.addSubview(cropController!.view) updateCropDocument() if viewManager.showRightSide == false { viewManager.showRightSide = true pdfToolbarController?.reloadRightToolsView() toggleOpenRightSide() } } } func updateCropDocument() { guard let controller = cropController else { return } controller.pdfDocument = nil let page = listView.document.page(at: UInt(listView.currentPageIndex)) let editDocument = CPDFDocument.init() editDocument?.insertPageObject(page, at: 0) if let editPage = editDocument?.page(at: 0) { editPage.setBounds(CGRectMake(0, 0, editPage.bounds(for: .mediaBox).size.width, editPage.bounds(for: .mediaBox).size.height), for: .cropBox) controller.selectionRect = page?.bounds(for: .cropBox) ?? .zero } controller.pdfDocument = editDocument controller.reloadData() } func removeCropController() { if cropController != nil { cropController?.view.removeFromSuperview() cropController = nil toolbarManager.edit_crop_Property.state = .normal } } //MARK: - Watermark水印 func showWatermarkController() { viewManager.editType = .watermark showEditToolbarView() editToolbarView?.editType = .watermark if KMWatermarkManager.defaultManager.watermarks.count == 0 { editToolbarView?.editSubType = .add } else { editToolbarView?.editSubType = .template } editToolbarView?.reloadData() if watermarkViewController == nil { watermarkViewController = KMWatermarkController.init() } watermarkViewController?.view.frame = CGRectMake(44, 0, CGRectGetWidth(bottomContendBox.frame)-44, CGRectGetHeight(bottomContendBox.frame)) watermarkViewController?.view.autoresizingMask = [.maxXMargin, .width, .height] watermarkViewController?.delegate = self bottomContendBox.contentView?.addSubview(watermarkViewController!.view) watermarkViewController?.editSubType = editToolbarView?.editSubType ?? .template updateWatermarkDocument() } func updateWatermarkDocument() { guard let controller = watermarkViewController else { return } var editDocument = CPDFDocument.init() if let vcDoc = controller.pdfDocument { editDocument = vcDoc } let page = listView.document.page(at: UInt(listView.currentPageIndex)) editDocument?.insertPageObject(page, at: 0) if editDocument?.pageCount == 2 { let theIndex = IndexSet(integer: 1) editDocument?.removePage(at: theIndex) } if watermarkViewController?.pdfDocument == nil { watermarkViewController?.pdfDocument = editDocument } watermarkViewController?.resetUI() watermarkViewController?.reloadData() } //移除文档水印 func removePDFWatermark() { let watermarks = self.listView.document.watermarks() if (watermarks == nil || watermarks!.count <= 0) { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Could not find a removable watermark in this document. If you see a watermark, it was not added with PDF Reader Pro and therefore cannot be detected.", comment: "") alert.addButton(withTitle: NSLocalizedString("Confirm", comment: "")) alert.runModal() return } let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Are you sure you want to remove the watermark?", comment: "") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result == .alertFirstButtonReturn) { for watermark in watermarks! { listView.document.removeWatermark(watermark) } listView.layoutDocumentView() _ = KMNCustomAlertView.alertView(message: KMLocalizedString("Watermark removed"), type: .success, fromView: bottomContendBox, point:CGPointMake(CGRectGetWidth(bottomContendBox.frame)/2, CGRectGetHeight(bottomContendBox.frame)-28)) } } func batchAddWatermark() { } func batchRemoveWatermark() { } //MARK: - PopUI func reloadPopUIWindow() { if listView.toolMode == .CSelectToolMode { let pageRect = listView.currentSelectionRect() let page:CPDFPage? = listView.currentSelectionPage() if listView.selectionRect != CGRectZero && page != nil { let positioningRect = listView.convert(pageRect, from: page) if (CGRectIntersectsRect(positioningRect, listView.frame)) { reloadPopUIOperation() return } } toggleClosePopUIWindow() } else if(listView.isEditing() == false) { let activeAnnotations:[CPDFAnnotation] = listView.activeAnnotations as! [CPDFAnnotation] if(activeAnnotations.count > 0) { if let page = activeAnnotations.first?.page { let pageRect = listView.selectionMultipleBounds(with: activeAnnotations) let positioningRect = listView.convert(pageRect, from: page) if (CGRectIntersectsRect(positioningRect, listView.frame)) { reloadPopUIActiveAnnotations(activeAnnotations: activeAnnotations) return } } } toggleClosePopUIWindow() } else { let editAreas:[CPDFEditArea] = listView.km_EditingAreas() if(editAreas.count > 0) { if let page = editAreas.first?.page { let pageRect = listView.selectionMultipleBounds(withEditArea: editAreas) let positioningRect = listView.convert(pageRect, from: page) if (CGRectIntersectsRect(positioningRect, listView.frame)) { reloadPopUIContentEdits(editAreas: editAreas) return } } } toggleClosePopUIWindow() } } func toggleClosePopUIWindow() { let popWindow = KMNPopAnnotationWindowController.shared if popWindow.window?.isVisible == true { closeAnnotationPopWindow() } let editPopWindow = KMNPopContentEditWindowController.shared if editPopWindow.window?.isVisible == true { closePopContentEditWindow() } let operationWindow = KMNPopOperationWindowController.shared if operationWindow.window?.isVisible == true { closePopOperationWindow() } } func closeAnnotationPopWindow() { KMNPopAnnotationWindowController.shared.closeWindow(listView: listView) } func closePopContentEditWindow() { KMNPopContentEditWindowController.shared.closeWindow(listView: listView) } func closePopOperationWindow() { KMNPopOperationWindowController.shared.closeWindow(listView: listView) } func reloadPopUIOperation() { if listView.selectionRect != CGRectZero { let popWindow = KMNPopOperationWindowController.shared if popWindow.window?.isVisible == false { listView.window?.addChildWindow(popWindow.window ?? NSWindow(), ordered: .above) } popWindow.listView = listView if listView.toolMode == .CSelectToolMode { popWindow.popType = .crop } else if listView.toolMode == .COCRToolMode { popWindow.popType = .ocr } updatePopOperationPopWinodwFrame() popWindow.updatePDFViewCallback = {[weak self] in self?.closePopOperationWindow() self?.listView.setNeedsDisplayForVisiblePages() } popWindow.cropCurrentCallback = {[weak self] in let rect = self?.listView.currentSelectionRect() ?? CGRect.zero let orgPage : CPDFPage = self?.listView.currentSelectionPage() ?? CPDFPage() self?.cropPages(atIndexs: [orgPage.pageIndex()], to: [rect]) self?.closePopOperationWindow() } } else { closePopOperationWindow() } } func reloadPopUIActiveAnnotations(activeAnnotations:[CPDFAnnotation]) { let annotationMode = KMNAnnotationPopMode(pdfAnnotations: activeAnnotations ) let popWindow = KMNPopAnnotationWindowController.shared if annotationMode.popType == .popTypeNone { closeAnnotationPopWindow() } else { if popWindow.window?.isVisible == false { listView.window?.addChildWindow(popWindow.window ?? NSWindow(), ordered: .above) } popWindow.listView = listView popWindow.annotationPopMode = annotationMode popWindow.isOpenPane = viewManager.showRightSide updateAnnotationsPopWinodwFrame() popWindow.updatePDFViewCallback = {[weak self] in self?.rightSideController?.reloadDataWithPDFView(pdfView: self?.listView ?? CPDFListView()) self?.listView.setNeedsDisplayMultiAnnotations(annotationMode.annotations) } popWindow.paneCallback = {[weak self] isOpen in if isOpen == true && self?.viewManager.showRightSide == false { self?.toggleCloseRightSide() } else { self?.toggleOpenRightSide() } } } } func reloadPopUIContentEdits(editAreas:[CPDFEditArea]) { let editingAreas = listView.km_EditingAreas() let editMode = KMNEditContentPopMode(currentEditAreas: editingAreas) let popWindow = KMNPopContentEditWindowController.shared if editMode.popType == .editNone { closePopContentEditWindow() } else { listView.window?.addChildWindow(popWindow.window ?? NSWindow(), ordered: .above) popWindow.listView = listView popWindow.editContentPopMode = editMode popWindow.isOpenPane = viewManager.showRightSide updateContentEditPopWinodwFrame() popWindow.paneCallback = {[weak self] isOpen in if isOpen == true && self?.viewManager.showRightSide == false { self?.toggleCloseRightSide() } else { self?.toggleOpenRightSide() } } } } func updateAnnotationsPopWinodwFrame() { let popWindow = KMNPopAnnotationWindowController.shared if popWindow.window?.isVisible == true { popWindow.updateFrame(listView: listView) } } func updateContentEditPopWinodwFrame() { let popWindow = KMNPopContentEditWindowController.shared if popWindow.window?.isVisible == true { popWindow.updateFrame(listView: listView) } } func updatePopOperationPopWinodwFrame() { let popWindow = KMNPopOperationWindowController.shared if popWindow.window?.isVisible == true { popWindow.updateFrame(listView: listView,page: listView.currentSelectionPage()) } } //MARK: - 安全 func removeOwnerPassword() { guard let doc = listView.document else { NSSound.beep() return } if doc.permissionsStatus != .user { NSSound.beep() return } _ = KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: doc.documentURL) { [weak self] result, password in if result == .cancel { /// 关闭 return } self?.listView.document?.unlock(withPassword: password) if doc.permissionsStatus == .owner { self?.alertTipViewController.reloadSecureAlertUI() self?.alertTipViewController.reloadAlertUIFrame() } } } //MARK: - Background背景 func showBackgroundController() { viewManager.editType = .background showEditToolbarView() editToolbarView?.editType = .background if KMBackgroundManager.defaultManager.datas.count == 0 { editToolbarView?.editSubType = .add } else { editToolbarView?.editSubType = .template } editToolbarView?.reloadData() if backgroundViewController == nil { backgroundViewController = KMBackgroundController.init() } backgroundViewController?.view.frame = CGRectMake(44, 0, CGRectGetWidth(bottomContendBox.frame)-44, CGRectGetHeight(bottomContendBox.frame)) backgroundViewController?.view.autoresizingMask = [.maxXMargin, .width, .height] backgroundViewController?.delegate = self bottomContendBox.contentView?.addSubview(backgroundViewController!.view) backgroundViewController?.editSubType = editToolbarView?.editSubType ?? .template backgroundViewController?.resetUI() updateBackgroundDocument() } func updateBackgroundDocument() { guard let controller = backgroundViewController else { return } controller.pdfDocument = nil let editDocument = CPDFDocument.init() let page = listView.document.page(at: UInt(listView.currentPageIndex)) editDocument?.insertPageObject(page, at: 0) backgroundViewController?.pdfDocument = editDocument backgroundViewController?.reloadData() } func removePDFBackground() { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Are you sure you want to remove the background?", comment: "") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result == .alertFirstButtonReturn) { let background = listView.document.background() background?.clear() listView.document?.refreshPageData() listView.layoutDocumentView() _ = KMNCustomAlertView.alertView(message: KMLocalizedString("Background removed"), type: .success, fromView: bottomContendBox, point:CGPointMake(CGRectGetWidth(bottomContendBox.frame)/2, CGRectGetHeight(bottomContendBox.frame)-28)) } } func batchAddBackground() { } func batchRemoveBackground() { } //MARK: - header&footer func showHeaderFooterController() { viewManager.editType = .header_Footer showEditToolbarView() editToolbarView?.editType = .header_Footer if KMHeaderFooterManager.defaultManager.headFooterObjects.count == 0 { editToolbarView?.editSubType = .add } else { editToolbarView?.editSubType = .template } editToolbarView?.reloadData() if headerFooterViewController == nil { headerFooterViewController = KMHeaderFooterController.init() } headerFooterViewController?.view.frame = CGRectMake(44, 0, CGRectGetWidth(bottomContendBox.frame)-44, CGRectGetHeight(bottomContendBox.frame)) headerFooterViewController?.view.autoresizingMask = [.maxXMargin, .width, .height] headerFooterViewController?.totalPDFCount = Int(listView.document.pageCount) headerFooterViewController?.delegate = self bottomContendBox.contentView?.addSubview(headerFooterViewController!.view) headerFooterViewController?.editSubType = editToolbarView?.editSubType ?? .template updateHeaderFooterDocument() } func updateHeaderFooterDocument() { guard let controller = headerFooterViewController else { return } controller.pdfDocument = nil let editDocument = CPDFDocument.init() let page = listView.document.page(at: UInt(listView.currentPageIndex)) editDocument?.insertPageObject(page, at: 0) headerFooterViewController?.totalPDFCount = Int(listView.document.pageCount) headerFooterViewController?.pdfDocument = editDocument headerFooterViewController?.resetUI() headerFooterViewController?.reloadData() } func removeHeaderFooter() { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Are you sure you want to remove the Header & Footer?", comment: "") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result == .alertFirstButtonReturn) { let headerFooter = listView.document.headerFooter() headerFooter?.clear() listView.document?.refreshPageData() listView.layoutDocumentView() _ = KMNCustomAlertView.alertView(message: KMLocalizedString("Header & Footer removed"), type: .success, fromView: bottomContendBox, point:CGPointMake(CGRectGetWidth(bottomContendBox.frame)/2, CGRectGetHeight(bottomContendBox.frame)-28)) } } func batchAddHeaderFooter() { } func batchRemoveHeaderFooter() { } //MARK: - Bates func showBatesController() { viewManager.editType = .bates showEditToolbarView() editToolbarView?.editType = viewManager.editType if KMBatesManager.defaultManager.datas.count == 0 { editToolbarView?.editSubType = .add } else { editToolbarView?.editSubType = .template } editToolbarView?.reloadData() if batesViewController == nil { batesViewController = KMBatesController.init() } batesViewController?.view.frame = CGRectMake(44, 0, CGRectGetWidth(bottomContendBox.frame)-44, CGRectGetHeight(bottomContendBox.frame)) batesViewController?.view.autoresizingMask = [.maxXMargin, .width, .height] batesViewController?.delegate = self batesViewController?.totalPDFCount = Int(listView.document.pageCount) bottomContendBox.contentView?.addSubview(batesViewController!.view) batesViewController?.editSubType = editToolbarView?.editSubType ?? .template updateBatesDocument() batesViewController?.resetUI() } func updateBatesDocument() { guard let controller = batesViewController else { return } controller.pdfDocument = nil let editDocument = CPDFDocument.init() let page = listView.document.page(at: UInt(listView.currentPageIndex)) editDocument?.insertPageObject(page, at: 0) batesViewController?.pdfDocument = editDocument batesViewController?.reloadData() } func removePDFBates() { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Are you sure you want to remove the Bates?", comment: "") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result == .alertFirstButtonReturn) { let bates = listView.document.bates() bates?.clear() listView.document?.refreshPageData() listView.layoutDocumentView() _ = KMNCustomAlertView.alertView(message: KMLocalizedString("Bates removed"), type: .success, fromView: bottomContendBox, point:CGPointMake(CGRectGetWidth(bottomContendBox.frame)/2, CGRectGetHeight(bottomContendBox.frame)-28)) } } func batchAddBates() { } func batchRemoveBates() { } //MARK: - Crop Action // 白边距,统一大小 @objc func auto_cropPagesWhiteMargin(_ pageIndexs: [UInt]) { var size = NSZeroSize for i in pageIndexs { let page = self.listView.document.page(at: i) let rect = KMCropTools.getPageForegroundBox(page!) size.width = fmax(size.width, NSWidth(rect)) size.height = fmax(size.height, NSHeight(rect)) } var rectArray: Array<NSRect> = [] for i in pageIndexs { progressC?.increment(by: Double(i)) progressC?.doubleValue = Double(i) let page = self.listView.document.page(at: i) var rect = KMCropTools.getPageForegroundBox(page!) let bounds: NSRect = (page?.bounds(for: .mediaBox))! if (rect.minX - bounds.minX > bounds.maxX-rect.maxX) { rect.origin.x = rect.maxX-size.width } rect.origin.y = rect.maxY-size.height rect.size = size if (NSWidth(rect) > NSWidth(bounds)) { rect.size.width = NSWidth(bounds) } if (NSHeight(rect) > NSHeight(bounds)) { rect.size.height = NSHeight(bounds) } if (NSMinX(rect) < NSMinX(bounds)) { rect.origin.x = NSMinX(bounds) } else if (NSMaxX(rect) > NSMaxX(bounds)) { rect.origin.x = NSMaxX(bounds) - NSWidth(rect) } if (NSMinY(rect) < NSMinY(bounds)) { rect.origin.y = NSMinY(bounds) } else if (NSMaxY(rect) > NSMaxY(bounds)) { rect.origin.y = NSMaxY(bounds) - NSHeight(rect) } rectArray.append(rect) } self.cropPages(atIndexs: pageIndexs, to: rectArray) } func cropPages(atIndexs pageIndexs: [UInt], to rects: Array<NSRect>) { let currentPage = self.listView.currentPage() let visibleRect: NSRect = self.listView.convert(self.listView.convert(self.listView.documentView().visibleRect, from: self.listView.documentView()), to: self.listView.currentPage()) var oldRectArray: Array<NSRect> = [] let rectCount = rects.count for i in pageIndexs { if let page = self.listView.document.page(at: i) { let rect = NSIntersectionRect(rects[Int(i) % rectCount], (page.bounds(for: .mediaBox))) let oldRect = page.bounds(for: .cropBox) oldRectArray.append(oldRect) page.setBounds(rect, for: .cropBox) } } let undoManager = self.listView.undoManager (undoManager?.prepare(withInvocationTarget: self) as AnyObject).cropPages(atIndexs: pageIndexs, to: oldRectArray) /// 刷新预览视图 self.listView.layoutDocumentView() self.listView.displayBox = .cropBox self.listView.go(to: currentPage) self.listView.go(to: visibleRect, on: currentPage) } //MARK: - TTS @IBAction func startSpeaking(_ sender: Any) { self.showTTSWindow() let ttsView = KMTTSWindowController.share ttsView.buttonItemClick_Play(ttsView.playButton) } @IBAction func stopSpeaking(_ sender: Any) { 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() } } } func showTTSWindow() { var lastPDFView: CPDFView? let ttsView = KMTTSWindowController.share if (ttsView.window?.isVisible ?? false) { lastPDFView = ttsView.pdfView if lastPDFView?.document?.documentURL?.path == self.listView.document?.documentURL?.path { lastPDFView = nil ttsView.window?.orderOut(nil) } else { ttsView.pdfView = self.listView ttsView.showWindow(nil) } } else { ttsView.pdfView = self.listView ttsView.showWindow(nil) } ttsView.closeWindowCallback = { (isCloseWindow: Bool) in if isCloseWindow { } } if let currentSelection = self.listView.currentSelection { if let data = currentSelection.selectionsByLine, data.isEmpty == false { ttsView.startSpeakingPDFSelection(currentSelection) } } if let lastPDFView = lastPDFView { lastPDFView.setHighlightedSelections([]) ttsView.stopSpeaking() } } //MARK: 导出图片 func extractImageAction(num: Int) { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_ExtractImage_BuyNow" winC?.showWindow(nil) return } if !(self.listView.document.allowsPrinting || self.listView.document.allowsCopying) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() return } let document = self.listView.document var fileURL = document?.documentURL if num == 1 { let pageCount = document?.pageCount ?? 0 let indeSet = NSMutableIndexSet() indeSet.add(in: NSRange(location: 0, length: Int(pageCount))) if indeSet.count == 0 { return } let lastPathName = fileURL?.deletingPathExtension().lastPathComponent ?? "" let tFileName = (String(format: "%@_Extract Images", lastPathName)) let outputSavePanel = NSSavePanel() outputSavePanel.title = NSLocalizedString("Save as PDF", comment: "") outputSavePanel.allowsOtherFileTypes = true outputSavePanel.isExtensionHidden = true outputSavePanel.canCreateDirectories = true outputSavePanel.nameFieldStringValue = tFileName outputSavePanel.beginSheetModal(for: self.view.window!, completionHandler: { (result) in if result == NSApplication.ModalResponse.OK { DispatchQueue.main.async { self.beginProgressSheet(withMessage: NSLocalizedString("Extracting all pictures...", comment: "") + "...", maxValue: 0) let tDestFile = outputSavePanel.url!.path let uniquePath = KMExtractImageWindowController.createDestFolder(path: tDestFile, isUnique: false) let pdfconverter = PDFConvertObject() pdfconverter.extractResourcesFromPDF(at: fileURL?.path ?? "", pdfPassword: document?.password, selectIndexSet: indeSet as IndexSet, destDocPath: uniquePath, moreOptions: nil) self.dismissProgressSheet() let fileManager = FileManager.default if fileManager.fileExists(atPath: tDestFile) { let workspace = NSWorkspace.shared let url = URL(fileURLWithPath: tDestFile) workspace.activateFileViewerSelecting([url]) } } } }) return } if fileURL != nil { self.myDocument?.save(nil) } else { let myDocument = self.myDocument let str = String(format: "%@.pdf", myDocument?.displayName ?? "") let writeSuccess = document!.write(to: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!)) if writeSuccess { var documentTemp = CPDFDocument(url: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!)) fileURL = document?.documentURL } else { NSSound.beep() return } } extract = KMExtractImageWindowController(windowNibName: "KMExtractImageWindowController") extract?.docPath = fileURL?.path ?? "" extract?.password = document?.password ?? "" extract?.currentPage = self.listView.currentPageIndex self.km_beginSheet(windowC: extract!) extract?.selectCurrentPageBtn() } func beginProgressSheet(withMessage message: String, maxValue: UInt) { 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.message = NSLocalizedString("Converting...", comment: "") progressC = progress progressC?.message = message if maxValue > 0 { progressC?.indeterminate = false progressC?.maxValue = Double(maxValue) progressC?.progressBar.doubleValue = 0.3 } else { progressC?.indeterminate = true } self.view.km_beginSheet(windowC: progressC!) } func dismissProgressSheet() { progressC?.stopAnimation() self.view.km_endSheet() progressC = nil } func converFilesToPath(files: Array<KMBatchOperateFile>) -> [String] { let newArr = NSMutableArray() for item in files { newArr.add(item.filePath) } return newArr as! [String] } internal func showPrintWindow(pageRange: KMPrintPageRange = KMPrintPageRange(type: .allPage, selectPages: [])) { self.saveDocument() if (self.listView.document != nil && !self.listView.document.allowsPrinting) { // 有打印限制 KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [weak self] result ,password in if (result == .cancel) { return } // 解除权限 self?.listView.document.unlock(withPassword: password) // 隐藏提示 self?.hiddenSecureLimitTip() // 去打印 KMPrintWindowController.openDocument(inputDocument: self?.listView.document, inputPageRange: pageRange) } return } KMPrintWindowController.openDocument(inputDocument: self.listView.document, inputPageRange: pageRange) } //MARK: - Share Action @objc private func shareDocument(sender: NSView) { let document = self.listView.document ?? CPDFDocument() if document?.documentURL == nil { return } var doucumentURL : URL = self.listView.document.documentURL if doucumentURL.path.count > 0 { let docDir = NSTemporaryDirectory() let documentName : String = doucumentURL.path.lastPathComponent let path = docDir.stringByAppendingPathComponent(documentName) let writeSuccess = self.listView.document.write(to: URL(fileURLWithPath: path)) if writeSuccess == false { __NSBeep() return; } doucumentURL = URL(fileURLWithPath: path) } let array = [doucumentURL] let picker = NSSharingServicePicker.init(items: array) if sender.window != nil { picker.show(relativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } @objc private func shareFlatten(sender: NSView) { let document = self.listView.document ?? CPDFDocument() var path: String? if document?.documentURL != nil { path = document?.documentURL.path ?? "" } if path?.count ?? 0 > 0 { let docDir = NSTemporaryDirectory() let documentName : String = path?.lastPathComponent ?? "" path = docDir.stringByAppendingPathComponent(documentName) } let pathFolder = path?.fileURL.deletingLastPathComponent().path var tfileName = path?.deletingPathExtension.lastPathComponent let tStdFileSuffix = "_flatten" tfileName = (tfileName ?? "") + tStdFileSuffix + ".pdf" path = (pathFolder ?? "") + "/" + (tfileName ?? "") let success : Bool = document?.writeFlatten(to: URL(fileURLWithPath: path ?? "")) ?? false if success { let url = URL(fileURLWithPath: path ?? "") let picker = NSSharingServicePicker.init(items: [url]) if sender.window != nil { picker.show(relativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } } @objc private func shareOriginalPDF(sender: NSView) { guard let pdfDoc = self.listView.document else { NSSound.beep() return } if !pdfDoc.allowsCopying || !pdfDoc.allowsPrinting { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() return } let document = self.listView.document ?? CPDFDocument() var path: String? if document?.documentURL != nil { path = document?.documentURL.path ?? "" } if path?.count ?? 0 > 0 { let docDir = NSTemporaryDirectory() let documentName : String = path?.lastPathComponent ?? "" path = docDir.stringByAppendingPathComponent(documentName) } var writeSuccess = document?.write(to: URL(fileURLWithPath: path ?? "")) if writeSuccess == false { __NSBeep() return; } let newDocument = CPDFDocument(url: URL(fileURLWithPath: path ?? "")) let cnt = newDocument?.pageCount ?? 0 for i in 0 ..< cnt { let page = newDocument!.page(at: i) var annotations : [CPDFAnnotation] = [] for annotation in page!.annotations { annotations.append(annotation) } for annotation in annotations { annotation.page.removeAnnotation(annotation) } } writeSuccess = newDocument?.write(to:URL(fileURLWithPath: path ?? "")) if writeSuccess ?? false { let url = URL(fileURLWithPath: path ?? "") let picker = NSSharingServicePicker.init(items: [url]) if sender.window != nil { picker.show(relativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } } @objc func shareFromService(sender: NSMenuItem) { if ((NSApp.mainWindow?.windowController is KMBrowserWindowController) == false) { return } var string = "" if let freeTextAnnotation = listView.activeAnnotation as? CPDFFreeTextAnnotation { string = freeTextAnnotation.contents ?? "" } else if let markupAnnotation = listView.activeAnnotation as? CPDFMarkupAnnotation { if let page = markupAnnotation.page { if let selection = page.selection(for: markupAnnotation.bounds) { string = selection.string() ?? "" } } } else { string = listView.currentSelection?.string() ?? "" } let windowControler = NSApp.mainWindow?.windowController as! KMBrowserWindowController let model = windowControler.browser?.tabStripModel if let cnt = model?.count(), cnt <= 0 { return } if let data = model?.activeTabContents().isHome, data { return } let document: KMMainDocument = model?.activeTabContents() as! KMMainDocument if string.count > 0 { let represent : NSSharingService = sender.representedObject as! NSSharingService represent.perform(withItems: [string]) return } let represent = sender.representedObject as? NSSharingService represent?.perform(withItems: [string]) } // 搜索 & 替换 func showSearchPopWindow(type: KMNBotaSearchType, keyborad: String?, replaceText: String?, results: [KMSearchMode]) { let toolMode = self.listView.toolMode let isEditing = self.listView.isEditing() var winH: CGFloat = 112 if type == .replace { if IAPProductsManager.default().isAvailableAllFunction() == false { let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_ReplaceText_BuyNow" winC?.showWindow(nil) return } if toolMode == .CEditPDFToolMode && isEditing { } else { // 进入内容编辑模式 viewManager.toolMode = .Edit updatePDFViewAnnotationMode() } winH = 208 } self.view.window?.makeFirstResponder(nil) let winC = KMSearchReplaceWindowController(with: listView, type: type) self.currentWindowController = winC winC.replaceCallback = { [weak self] in let toolMode = self?.listView.toolMode ?? .none let isEditing = self?.listView.isEditing() ?? false if toolMode == .CEditPDFToolMode && isEditing { } else { // 进入内容编辑模式 self?.viewManager.toolMode = .Edit self?.updatePDFViewAnnotationMode() } } winC.itemClick = { [weak self] idx, params in if idx == 1 { self?.toggleOpenLeftSide(pdfSideBarType: .search) guard let handdler = params.first as? KMNSearchHanddler else { return } let viewC = self?.botaViewController?.searchViewC viewC?.update(keyborad: handdler.searchKey, replaceKey: handdler.replaceKey, results: handdler.searchSectionResults) } } let targetView = self.pdfToolbarController?.leftViewButton let point = targetView?.convert(targetView?.frame.origin ?? .zero, to: nil) ?? .zero // 200 248 let x = point.x + (self.view.window?.frame.origin.x ?? 0) - 32 let y = point.y + (self.view.window?.frame.origin.y ?? 0) - winH - 32 let winFramePoint = NSPoint(x: x, y: y) winC.window?.setFrameOrigin(winFramePoint) winC.update(keyborad: keyborad, replaceKey: replaceText, results: results) self.view.window?.addChildWindow(winC.window!, ordered: .above) } } //MARK: Compress extension KMMainViewController { func showCompressController(_ url: URL) { self.compressWindowController = KMCompressWindowController(windowNibName: "KMCompressWindowController") self.compressWindowController?.password = self.listView.document?.password ?? "" self.compressWindowController?.documentURL = url self.view.window?.beginSheet(self.compressWindowController!.window!) self.compressWindowController?.itemClick = { [unowned self] in self.view.window?.endSheet((self.compressWindowController?.window)!) } self.compressWindowController?.batchAction = { [unowned self] view, filePaths in self.view.window?.endSheet((self.compressWindowController?.window)!) self.showBatchCompressController(filePaths) } self.compressWindowController?.resultCallback = { [unowned self] result, openDocument, fileURL, error in self.view.window?.endSheet((self.compressWindowController?.window)!) if (result) { if (openDocument) { NSDocumentController.shared.openDocument(withContentsOf: fileURL, display: true) { document, result, error in } } else { NSWorkspace.shared.activateFileViewerSelecting([fileURL]) } } else { let alert = NSAlert() alert.messageText = NSLocalizedString("Compress Faild", comment: "") alert.runModal() } } } func showBatchCompressController(_ filePaths: [URL]) { let batchWindowController = KMBatchOperateWindowController.sharedWindowController let batchOperateFile = KMBatchOperateFile(filePath: filePaths.first!.path, type: .Compress) batchWindowController.switchToOperateType(KMBatchOperationType.Compress, files: [batchOperateFile]) batchWindowController.window?.makeKeyAndOrderFront("") } } //MARK: - NSSplitViewDelegate extension KMMainViewController: NSSplitViewDelegate { func splitView(_ splitView: NSSplitView, canCollapseSubview subview: NSView) -> Bool { if splitView == infoContendSplitView { return subview.isEqual(to: infoSplitCenterView) == false } return false } func splitView(_ splitView: NSSplitView, shouldCollapseSubview subview: NSView, forDoubleClickOnDividerAt dividerIndex: Int) -> Bool { if splitView == infoContendSplitView { if(subview.isEqual(to: infoSplitLeftView)) { } else if(subview.isEqual(to: infoSplitRightView)) { } } return false } func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool { if splitView == infoContendSplitView { return splitView == infoContendSplitView } else if splitView == pdfSplitView { return splitView == pdfSplitView } return false } func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { if(splitView == infoContendSplitView && dividerIndex == 1) { return proposedMaximumPosition - MIN_SIDE_PANE_WIDTH.doubleValue } return proposedMaximumPosition } func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { if(splitView == infoContendSplitView && dividerIndex == 0) { return proposedMinimumPosition + MIN_SIDE_PANE_WIDTH.doubleValue } return proposedMinimumPosition } func splitViewDidResizeSubviews(_ notification: Notification) { let splitView = notification.object as? NSSplitView if(splitView == infoContendSplitView) { leftSplitViewResizeFinish() if(newMwcFlags.settingUpWindow == false && self.view.window?.frameAutosaveName != nil) { let leftWidth = infoContendSplitView.isSubviewCollapsed(infoSplitLeftView) ? 0.0 : infoSplitLeftView.frame.width UserDefaults.standard.set(leftWidth, forKey: CPDFViewLeftSidePaneWidthKey) UserDefaults.standard.synchronize() } if listView.isEditing() == false { updateAnnotationsPopWinodwFrame() } else { updateContentEditPopWinodwFrame() } } NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(splitViewResizeFinish), object: nil) self.perform(#selector(splitViewResizeFinish), with: nil, afterDelay: 0.15) } @objc func leftSplitViewResizeFinish() { botaViewController?.changeLeftSideBounds() } @objc func splitViewResizeFinish() { if infoContendSplitView.isSubviewCollapsed(infoSplitLeftView) { if viewManager.pdfSideBarType != .none { viewManager.pdfSideBarType = .none sideBarController?.reloadBOTAData() } } } } //MARK: - KMPDFSideBarControllerDelegate 左侧Sidebar代理 extension KMMainViewController: KMPDFSideBarControllerDelegate { func kmPDFSideBarControllerDidSidebarTypeUpdated(_ view: KMPDFSideBarController) { if viewManager.pdfSideBarType == .none { toggleCloseLeftSide() } else { toggleOpenLeftSide(pdfSideBarType: viewManager.pdfSideBarType) } } func kmPDFSideBarControllerDidGotoPage(_ view: KMPDFSideBarController, _ pageIndex: Int) { listView.go(toPageIndex: pageIndex, animated: true) } } //MARK: - KMPDFToolbarControllerDelegate 工具栏代理 extension KMMainViewController: KMPDFToolbarControllerDelegate { //MARK: -ViewTools发生变化时调用 func kmPDFToolbarControllerDidViewToolsChanged(_ controller: KMPDFToolbarController) { let viewToolsType = viewManager.viewToolsType if viewToolsType == .Select { listView.toolMode = .CNoteToolMode } else if viewToolsType == .Scroll { listView.toolMode = .CMoveToolMode } else if viewToolsType == .Content_Selection { listView.toolMode = .CSelectToolMode } else if viewToolsType == .Magnify { listView.toolMode = .CMagnifyToolMode } else if viewToolsType == .AreaZoom { listView.toolMode = .CSelectZoomToolMode } refreshToolbarViewHeightInfo() } //MARK: -一级工具栏状态发生变化时调用 func kmPDFToolbarControllerDidToolModeChanged(_ controller: KMPDFToolbarController) { refreshToolbarViewHeightInfo() toolbarViewModeChanged() } //MARK: -点击工具栏按钮 func kmPDFToolbarControllerDidToolbarItemClicked(_ controller: KMPDFToolbarController, _ itemIdentifier: String) { print("toolbar点击", itemIdentifier) if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_PageEdit_Identifier).contains(itemIdentifier) { //MARK: -页面编辑 if itemIdentifier == KMPDFToolbar_PageEdit_InsertFile_Identifier { pageEditViewController?.insertFromPDFAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_InsertBlank_Identifier { pageEditViewController?.insertFromBlankAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_InsertClip_Identifier { pageEditViewController?.insertFromClipboardAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_InsertScanner_Identifier { pageEditViewController?.insertFromScannerAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_Extract_Identifier { pageEditViewController?.extractPDFAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_Replace_Identifier { pageEditViewController?.replacePDFAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_Split_Identifier { pageEditViewController?.splitPDFAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_Reverse_Identifier { pageEditViewController?.reversePDFAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_LeftRotate_Identifier { pageEditViewController?.rotatePageLeftAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_RightRotate_Identifier{ pageEditViewController?.rotatePageRightAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_Delete_Identifier { pageEditViewController?.deletePageAction() } else if itemIdentifier == KMPDFToolbar_PageEdit_Reduce_Identifier { pageEditViewController?.zoomOutPageAction() if(pageEditViewController?.canZoomInPageSize() == false) { toolbarManager.page_Increase_Property.isDisabled = true } else { toolbarManager.page_Increase_Property.isDisabled = false } if(pageEditViewController?.canZoomOutPageSize() == false) { toolbarManager.page_Reduce_Property.isDisabled = true } else { toolbarManager.page_Reduce_Property.isDisabled = false } controller.refreshSecondToolbarItemsState() } else if itemIdentifier == KMPDFToolbar_PageEdit_Increase_Identifier { pageEditViewController?.zoomInPageAction() if(pageEditViewController?.canZoomInPageSize() == false) { toolbarManager.page_Increase_Property.isDisabled = true } else { toolbarManager.page_Increase_Property.isDisabled = false } if(pageEditViewController?.canZoomOutPageSize() == false) { toolbarManager.page_Reduce_Property.isDisabled = true } else { toolbarManager.page_Reduce_Property.isDisabled = false } controller.refreshSecondToolbarItemsState() } else if itemIdentifier == KMPDFToolbar_PageEdit_page_oddPage_Identifier { pageEditViewController?.thumbnailChoosePageStyle = .odd if(toolbarManager.page_pageInfo_Property.creatable == true) { toolbarManager.page_pageInfo_Property.creatable = false controller.refreshSecondToolbarItemsState() } } else if itemIdentifier == KMPDFToolbar_PageEdit_page_EvenPage_Identifier { pageEditViewController?.thumbnailChoosePageStyle = .even if(toolbarManager.page_pageInfo_Property.creatable == true) { toolbarManager.page_pageInfo_Property.creatable = false controller.refreshSecondToolbarItemsState() } } else if itemIdentifier == KMPDFToolbar_PageEdit_page_PortraitPage_Identifier { pageEditViewController?.thumbnailChoosePageStyle = .horizontal if(toolbarManager.page_pageInfo_Property.creatable == true) { toolbarManager.page_pageInfo_Property.creatable = false controller.refreshSecondToolbarItemsState() } } else if itemIdentifier == KMPDFToolbar_PageEdit_page_LandscapePage_Identifier { pageEditViewController?.thumbnailChoosePageStyle = .vertical if(toolbarManager.page_pageInfo_Property.creatable == true) { toolbarManager.page_pageInfo_Property.creatable = false controller.refreshSecondToolbarItemsState() } } else if itemIdentifier == KMPDFToolbar_PageEdit_page_AllPage_Identifier { pageEditViewController?.thumbnailChoosePageStyle = .allPage if(toolbarManager.page_pageInfo_Property.creatable == true) { toolbarManager.page_pageInfo_Property.creatable = false controller.refreshSecondToolbarItemsState() } } else if itemIdentifier == KMPDFToolbar_PageEdit_page_CustomPage_Identifier { pageEditViewController?.thumbnailChoosePageStyle = .custom toolbarManager.page_pageInfo_Property.text = nil if(toolbarManager.page_pageInfo_Property.creatable == false) { toolbarManager.page_pageInfo_Property.creatable = true } controller.refreshSecondToolbarItemsState() } } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Markup_Identifier).contains(itemIdentifier) { //MARK: -Markup if itemIdentifier == KMPDFToolbar_eye_Identifier { self.showOrHideNotes() } if viewManager.subToolMode == .None { viewManager.showRightSide = false } else { viewManager.showRightSide = true } } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Edit_Identifier).contains(itemIdentifier) { //MARK: -编辑 if itemIdentifier == KMPDFToolbar_edit_addWatermark_Identifier { showWatermarkController() } else if itemIdentifier == KMPDFToolbar_edit_removeWatermark_Identifier { removePDFWatermark() } else if itemIdentifier == KMPDFToolbar_edit_batch_AddWatermark_Identifier { batchAddWatermark() } else if itemIdentifier == KMPDFToolbar_edit_batchRemoveWatermark_Identifier { batchRemoveWatermark() } else if itemIdentifier == KMPDFToolbar_edit_addBG_Identifier { showBackgroundController() } else if itemIdentifier == KMPDFToolbar_edit_removeBG_Identifier { removePDFBackground() } else if itemIdentifier == KMPDFToolbar_edit_batch_AddBG_Identifier { batchAddBackground() } else if itemIdentifier == KMPDFToolbar_edit_batchRemoveBG_Identifier { batchRemoveBackground() } else if itemIdentifier == KMPDFToolbar_edit_addHF_Identifier { showHeaderFooterController() } else if itemIdentifier == KMPDFToolbar_edit_removeHF_Identifier { removeHeaderFooter() } else if itemIdentifier == KMPDFToolbar_edit_batch_AddHF_Identifier { batchAddHeaderFooter() } else if itemIdentifier == KMPDFToolbar_edit_batchRemoveHF_Identifier { batchRemoveHeaderFooter() } else if itemIdentifier == KMPDFToolbar_edit_addBates_Identifier { showBatesController() } else if itemIdentifier == KMPDFToolbar_edit_removeBates_Identifier { removePDFBates() } else if itemIdentifier == KMPDFToolbar_edit_batch_AddBates_Identifier { batchAddBates() } else if itemIdentifier == KMPDFToolbar_edit_batchRemoveBates_Identifier { batchRemoveBates() } else if itemIdentifier == KMPDFToolbar_edit_crop_Identifier { showCropController() } } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Form_Identifier).contains(itemIdentifier) { //MARK: -Form表单 if itemIdentifier == KMPDFToolbar_form_HighlightFields_Identifier { CPDFWidgetAnnotation.updateHighlightFormFiled(listView) } else if itemIdentifier == KMPDFToolbar_form_ShowName_Identifier { listView.showFormFieldName = !listView.showFormFieldName if listView.showFormFieldName { toolbarManager.form_ShowName_Property.righticon = NSImage(named: "tick_Green") } else { toolbarManager.form_ShowName_Property.righticon = nil } listView.setNeedsDisplayForVisiblePages() } else if itemIdentifier == KMPDFToolbar_form_ClearForm_Identifier { listView.resetFormAnnotation() } } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Fill_Identifier).contains(itemIdentifier) { //MARK: -填充 } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Convert_Identifier).contains(itemIdentifier) { //MARK: -转档 if itemIdentifier == KMPDFToolbar_convert_word_Identifier { let winC = KMConvertWordWindowController() let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_ppt_Identifier { let winC = KMConvertPPTsWindowController() winC.subType = 1 let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_RTF_Identifier { let winC = KMConvertPPTsWindowController() winC.subType = 2 let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_Text_Identifier { let winC = KMConvertPPTsWindowController() winC.subType = 4 let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_CSV_Identifier { let winC = KMConvertPPTsWindowController() winC.subType = 5 let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_excel_Identifier { let winC = KMConvertExcelWindowController() let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_HTML_Identifier { let winC = KMConvertHtmlWindowController() let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: self.view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_Json_Identifier { let winC = KMConvertJsonWindowController() let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_image_Identifier { let winC = KMConvertImageWindowController() let model = KMDocumentModel(url: listView.document.documentURL) winC.documentModel = model winC.own_beginSheetModal(for: view.window, completionHandler: nil) } else if itemIdentifier == KMPDFToolbar_convert_imageToPDF_Identifier { NSApplication.ShowImageToPDFWindow() } } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Protect_Identifier).contains(itemIdentifier) { //MARK: -Protect if itemIdentifier == KMPDFToolbar_protect_redact_Identifier { } else if itemIdentifier == KMPDFToolbar_protect_security_Identifier { } else if itemIdentifier == KMPDFToolbar_protect_removeSecurity_Identifier { } else if itemIdentifier == KMPDFToolbar_protect_digitalSign_Identifier { } } else if toolbarManager.getSubToolItemIdentifys(KMPDFToolbar_Tools_Identifier).contains(itemIdentifier) { //MARK: -工具 if itemIdentifier == KMPDFToolbar_tools_compress_Identifier { self.showCompressController(self.listView.document.documentURL) } else if itemIdentifier == KMPDFToolbar_tools_batch_compress_Identifier { self.showBatchCompressController([self.listView.document.documentURL]) } else if itemIdentifier == KMPDFToolbar_tools_OCR_Identifier { viewManager.showRightSide = !viewManager.showRightSide } else if itemIdentifier == KMPDFToolbar_tools_merge_Identifier { self.showMergeWindow(self.listView.document.password) } else if itemIdentifier == KMPDFToolbar_tools_TTS_Identifier { self.showTTSWindow() } else if itemIdentifier == KMPDFToolbar_tools_extractImage_Identifier { self.extractImageAction(num: 2) } else if itemIdentifier == KMPDFToolbar_tools_AITools_Identifier { self.viewManager.pdfSideBarType = .aiTools self.sideBarController?.reloadData() if let sideVC = self.sideBarController { self.kmPDFSideBarControllerDidSidebarTypeUpdated(sideVC) } } } else if itemIdentifier == KMPDFToolbar_ViewDisplay_Identifier { //MARK: -Display updatePDFDisplaySettingView() } else if itemIdentifier == KMPDFToolbar_rightView_Identifier { //MARK: -属性栏 } else if itemIdentifier == KMPDFToolbar_PageEdit_Identifier { //MARK: -页面编辑 if viewManager.isPageEditMode == true { enterPageEditMode() } else { exitPageEditMode() } } else if(itemIdentifier == KMPDFToolbar_undo_Identifier) { //MARK: -Undo listView.undoManager?.undo() } else if(itemIdentifier == KMPDFToolbar_redo_Identifier) { //MARK: -Redo listView.undoManager?.redo() } else if(itemIdentifier == KMPDFToolbar_share_PDF_Identifier || itemIdentifier == KMPDFToolbar_share_Flattened_Identifier || itemIdentifier == KMPDFToolbar_share_Original_Identifier) { //MARK: -Share if(itemIdentifier == KMPDFToolbar_share_PDF_Identifier) { if let view = controller.findViewWith(KMPDFToolbar_share_Identifier) { shareDocument(sender: view) } } else if(itemIdentifier == KMPDFToolbar_share_Flattened_Identifier) { if let view = controller.findViewWith(KMPDFToolbar_share_Identifier) { shareFlatten(sender: view) } } else if(itemIdentifier == KMPDFToolbar_share_Original_Identifier) { if let view = controller.findViewWith(KMPDFToolbar_share_Identifier) { shareOriginalPDF(sender: view) } } } else { print("click else") } refreshToolbarViewHeightInfo() toolbarViewModeChanged() refreshRightSide() } func kmPDFToolbarControllerDidSelectTextDidBeginEditing(_ controller: KMPDFToolbarController, _ view: ComponentSelect) { } func kmPDFToolbarControllerDidSelectTextDidChange(_ controller: KMPDFToolbarController, _ view: ComponentSelect) { } func kmPDFToolbarControllerDidSelectTextDidEndEditing(_ controller: KMPDFToolbarController, _ view: ComponentSelect) { if view.properties == toolbarManager.page_pageInfo_Property { if viewManager.isPageEditMode == true { let fileAttribute = KMNFileAttribute() fileAttribute.password = listView.document?.password ?? "" fileAttribute.pdfDocument = listView.document fileAttribute.filePath = listView.document?.documentURL.path ?? "" fileAttribute.bAllPage = false fileAttribute.pagesType = .PagesString fileAttribute.pagesString = view.properties.text ?? "" let fetchSelectPages = fileAttribute.fetchSelectPages() if (fetchSelectPages.isEmpty) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@ %@", fileAttribute.filePath.lastPathComponent, KMLocalizedString("Invalid page range or the page number is out of range. Please try again.")) alert.runModal() toolbarManager.page_pageInfo_Property.text = "" controller.refreshSecondToolbarItemsState() } else { var tIndexPaths: Set<IndexPath> = [] for i in 0 ..< fetchSelectPages.count { tIndexPaths.insert(IndexPath(item: (fetchSelectPages[i] - 1), section: 0)) } pageEditViewController?.selectionIndexPaths = tIndexPaths } } } } func kmPDFToolbarControllerDidExitPageEditMode(_ controller: KMPDFToolbarController) { exitPageEditMode() } } //MARK: - KMRightSideControllerDelegate右边属性栏代理 extension KMMainViewController: KMRightSideControllerDelegate { func kmRightSideControllerDidContendVCUpdated(_ controller: KMRightSideController) { //MARK: -Crop if (controller.contentViewController is KMCropPropertyController) { if let cropVC = rightSideController?.edit_cropController { cropVC.pdfView = controller.pdfView if cropVC.delegate == nil { cropVC.delegate = cropController } cropVC.reloadData() } } } } //MARK: - KMNDisplayViewControllerDelegate代理 extension KMMainViewController: KMNDisplayViewControllerDelegate { //Display Mode func displayViewControllerDidDisplayModeChanged(_ controller: KMNDisplayViewController) { listView.layoutDocumentView() } //阅读模式 func displayViewControllerDidReadModeUpdated(_ controller: KMNDisplayViewController) { if viewManager.isPDFReadMode { openPDFReadMode() } else { exitPDFReadMode() } } //PPT func displayViewControllerDidGotoSlideShow(_ controller: KMNDisplayViewController) { togglePresentation(nil) } //SplitView func displayViewControllerDidSplitModeChanged(_ controller: KMNDisplayViewController) { reloadPDFSplitInfo() } func displayViewControllerDidSplitFileChanged(_ controller: KMNDisplayViewController) { splitPDFController?.reloadData() } func displayViewControllerDidToolbarStateChanged(_ controller: KMNDisplayViewController) { splitPDFController?.refreshToolbarState() reloadPDFPageNumberToolbar() } } //MARK: - PPT extension KMMainViewController: KMInteractionProviderProtocol { func providerContentView(fullScreenWindow: NSWindow, inset: CGFloat) -> NSView? { if(interactionMode == .presentation) { if listView.presentationDrawView == nil { listView.createPresentationDraw() } presentationTopViewController = KMPresentationTopViewController.init(nibName: "KMPresentationTopViewController", bundle: nil) presentationTopViewController?.pdfView = listView presentationTopViewController?.delegate = self presentationTopViewController?.isSelectionPre = true listView.isPresentationMode = true presentationTopViewController?.view.frame = CGRect(x: 0, y: (fullScreenWindow.contentView?.bounds.height ?? 0) - 42, width: fullScreenWindow.contentView?.bounds.width ?? 0, height: 42) if((presentationTopViewController) != nil) { fullScreenWindow.contentView?.addSubview(presentationTopViewController!.view) } } else { listView.frame = NSInsetRect(fullScreenWindow.contentView?.bounds ?? .zero, 0, 0) } fullScreenWindow.contentView?.addSubview(listView) if(interactionMode == .presentation) { let frame = fullScreenWindow.frame listView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height-42) listView.autoresizingMask = [.width, .maxYMargin] } return view } @objc func willEnterInteractionModeNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } let interactionMode = sender.userInfo?[NSWindow.UserInfo.interactionModeKey] as? KMInteractionMode if interactionMode == .presentation { let backgroundColor = NSColor.black let level = UserDefaults.standard.bool(forKey: "SKUseNormalLevelForPresentationKey") ? NSWindow.Level.normal : NSWindow.Level.popUpMenu let wasInteractionMode = self.interactionMode if wasInteractionMode == .normal { self.savedNormalSetup.setDictionary(self.currentPDFSettings() as! [AnyHashable : Any]) } if wasInteractionMode == .legacyFullScreen { self.enterPresentationMode() 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) } } 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 { 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() } } } // MARK: -KMPresentationTopViewControllerDelegate (幻灯片) extension KMMainViewController: KMPresentationTopViewControllerDelegate { func presentationTopViewExit(_ presentationTopViewController: KMPresentationTopViewController, withButton: NSButton) { self.exitFullScreen() } func presentationTopViewClear(_ presentationTopViewController: KMPresentationTopViewController, withButton: NSButton) { listView.presentationDrawView?.clear() } func presentationTopViewUndo(_ presentationTopViewController: KMPresentationTopViewController, withButton: NSButton) { let presentationDrawView = listView.presentationDrawView if presentationDrawView?.canUndo() == true { presentationDrawView?.undo() } } func presentationTopViewType(_ presentationTopViewController: KMPresentationTopViewController, withButton: NSButton, isSeletion: Bool) { listView.isPresentationMode = isSeletion if listView.isEnterPresentationDrawMode() == true { listView.exitPresentationDrawMode() } } func presentationTopViewDrawColor(_ presentationTopViewController: KMPresentationTopViewController, withView: NSView,color:NSColor?) { if color == nil{ listView.exitPresentationDrawMode() } else { if listView.isEnterPresentationDrawMode() == false { listView.enterPresentationDrawMode() } listView.changePresentationDrawModelColor(color) } } } //MARK: - KMSplitPDFViewControllerDelegate SplitPDFView分屏视图 extension KMMainViewController: KMSplitPDFViewControllerDelegate { func splitPDFViewControllerDidUpdateFilePath(_ controller: KMSplitPDFViewController) { displaySettingController?.reloadData() } func splitPDFViewControllerDidUpdatePDFScale(_ controller: KMSplitPDFViewController) { if let scaleFactor = controller.pdfView?.scaleFactor { listView.scaleFactor = scaleFactor } } func splitPDFViewControllerDidUpdatePDFPageIndex(_ controller: KMSplitPDFViewController) { if let pageIndex = controller.pdfView?.currentPageIndex { listView.go(toPageIndex: pageIndex, animated: false) } } } //MARK: - Edit编辑相关代理 extension KMMainViewController: KMEditToolbarViewDelegate { func kmEditToolbarViewDidUpdateMode(_ view: KMEditToolbarView) { if view.editType == .watermark { watermarkViewController?.editSubType = editToolbarView?.editSubType ?? .template watermarkViewController?.resetUI() watermarkViewController?.reloadData() } else if view.editType == .background { backgroundViewController?.editSubType = editToolbarView?.editSubType ?? .template backgroundViewController?.resetUI() backgroundViewController?.reloadData() } else if view.editType == .header_Footer { headerFooterViewController?.editSubType = editToolbarView?.editSubType ?? .template headerFooterViewController?.resetUI() headerFooterViewController?.reloadData() } else if view.editType == .bates { batesViewController?.editSubType = editToolbarView?.editSubType ?? .template batesViewController?.resetUI() batesViewController?.reloadData() } } func kmEditToolbarViewDidChooseBatch(_ view: KMEditToolbarView) { } func kmEditToolbarViewDidChooseApply(_ view: KMEditToolbarView) { // let pageIndex = view.getSelectedPageIndex(listView.document) // if pageIndex.isEmpty { // let alert = NSAlert() // alert.alertStyle = .critical // alert.messageText = KMLocalizedString("Invalid page range or the page number is out of range. Please try again.") // alert.runModal() // return // } // let pageString = view.getSelectedPageString(listView.document, pageIndex) // // if view.editType == .watermark { // if let model = watermarkViewController?.currentWatermarkData { // let watermark = KMPDFWatermarkData.returnWaterMarkWith(model, listView.document) // watermark.pageString = pageString // listView.document.addWatermark(watermark) // listView.layoutDocumentView() // } // exitEditToolbarView() // } else if view.editType == .background { // if let model = backgroundViewController?.backgroundModel { // if let background = listView.document.background() { // KMBackgroundManager.defaultManager.updateBackground(background, withModel: model) // background.pageString = pageString // background.update() // // listView.document?.refreshPageData() // listView.layoutDocumentView() // } // } // exitEditToolbarView() // // } else if view.editType == .header_Footer { // if let model = headerFooterViewController?.headerFooterModel { // if let headerFooter = listView.document.headerFooter() { // KMHeaderFooterManager.defaultManager.updateCPDFHeaderFooter(headerFooter, withModel: model, Int(listView.document.pageCount)) // headerFooter.pageString = pageString // headerFooter.update() // // listView.document?.refreshPageData() // listView.layoutDocumentView() // } // } // // exitEditToolbarView() // // } else if view.editType == .bates { // exitEditToolbarView() // // } } func kmEditToolbarViewDidChooseExit(_ view: KMEditToolbarView) { if view.applyEnable { let alert = NSAlert() if view.editType == .watermark { alert.messageText = NSLocalizedString("There are unapplied Watermark settings, do you want to apply them?", comment: "") } else if view.editType == .background { alert.messageText = NSLocalizedString("There are unapplied Background settings, do you want to apply them?", comment: "") } else if view.editType == .header_Footer { alert.messageText = NSLocalizedString("There are unapplied Header & Footer settings, do you want to apply them?", comment: "") } else if view.editType == .bates { alert.messageText = NSLocalizedString("There are unapplied Bates settings, do you want to apply them?", comment: "") } alert.informativeText = NSLocalizedString("If not, the changes will be lost.", comment: "") alert.addButton(withTitle: NSLocalizedString("Apply", comment: "")) alert.addButton(withTitle: NSLocalizedString("Don't Apply", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result == .alertFirstButtonReturn) { self.kmEditToolbarViewDidChooseApply(view) } else if (result == .alertSecondButtonReturn) { //"Don't Apply" exitEditToolbarView() } else if (result == .alertThirdButtonReturn) { //Cancel } } else { exitEditToolbarView() } } } //MARK: - KMCropControllerDelegate 裁剪相关代理 extension KMMainViewController: KMCropControllerDelegate { func kmCropControllerDidCrop(_ controller: KMCropController, _ cropRect: CGRect, _ view: KMPageRangeSelectView) { let rangeSelectResult = view.getSelectedPageIndex(listView.document) let indexs = rangeSelectResult.0 let isCurrentPage = rangeSelectResult.1 var uIndexs: [UInt] = [] for index in indexs { if index > 0 { uIndexs.append(UInt(index-1)) } } if isCurrentPage { uIndexs = [UInt(listView.currentPageIndex)] } cropPages(atIndexs: uIndexs, to: [cropRect]) removeCropController() viewManager.subToolMode = .None if let toolbarVC = self.pdfToolbarController { toolbarVC.refreshSecondToolbarItemsState() self.kmPDFToolbarControllerDidToolbarItemClicked(toolbarVC, KMPDFToolbar_edit_crop_Identifier) } } func kmCropControllerDidCropSeparate(_ controller: KMCropController, _ view: KMPageRangeSelectView) { let rangeSelectResult = view.getSelectedPageIndex(listView.document) let indexs = rangeSelectResult.0 let isCurrentPage = rangeSelectResult.1 var rectArray: Array<NSRect> = [] var uIndexs: [UInt] = [] for index in indexs { if index > 0 { uIndexs.append(UInt(index-1)) let page = self.listView.document.page(at: UInt(index-1)) let rect = KMCropTools.getPageForegroundBox(page!) rectArray.append(rect) } } if isCurrentPage { uIndexs = [UInt(listView.currentPageIndex)] } cropPages(atIndexs: uIndexs, to: rectArray) removeCropController() viewManager.subToolMode = .None if let toolbarVC = self.pdfToolbarController { toolbarVC.refreshSecondToolbarItemsState() self.kmPDFToolbarControllerDidToolbarItemClicked(toolbarVC, KMPDFToolbar_edit_crop_Identifier) } } func kmCropControllerDidCropAuto(_ controller: KMCropController, _ view: KMPageRangeSelectView) { let rangeSelectResult = view.getSelectedPageIndex(listView.document) let indexs = rangeSelectResult.0 let isCurrentPage = rangeSelectResult.1 var uIndexs: [UInt] = [] for index in indexs { if index > 0 { uIndexs.append(UInt(index-1)) } } if isCurrentPage { uIndexs = [UInt(listView.currentPageIndex)] } auto_cropPagesWhiteMargin(uIndexs) removeCropController() viewManager.subToolMode = .None if let toolbarVC = self.pdfToolbarController { toolbarVC.refreshSecondToolbarItemsState() self.kmPDFToolbarControllerDidToolbarItemClicked(toolbarVC, KMPDFToolbar_edit_crop_Identifier) } } func kmCropControllerDidChangedSelectionOrMagnification(_ controller: KMCropController) { if let cropVC = rightSideController?.edit_cropController { if cropVC.pdfView != controller.pdfView { cropVC.pdfView = controller.pdfView } cropVC.cropSeparateOn = false cropVC.cropAutoOn = false cropVC.reloadData() } } } //MARK: - KMWatermarkControllerDelegate 水印相关代理 extension KMMainViewController: KMWatermarkControllerDelegate { func kmWatermarkControllerDidUpdateMode(_ view: KMWatermarkController) { editToolbarView?.editSubType = view.editSubType editToolbarView?.reloadData() } func kmWatermarkControllerDidWatermarkUpdated(_ view: KMWatermarkController) { var applyEnable = true if let model = view.currentWatermarkData { if model.watermarkType == .text { if model.text == nil || model.text?.count == 0 { applyEnable = false } } else if model.watermarkType == .image { if model.imagePath == nil { applyEnable = false } } } else { applyEnable = false } editToolbarView?.applyEnable = applyEnable editToolbarView?.reloadData() } } //MARK: - KMBackgroundControllerDelegate 背景代理 extension KMMainViewController: KMBackgroundControllerDelegate { func kmBackgroundControllerDidUpdateMode(_ view: KMBackgroundController) { editToolbarView?.editSubType = view.editSubType } func kmBackgroundControllerDidWatermarkUpdated(_ view: KMBackgroundController) { var applyEnable = true if let model = view.backgroundModel { if model.type == .image { if model.imagePath == nil { applyEnable = false } } } else { applyEnable = false } editToolbarView?.applyEnable = applyEnable editToolbarView?.reloadData() } } //MARK: - KMHeaderFooterControllerDelegate 页眉页脚代理 extension KMMainViewController: KMHeaderFooterControllerDelegate { func kmHeaderFooterControllerDidUpdateModeType(_ view: KMHeaderFooterController) { editToolbarView?.editSubType = view.editSubType } func kmHeaderFooterControllerDidModelDataUpdated(_ view: KMHeaderFooterController) { var applyEnable = true if let model = view.headerFooterModel { if model.topLeftString.count == 0 && model.topCenterString.count == 0 && model.topRightString.count == 0 && model.bottomLeftString.count == 0 && model.bottomCenterString.count == 0 && model.bottomRightString.count == 0 { applyEnable = false } } else { applyEnable = false } editToolbarView?.applyEnable = applyEnable editToolbarView?.reloadData() } } //MARK: - KMBatesControllerDelegate Bates贝茨码代理 extension KMMainViewController: KMBatesControllerDelegate { func kmBatesControllerDidUpdateMode(_ view: KMBatesController) { editToolbarView?.editSubType = view.editSubType editToolbarView?.reloadData() } func kmBatesControllerDidModelDataUpdated(_ view: KMBatesController) { var applyEnable = true if let model = view.batesModel { if model.topLeftString.count == 0 && model.topCenterString.count == 0 && model.topRightString.count == 0 && model.bottomLeftString.count == 0 && model.bottomCenterString.count == 0 && model.bottomRightString.count == 0 { applyEnable = false } } else { applyEnable = false } editToolbarView?.applyEnable = applyEnable editToolbarView?.reloadData() } } //MARK: - CPDFViewDelegate PDFView代理 extension KMMainViewController: CPDFViewDelegate,CPDFListViewDelegate { func pdfViewDocumentDidLoaded(_ pdfView: CPDFView!) { sideBarController?.reloadPageTurnerData() documentLoadComplete() } func pdfViewCurrentPageDidChanged(_ pdfView: CPDFView!) { sideBarController?.reloadPageTurnerData() botaViewController?.currentPageDidChangedAction(listView: listView) //分屏视图 reloadPDFPageNumberToolbar() if viewManager.splitSyncScroll { if splitPDFController?.inPDFFirst == false && splitPDFController?.outPDFFirst == false { splitPDFController?.outPDFFirst = true if let splitPDFView = splitPDFController?.pdfView, let document = splitPDFView.document { var index = pdfView.currentPageIndex if index > document.pageCount { index = Int(splitPDFView.document.pageCount - 1) } splitPDFView.go(toPageIndex: index, animated: false) } NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(pdfUpdatedFinish), object: nil) self.perform(#selector(pdfUpdatedFinish), with: nil, afterDelay: 0.35) } else if splitPDFController?.outPDFFirst == true { if let splitPDFView = splitPDFController?.pdfView, let document = splitPDFView.document { var index = pdfView.currentPageIndex if index > document.pageCount { index = Int(splitPDFView.document.pageCount - 1) } splitPDFView.go(toPageIndex: index, animated: false) } NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(pdfUpdatedFinish), object: nil) self.perform(#selector(pdfUpdatedFinish), with: nil, afterDelay: 0.35) } } //水印 updateEditModeDocumentWhenPageChanged() // } func pdfViewScaleDidChanged(_ pdfView: CPDFView!) { pdfToolbarController?.reloadSelectZoomView() reloadPDFPageNumberToolbar() reloadPopUIWindow() //分屏视图 if viewManager.splitSyncScroll { if splitPDFController?.inPDFFirst == false && splitPDFController?.outPDFFirst == false { splitPDFController?.outPDFFirst = true NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(pdfUpdatedFinish), object: nil) self.perform(#selector(pdfUpdatedFinish), with: nil, afterDelay: 0.35) } else if splitPDFController?.outPDFFirst == true { if let splitPDFView = splitPDFController?.pdfView { splitPDFView.scaleFactor = pdfView.scaleFactor } NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(pdfUpdatedFinish), object: nil) self.perform(#selector(pdfUpdatedFinish), with: nil, afterDelay: 0.35) } } } func pdfViewDidClick(onLink pdfView: CPDFView!, withURL url: String!) { if let urlString = url, urlString == kKMPurchaseProductURLString { //跳转订阅比较表 return } if url.hasPrefix("smb://") { NSWorkspace.shared.openFile(url) } else { KMTools.openURL(urlString: url) } } func pdfViewPerformURL(_ pdfView: CPDFView!, withContent content: String!) { KMPrint("pdfViewPerformURL") if content != nil { NSWorkspace.shared.open(URL(string: content)!) } else { let alert = NSAlert() alert.alertStyle = .critical alert.informativeText = NSLocalizedString("The hyperlink is invalid.", comment: "") alert.messageText = "" alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() return } } func pdfViewPerformPrint(_ pdfView: CPDFView!) { KMPrint("pdfViewPerformPrint") self.showPrintWindow() } func pdfViewPerformGo(toPage pdfView: CPDFView!) { KMPrint("pdfViewPerformGo") } func pdfViewOpenPDF(_ pdfView: CPDFView!, forRemoteGoTo action: CPDFAction!) { KMPrint("pdfViewOpenPDF") } func pdfViewPerformReset(_ pdfView: CPDFView!) { KMPrint("pdfViewPerformReset") pdfView.document?.resetForm() } func pdfViewEditingBlockDidChanged(_ pdfView: CPDFView!) { KMPrint("pdfViewEditingBlockDidChanged") } func pdfViewAsBookBookmark() -> NSImage! { return NSImage(named: "KMImageNameBookmarkIcon")! } //MARK: -编辑模块 func pdfViewEditingSelectionDidChanged(_ pdfView: CPDFView!) { // 文本区块 选中文本已经变化 reloadPopUIWindow() } func pdfViewPDFSelectionAttributeDidChanged(_ pdfView: CPDFView!) { reloadPopUIWindow() } func pdfViewEditingAreaDidChanged(_ pdfView: CPDFView!) { //编辑模块变化 rightSideController?.reloadDataWithPDFView(pdfView: (pdfView as! CPDFListView)) if pdfView is CPDFListView { (pdfView as! CPDFListView).isEditImage = false } reloadPopUIWindow() } func pdfViewEditingCropBoundsDidChanged(_ pdfView: CPDFView!, editing editArea: CPDFEditArea!) { if editArea != nil && (editArea is CPDFEditImageArea){ self.listView.cropAreas = editArea as? CPDFEditImageArea } reloadPopUIWindow() } //编辑PDF 创建图片区域回调 func pdfViewEditingAddImageArea(_ pdfView: CPDFView!, add page: CPDFPage!, add rect: CGRect) { if (pdfView as! CPDFListView).isEditImage { return } if rect.size.width < 5 && rect.size.height < 5 { pdfView.updateEditing([]) return } 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 let 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 } var scale = min(previewSize.width / imageSize.width, previewSize.height / imageSize.height) if scale < 1 { // 大于 500 } else { let wh = max(imageSize.width, imageSize.height) if wh >= 72 { scale = min(scale, 1) } else { scale = min(72 / imageSize.width, 72 / 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 ?? .zero 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()) } } } } } func pdfViewEditingAddTextArea(_ pdfView: CPDFView!, add page: CPDFPage!, add rect: CGRect) { if rect.size.width < 5 && rect.size.height < 5 { let areas = self.listView.km_EditingAreas() if let area = areas.last { if let data = area as? CPDFEditTextArea { if let str = data.editTextAreaString(), str.isEmpty { self.listView.remove(with: area) } else { self.listView.updateEditing([]) } } } return } var newRect = rect if rect.size.equalTo(.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 fontSize = model.fontSize let fontColor = model.color let fontAlign = model.alignment NSColorPanel.shared.color = fontColor let attri = CEditAttributes() attri.cFont = CPDFFont(familyName: model.fontName, fontStyle: model.fontStyle) attri.fontColor = fontColor attri.alignment = fontAlign attri.isBold = model.bold attri.isItalic = model.italic self.listView.createStringBounds(newRect, with: attri, page: page) } func pdfViewMobileEditingBegan(_ point: CGPoint, for pdfView: CPDFView!, forEditing editingAreas: [CPDFEditArea]!) { rightSideController?.reloadEditingAreas() toggleClosePopUIWindow() } func pdfViewMobileEditingMove(_ point: CGPoint, for pdfView: CPDFView!, forEditing editingAreas: [CPDFEditArea]!) { rightSideController?.reloadEditingAreas() toggleClosePopUIWindow() } func pdfViewMobileEditingEnd(_ point: CGPoint, for pdfView: CPDFView!, forEditing editingAreas: [CPDFEditArea]!) { rightSideController?.reloadEditingAreas() reloadPopUIWindow() } func pdfViewEditingSelectCharDidChanged(_ pdfView: CPDFView!) { rightSideController?.reloadEditingAreas() reloadPopUIWindow() } func pdfViewEditingExitCropMode(_ pdfView: CPDFView!, forEditing editingArea: CPDFEditImageArea!) { rightSideController?.reloadEditingAreas() toggleClosePopUIWindow() } func pdfViewEditingOperationDidChanged(_ pdfView: CPDFView!) { let areas = self.listView.km_editingImageAreas() if areas.count == 1 { if let data = areas.first as? CPDFEditImageArea { let updating = self.listView.editAreaBoundUpdating if updating { self.listView.editAreaBoundUpdating = false } } } } func pdfViewEditingDoubleClick(_ pdfView: CPDFView!, imageArea editArea: CPDFEditArea!) { } func pdfListViewKeyDownIsContinue(_ pdfListView: CPDFListView!, theEvent: NSEvent!) -> Bool { let command = theEvent.modifierFlags.contains(.command) let control = theEvent.modifierFlags.contains(.control) KMPrint(theEvent.keyCode) if self.listView.isEditing() == true { if control && theEvent.keyCode == 11 { // ctr + b self.listView.setEditingTextarea_Bold() rightSideController?.reloadEditingAreas() return false } else if control && theEvent.keyCode == 34 { // ctr +i self.listView.setEditingTextarea_Italic() rightSideController?.reloadEditingAreas() return false } else if theEvent.keyCode == 36 { // enter if self.listView.isCropMode { self.listView.cropComfirmAction() rightSideController?.reloadEditingAreas() return false } } else if theEvent.keyCode == 53 { // Cancel if self.listView.isCropMode { self.listView.cropCancelAction() rightSideController?.reloadEditingAreas() return false } } } 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.shouAddEditAreaType() == .image || self.listView.shouAddEditAreaType() == .text { if self.listView.isEditImage { self.menuItemEditingClick_CropImage(sender: NSMenuItem()) } } } if theEvent.keyCode == 53 { //ESC self.exitFullScreen() if viewManager.isPDFReadMode { self.exitPDFReadMode() } self.leftSideViewCancelSelect() } return true } func pdfListViewMenuValidate(_ pdfListView: CPDFListView!, menuItem: NSMenuItem!, isTakesEffect: UnsafeMutablePointer<ObjCBool>!) -> 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 pdfListViewChangedToolMode(_ pdfListView: CPDFListView!, for toolMode: CToolMode) { reloadPopUIWindow() } func pdfListViewChangeatioActiveAnnotations(_ pdfListView: CPDFListView!, forActiveAnnotations annotations: [CPDFAnnotation]!, isRightMenu: Bool) { self.view.window?.makeFirstResponder(self.listView) reloadPopUIWindow() if isRightMenu { } else if annotations.count > 0 { if annotations.count > 1 { var isMultiAnnotations = pdfListView.isMultiAnnotation(annotations) if isMultiAnnotations == true { self.toggleCloseRightSide() } else { self.toggleOpenRightSide() } self.rightSideController?.reloadDataWithPDFView(pdfView: pdfListView) } else { let fristAnnotation = annotations.first let className = NSStringFromClass(fristAnnotation!.classForCoder) if self.viewManager.isPDFReadMode { toggleCloseRightSide() } else { self.toggleOpenRightSide() self.rightSideController?.reloadDataWithPDFView(pdfView: pdfListView) } } //测量相关 if (listView.activeAnnotation.isKind(of: CPDFLineAnnotation.self)) { if (!(listView.activeAnnotation as! CPDFLineAnnotation).isMeasure) { cancelMeasureType() } else { if distanceMeasureInfoWindowController == nil { let measureInfo = CPDFDistanceMeasureInfo() distanceMeasureInfoWindowController = CDistanceMeasureInfoWindowController() distanceMeasureInfoWindowController?.measureInfo = measureInfo distanceMeasureInfoWindowController?.delegate = self } } } else if (!listView.activeAnnotation.isKind(of: CPDFPolygonAnnotation.self) && !listView.activeAnnotation.isKind(of: CPDFPolylineAnnotation.self)) { cancelMeasureType() } else if (listView.activeAnnotation.isKind(of: CPDFPolygonAnnotation.self) || listView.activeAnnotation.isKind(of: CPDFPolylineAnnotation.self)) { if perimeterMeasureInfoWindowController == nil { let measureInfo = CPDFPerimeterMeasureInfo() perimeterMeasureInfoWindowController = CPerimeterMeasureInfoWindowController() perimeterMeasureInfoWindowController?.measureInfo = measureInfo perimeterMeasureInfoWindowController?.delegate = self } if areaMeasureInfoWindowController == nil { let measureInfo = CPDFAreaMeasureInfo() areaMeasureInfoWindowController = CAreaMeasureInfoWindowController() areaMeasureInfoWindowController?.measureInfo = measureInfo areaMeasureInfoWindowController?.delegate = self } } } else if (annotations.count == 0){ if pdfListView.annotationType == .unkown { toggleCloseRightSide() } else { if self.viewManager.isPDFReadMode { toggleCloseRightSide() } else { toggleOpenRightSide() } } rightSideController?.reloadDataWithPDFView(pdfView: pdfListView) } } func pdfListViewMobileAnnotationBegan(_ point: CGPoint, for pdfListView: CPDFListView!, forActiveAnnotations annotations: [CPDFAnnotation]!) { toggleClosePopUIWindow() } func pdfListViewMobileAnnotationMove(_ point: CGPoint, for pdfListView: CPDFListView!, forActiveAnnotations annotations: [CPDFAnnotation]!) { toggleClosePopUIWindow() } func pdfListViewMobileAnnotationEnd(_ point: CGPoint, for pdfListView: CPDFListView!, forActiveAnnotations annotations: [CPDFAnnotation]!) { reloadPopUIWindow() } func pdfListViewChangedAnnotationType(_ pdfListView: CPDFListView!, for annotationType: CAnnotationType) { if(annotationType == .unkown) { toggleCloseRightSide() } } func pdfListViewMenuItemsEditing(at point: CGPoint, for page: CPDFPage!, menuItems: [NSMenuItem]!) -> [NSMenuItem]! { return menuItems } func pdfListViewAddAnnotations(_ pdfListView: CPDFListView!, forAdd annotations: [CPDFAnnotation]!, in pdfPage: CPDFPage!) { var pageIndexes = IndexSet() pageIndexes.insert(Int(pdfPage.pageIndex())) botaViewController?.thumnailViewController?.reloadDataWithIndexs(pageIndexs: pageIndexes) } func pdfListViewRemoveAnnotations(_ pdfListView: CPDFListView!, forRemove annotations: [CPDFAnnotation]!, in pdfPage: CPDFPage!) { var pageIndexes = IndexSet() pageIndexes.insert(Int(pdfPage.pageIndex())) botaViewController?.thumnailViewController?.reloadDataWithIndexs(pageIndexs: pageIndexes) } func pdfListViewEditAnnotation(_ pdfListView: CPDFListView!, for anotation: CPDFAnnotation!) { if anotation.isKind(of: CPDFSignatureWidgetAnnotation.self) { if let signatureWidgetAnnotation = anotation as? CPDFSignatureWidgetAnnotation { let signature = signatureWidgetAnnotation.signature() if ((signature) != nil) { popUpSignatureWidgetState(signature!, listView) } else { let widget = CPDFSignatureWidgetAnnotation.init(PDFListViewNoteWith: listView.document) widget.bounds = NSMakeRect(-1000, -1000, 545, 178); anotation.page.addAnnotation(widget) let configWindowVC = DSignatureConfigWindowController.init(windowNibName: "DSignatureConfigWindowController") configWindowVC.viewType = .fileList; configWindowVC.appearanceWidget = widget; configWindowVC.isCreatDS = false configWindowVC.complentionHandle = {[weak self] isSign, dic, config, isLock in widget.page.removeAnnotation(widget) if isSign { if (dic.object(forKey: SAVEFILEPATH_KEY) != nil) { let p12Path = dic.object(forKey: SAVEFILEPATH_KEY) as! String let password = dic.object(forKey: PASSWORD_KEY) if p12Path.count > 0 { self?.writeSignatureToWidget(signatureWidgetAnnotation, p12Path, password as! String, config, isLock) } } } else { if signatureWidgetAnnotation.isSignSignatureAdd() == true { self?.listView.remove(anotation) } } } configWindowVC.actionBlock = {[weak self] controller, type in if (type == .cancel) { NSApplication.shared.stopModal() controller.window?.orderOut(nil) controller.window?.close() widget.page.removeAnnotation(widget) if signatureWidgetAnnotation.isSignSignatureAdd() == true { self?.listView.remove(anotation) } else { self?.listView.setNeedsDisplayAnnotationViewFor(anotation.page) } } else if (type == .confirm) { NSApplication.shared.stopModal() controller.window?.orderOut(nil) controller.window?.close() } } configWindowVC.window?.center() NSApplication.shared.runModal(for: configWindowVC.window!) } } } else if anotation.isKind(of: CPDFRedactAnnotation.self) { if let redactAnnotation = anotation as? CPDFRedactAnnotation { let properties = KMRedactPropertiesWindowController() properties.readactAnnotation = redactAnnotation self.km_beginSheet(windowC: properties) properties.callback = { [weak self] annotation in if let page = annotation?.page { self?.listView.setNeedsDisplayAnnotationViewFor(page) } } } } } //MARK: -Crop func pdfListViewChangedSelectionOrMagnification(_ pdfListView: CPDFListView!) { reloadPopUIWindow() } func pdfListViewDidSelectionEnd(_ pdfListView: CPDFListView!) { if (!self.listView.isEqual(to: pdfListView)) { return } if (self.listView.toolMode != .CSelectToolMode) { return } reloadPopUIWindow() } 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 pdfListViewAnnotationMeasureInfoChange(_ pdfListView: CPDFListView!, with annotation: CPDFAnnotation!) { guard let data = annotation else { if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.clearData() } return } if let lineAnnotation = annotation as? CPDFLineAnnotation { handleLineAnnotation(lineAnnotation) } else if let polylineAnnotation = annotation as? CPDFPolylineAnnotation { handlePolylineAnnotation(polylineAnnotation) } else if let polygonAnnotation = annotation as? CPDFPolygonAnnotation { handlePolygonAnnotation(polygonAnnotation) } } func pdfListViewMeasureCancel(_ pdfListView: CPDFListView!) { cancelMeasureType() } private func handleLineAnnotation(_ annotation: CPDFLineAnnotation) { if perimeterMeasureInfoWindowController?.window?.isVisible == true { perimeterMeasureInfoWindowController?.hideFloatingWindow() distanceMeasureInfoWindowController?.showWindow(self) } else if areaMeasureInfoWindowController?.window?.isVisible == true { areaMeasureInfoWindowController?.hideFloatingWindow() distanceMeasureInfoWindowController?.showWindow(self) } else if distanceMeasureInfoWindowController?.window?.isVisible == false { distanceMeasureInfoWindowController?.showWindow(self) } let measureInfo = annotation.measureInfo let startPoint = annotation.startPoint let endPoint = annotation.endPoint let angle = atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x) * (180.0 / .pi) distanceMeasureInfoWindowController?.angleLabel.stringValue = String(format: "%.2f°", abs(angle)) distanceMeasureInfoWindowController?.xLabel.stringValue = String(format: "%.0f", abs(endPoint.x - startPoint.x)) distanceMeasureInfoWindowController?.yLabel.stringValue = String(format: "%.0f", abs(endPoint.y - startPoint.y)) distanceMeasureInfoWindowController?.reloadData(with: measureInfo!) } private func handlePolylineAnnotation(_ annotation: CPDFPolylineAnnotation) { if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.hideFloatingWindow() perimeterMeasureInfoWindowController?.showWindow(self) } else if areaMeasureInfoWindowController?.window?.isVisible == true { areaMeasureInfoWindowController?.hideFloatingWindow() perimeterMeasureInfoWindowController?.showWindow(self) } else if perimeterMeasureInfoWindowController?.window?.isVisible == false { perimeterMeasureInfoWindowController?.showWindow(self) } let measureInfo = annotation.measureInfo let savePoints = annotation.savePoints() var angle: CGFloat = 0 if savePoints.count >= 3 { let count = savePoints.count let startPoint = savePoints[count - 3].pointValue let midPoint = savePoints[count - 2].pointValue let endPoint = savePoints.last!.pointValue angle = angleBetweenPoints(startPoint, midPoint, endPoint) } angle = 180 - angle perimeterMeasureInfoWindowController?.angleLabel.stringValue = String(format: "%.2f°", abs(angle)) perimeterMeasureInfoWindowController?.reloadData(with: measureInfo!) } private func handlePolygonAnnotation(_ annotation: CPDFPolygonAnnotation) { if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.hideFloatingWindow() areaMeasureInfoWindowController?.showWindow(self) } else if perimeterMeasureInfoWindowController?.window?.isVisible == true { perimeterMeasureInfoWindowController?.hideFloatingWindow() areaMeasureInfoWindowController?.showWindow(self) } else if areaMeasureInfoWindowController?.window?.isVisible == false { areaMeasureInfoWindowController?.showWindow(self) } let measureInfo = annotation.measureInfo let savePoints = annotation.savePoints var angle: CGFloat = 0 if savePoints.count >= 3 { let count = savePoints.count let startPoint = (savePoints[count - 3] as AnyObject).pointValue let midPoint = (savePoints[count - 2] as AnyObject).pointValue let endPoint = (savePoints.lastObject as AnyObject).pointValue angle = angleBetweenPoints(startPoint!, midPoint!, endPoint!) } angle = 180 - angle areaMeasureInfoWindowController?.angleLabel.stringValue = String(format: "%.2f°", abs(angle)) areaMeasureInfoWindowController?.reloadData(measureInfo!) } private func angleBetweenPoints(_ startPoint: CGPoint, _ midPoint: CGPoint, _ endPoint: CGPoint) -> CGFloat { let vector1 = CGPoint(x: midPoint.x - startPoint.x, y: midPoint.y - startPoint.y) let vector2 = CGPoint(x: endPoint.x - midPoint.x, y: endPoint.y - midPoint.y) let dotProduct = vector1.x * vector2.x + vector1.y * vector2.y let magnitude1 = sqrt(vector1.x * vector1.x + vector1.y * vector1.y) let magnitude2 = sqrt(vector2.x * vector2.x + vector2.y * vector2.y) return acos(dotProduct / (magnitude1 * magnitude2)) * (180.0 / .pi) } @objc func pdfUpdatedFinish() { splitPDFController?.inPDFFirst = false splitPDFController?.outPDFFirst = false } //MARK: - Notification @objc private func pdfViewScrollViewDidScroll(_ noti: Notification) { reloadPopUIWindow() } func pageCountChangedNotification(_ sender: Notification) { guard let document = sender.object as? CPDFDocument else { return } botaViewController?.pageCountChangedAction(document: document) } func annotationsAttributeHasChange(_ sender: Notification) { guard let dict = sender.object as? [String : Any] else { return } if let anno = dict["object"] as? CPDFAnnotation { let value = dict["keyPath"] as? String ?? "" let didEnd = dict["didEnd"] as? Bool ?? false if didEnd { if value == CPDFAnnotationBoundsKey { if anno is CPDFSquareAnnotation || anno is CPDFCircleAnnotation { anno.contents = anno.page?.string(for: anno.bounds) ?? "" } } if anno.km_isMeasure() && anno.contents == nil { anno.contents = anno.string() ?? "" } var pageIndexes = IndexSet() pageIndexes.insert(Int(anno.page.pageIndex())) botaViewController?.thumnailViewController?.reloadDataWithIndexs(pageIndexs: pageIndexes) reloadPopUIWindow() } else { if value != CPDFAnnotationBoundsKey && value != CPDFAnnotationStartPointKey && value != CPDFAnnotationEndPointKey && value != CPDFAnnotationPathsKey { // 改变bounds(箭头、直线注释 开始点和结束点, 手绘注释的paths)的操作会卡顿,比如移动 var pageIndexes = IndexSet() pageIndexes.insert(Int(anno.page.pageIndex())) botaViewController?.thumnailViewController?.reloadDataWithIndexs(pageIndexs: pageIndexes) reloadPopUIWindow() } } } } @objc fileprivate func signatureStateChangeNoti(_ sender: Notification) { guard let objecListView = sender.object as? CPDFListView else { return } if listView == objecListView { reloadDigitalSigns() alertTipViewController.reloadDigitalAlertUI() alertTipViewController.reloadAlertUIFrame() let signatureWidget = listView.editAnnotation if let signatureWidgetAnnotation = signatureWidget as? CPDFSignatureWidgetAnnotation { let signature = signatureWidgetAnnotation.signature() if signature == nil { return } signaturestateVC.signature = signature signaturestateVC.reloadData() } } } } //MARK: - KMNThumbnailBaseViewDelegate extension KMMainViewController: KMNThumbnailBaseViewDelegate { func clickThumbnailViewControlle(pageEditVC:KMNThumbnailBaseViewController?,currentIndex:Int) { exitPageEditMode() if listView.currentPageIndex != currentIndex { listView.go(toPageIndex: currentIndex, animated: true) } viewManager.isPageEditMode = false pdfToolbarController?.clickWithIdentify(KMPDFToolbar_PageEdit_Identifier) } func insertPDFThumbnailViewControlle(pageEditVC: KMNThumbnailBaseViewController?, pdfDocment: CPDFDocument?) { if(pdfDocment != nil) { insertDocuments.insert(pdfDocment!) } } func changeIndexPathsThumbnailViewControlle(pageEditVC: KMNThumbnailBaseViewController?, selectionIndexPaths: Set<IndexPath>, selectionStrings: String) { toolbarManager.page_pageInfo_Property.text = selectionStrings if(toolbarManager.page_pageInfo_Property.creatable == false) { toolbarManager.page_pageInfo_Property.creatable = true } pdfToolbarController?.refreshSecondToolbarItemsState() } } //MARK: - KMNLeftSideViewControllerDelegate extension KMMainViewController: KMNLeftSideViewControllerDelegate { func enterPageEditLeftSideViewController(leftSideViewController: KMNLeftSideViewController) { if viewManager.isPageEditMode == false { viewManager.isPageEditMode = true if(pdfToolbarController != nil) { kmPDFToolbarControllerDidToolbarItemClicked(pdfToolbarController!, KMPDFToolbar_PageEdit_Identifier) pdfToolbarController?.reloadSecondToolbar() } } } func changeSelectePageLeftSideViewController(leftSideViewController: KMNLeftSideViewController, pageIndex: Int) { if(listView.currentPageIndex != pageIndex) { listView.go(toPageIndex: pageIndex, animated: true) } } func addBookmarkForLeftC(controller: KMNLeftSideViewController, bookmark: CPDFBookmark?, info: [String : Any]?) { if let result = info?["result"] as? Bool { if result == false { if let targetV = listView.superview { _ = KMNCustomAlertView.alertView(message: KMLocalizedString("This page has been bookmarked"), type: .normal_custom, fromView: targetV, point:CGPointMake(targetV.frame.size.width/2, targetV.bounds.size.height-24)) } } } } func switchSearchPopWindow(controller: KMNLeftSideViewController) { closeLeftPane() let handdler = controller.searchViewC.handdler showSearchPopWindow(type: handdler.type, keyborad: handdler.searchKey, replaceText: handdler.replaceKey, results: handdler.searchResults) } func searchTypeDidChange(controller: KMNLeftSideViewController) { let handdler = controller.searchViewC.handdler if handdler.type == .replace { viewManager.toolMode = .Edit updatePDFViewAnnotationMode() } } } //MARK: - //MARK: - //MARK: - //MARK: - 旧代码,需要用到的内容需要拖出来,写好注释 extension KMMainViewController { internal func removeNotifications() { NotificationCenter.default.removeObserver(self) } func removeAllAnnotations() { let alert = NSAlert() alert.messageText = NSLocalizedString("This will permanently remove all annotations. Are you sure to continue?", comment: "") alert.addButton(withTitle: NSLocalizedString("Yes", comment:"")) alert.addButton(withTitle: NSLocalizedString("No", comment:"")) if (alert.runModal() != .alertFirstButtonReturn) { return } DispatchQueue.main.async { self.removeAllAnnotationsStore.store(t: self.listView) } } @objc func cancelMeasureType() { self.hideMeasureFloatingWindows() } func hideMeasureFloatingWindows() { if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.hideFloatingWindow() } else if perimeterMeasureInfoWindowController?.window?.isVisible == true { perimeterMeasureInfoWindowController?.hideFloatingWindow() } else if areaMeasureInfoWindowController?.window?.isVisible == true { areaMeasureInfoWindowController?.hideFloatingWindow() } } func showMeasureFloatingWindowsIfNeed() { let toolMode = self.listView.toolMode if toolMode != .CNoteToolMode { return } let type = self.listView.annotationType if type == .measureLine { self.distanceMeasureInfoWindowController?.window?.orderFront(nil) } else if type == .measurePolyLine { self.perimeterMeasureInfoWindowController?.window?.orderFront(nil) } else if type == .measurePolyGon { self.areaMeasureInfoWindowController?.window?.orderFront(nil) } else if type == .measureSquare { self.areaMeasureInfoWindowController?.window?.orderFront(nil) } } // MARK: - 标记密文 func enterRedact() { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_Redact_BuyNow" winC?.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.")) } 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 redactController = KMPDFRedactViewController(url: self.listView.document!.documentURL, password: self.listView.document?.password) self.addChild(redactController) redactController.view.autoresizingMask = [.width, .height] self.listView.isHidden = true redactController.scaleFactor = self.listView.scaleFactor redactController.titleBack = { [weak self] title in self?.view.window?.title = title } redactController.callback = { [weak self] result, currentPageIndex, saveResult, saveUrl in self?.listView.go(toPageIndex: self!.redactController.redactPdfView.currentPageIndex, animated: false) if result == false { // 退出 self?.exitRedact() return } let controller = self?._getPDFRedactController() controller?.redactPdfView.newAddAnnotation.removeAll() self?.exitRedact() if saveResult { let newDocument = CPDFDocument(url: saveUrl) if let data = newDocument?.isLocked, data { newDocument?.unlock(withPassword: self?.listView.document?.password ?? "") } self?.document = newDocument self?.listView.document = newDocument self?.listView.layoutDocumentView() } } redactController.setCurrentPageIndex(self.listView.currentPageIndex) } func exitRedact() { 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."), buttons: [KMLocalizedString("Exit"), KMLocalizedString("Cancel")]) { response in if response == .alertFirstButtonReturn { controller?.redactPdfView.newAddAnnotation.removeAll() self.exitRedact() } } return } } NSColorPanel.shared.showsAlpha = true controller?.redactPdfView.resignMonitor() controller?.view.removeFromSuperview() controller?.removeFromParent() self.listView.isHidden = false self.listView.annotationType = .unkown } func hasEnterRedact() -> Bool { return self._getPDFRedactController() != nil } //MARK: - AI func showAITypeChooseView(aiConfigType: AIConfigType) -> Void { if (self.document != nil) { AIChatInfoManager.defaultManager.currentFilePath = (self.document?.documentURL.path)! } else { AIChatInfoManager.defaultManager.currentFilePath = "" } let windowVC: AINewConfigWindowController = AINewConfigWindowController.currentWC() windowVC.chooseCurFileHandle = {[unowned self] windowVC in if AIChatInfoManager.defaultManager.currentFilePath.isEmpty == false { let documentArray = NSDocumentController.shared.documents var didFileEdit: Bool = false var curDoc: KMMainDocument! for document in documentArray { if document.fileURL?.path == AIChatInfoManager.defaultManager.currentFilePath { didFileEdit = document.isDocumentEdited curDoc = document as! KMMainDocument break } } if didFileEdit { let tempFileURL = FileManager.default.temporaryDirectory.appendingPathComponent(AIChatInfoManager.defaultManager.currentFilePath.lastPathComponent) if FileManager.default.fileExists(atPath: tempFileURL.path) { do { try FileManager.default.removeItem(at: tempFileURL) } catch { } } if curDoc != nil { curDoc.mainViewController?.SaveTempPDFDocumentToURLPath(tempPath: tempFileURL.path) } } windowVC.window?.becomeMain() } } if windowVC.window?.isVisible == true && windowVC.didSetOriginFrame == true { } else { var windowRect = windowVC.window?.frame windowRect!.origin.x = NSMaxX(self.view.window!.frame) - (windowRect?.size.width)! windowRect!.origin.y = NSMaxY(self.view.window!.frame) - (windowRect?.size.height)! - 64 windowVC.window?.setFrame(windowRect!, display: true) windowVC.didSetOriginFrame = true } windowVC.eventLabel = "AITools_Tbr" windowVC.showWindow(nil) if (aiConfigType != .none) { windowVC.eventLabel = "AITools_Start" if self.listView.currentSelection?.string()?.isEmpty == false { windowVC.setCurrentPDFSelection(self.listView.currentSelection.string()) } windowVC.chooseAIFunctionWithType(aiConfigType) } } @objc func aiTipIconViewShowStateChangeNoti() { } //MARK: - 引导 func loadFunctionGuide() -> Void { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { if self.view.window != nil { self.loadOpenFileFunctionGuide(.openFileNormal) } } } func loadOpenFileFunctionGuide(_ showType: KMGuideInfoType) -> Void { if showType == .openFileNormal && KMGuideInfoWindowController.availableShow(.openFileNormal) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .openFileNormal // guideWC.openPanelRect = (self.view.window?.contentView?.convert(leftPanelItem.frame, from: leftPanelItem.superview)) ?? .zero guideWC.window?.collectionBehavior = [.canJoinAllSpaces] guideWC.normalGuideFinishHandle = { [weak self] windowVC in } guideWC.finishHandle = { [weak self] windowVC, type in if type == .windowNewFinish || type == . windowDigitalFinish { self?.checkFirstTrialController() } } guideWC.openFileToggleHandle = { [weak self] windowVC, type in self?.checkFirstTrialController() } var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } else if showType == .digitalSignGuide && KMGuideInfoWindowController.availableShow(.digitalSignGuide) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .digitalSignGuide guideWC.window?.collectionBehavior = [.canJoinAllSpaces] guideWC.finishHandle = { [weak self] windowVC, type in self?.checkFirstTrialController() } var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } else if showType == .pdfCompareGuide && KMGuideInfoWindowController.availableShow(.pdfCompareGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .pdfCompareGuide guard let win = self.view.window else { return } guideWC.finishHandle = { [weak self] winC, type in if type == .windowNewFinish { DispatchQueue.main.async { self?.loadOpenFileFunctionGuide(.measureGuide) } return } } guideWC.window?.collectionBehavior = [.canJoinAllSpaces] var rect = self.view.window!.frame rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } } else if showType == .measureGuide && KMGuideInfoWindowController.availableShow(.measureGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guard let _ = self.view.window else { return } guideWC.type = .measureGuide guideWC.window?.collectionBehavior = [.canJoinAllSpaces] var rect = self.view.window?.frame ?? .zero rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } } else if showType == .convertGuide && KMGuideInfoWindowController.availableShow(.convertGuide) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { self.guideInfoWindowController = KMGuideInfoWindowController.currentWC() guard let guideWC = self.guideInfoWindowController else { return } guideWC.type = .convertGuide guard let win = self.view.window else { return } 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 = { 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 ?? .zero rect.size.height -= 20 guideWC.window?.setFrame(rect, display: false) guideWC.window?.minSize = rect.size guideWC.window?.maxSize = rect.size self.view.window?.addChildWindow(guideWC.window!, ordered: .above) guideWC.show() } } else { } } func checkFirstTrialController() -> Void { #if VERSION_DMG //打开文档后引导相关 if VerificationManager.default().status == .none { let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" let lastVersion = UserDefaults.standard.object(forKey: "SKLastTrialVersionMainDocumentLaunchedKey") as? String ?? "" if lastVersion.isEmpty || lastVersion != appVersion { UserDefaults.standard.setValue(appVersion, forKey: "SKLastTrialVersionMainDocumentLaunchedKey") UserDefaults.standard.synchronize() KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) } } #endif } // MARK: - 页面编辑 open func enterPageEdit(_ pages: [Int] = []) { if let doc = self.listView.document { if doc.allowsCopying == false || doc.allowsPrinting == false { KMBaseWindowController.checkPassword(url: doc.documentURL, type: .owner) { result, pwd in if result && pwd.isEmpty == false { self.listView.document?.unlock(withPassword: pwd) Task { @MainActor in self.enterPageEdit(pages) } } else { self.exitPageEdit() } } return } } //选中page var tPages = pages if tPages.count == 0 { } if (hasEnterPageEdit()) { exitPageEdit() return } let controller = KMPDFEditViewController(self.listView.document) controller.selectedPages = tPages controller.listView = self.listView self.addChild(controller) controller.view.autoresizingMask = [.width,.height] self.listView.isHidden = true controller.itemClick = { [weak self] index, params in if (index == 1) { /// 双击退出 DispatchQueue.main.async { let pageIndex: Int = params.first as! Int self?.listView.go(toPageIndex: pageIndex, animated: true) } } else if (index == 2) { // 打印 self?.showPrintWindow(pageRange: KMPrintPageRange(type: .custom, selectPages: params.first as! [Int])) } } controller.documentEditedCallback = { [weak self] params in self?.recordIsPDFDocumentEdited() } controller.selectionDidChange = { selectedIndexs in var indexSet = IndexSet() for indexPath in selectedIndexs { indexSet.insert(indexPath.item) } if indexSet.count != 0 { } } } open func exitPageEdit() { let editController = getPDFEditController() if (editController == nil) { return } self.listView.annotationType = .highlight // FIXME: - sdk修复插入特定文档crash后,这行代码可以去掉 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) } 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() { } private func removeBackgroundMaskView() { } private func _goToFirstPageForFristAppear() { DispatchQueue.main.asyncAfter(wallDeadline: .now()+0.1) { self.listView.go(toPageIndex: 0, animated: false) } } func isPDFPageCountExceedsLimit(filePath: String) -> Bool { let url = URL(fileURLWithPath: filePath) guard let document = PDFDocument(url: url) else { return false } let pageCount = document.pageCount return pageCount > 30 } // MARK: - Redact 【标记密文】 func exeRedactConfirm(_ type: KMRedactConfirmType, callback: @escaping () -> ()?) { let windowController = KMRedactConfirmWindowController(type) self.currentWindowController = windowController self.view.window?.beginSheet(windowController.window!) windowController.itemClick = { [weak self] index in if (index == 2) { /// 取消 self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil callback() return } self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil let panel = NSSavePanel() panel.nameFieldStringValue = "[新文件]"+((self?.listView.document?.documentURL.lastPathComponent) ?? "") let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.isExtensionHidden = true panel.beginSheetModal(for: (self?.view.window!)!) { response in if response != .OK { callback() return } if (type == .redactOne) { let anno = self!.listView.activeAnnotation if (anno == nil || (anno?.isKind(of: CPDFRedactAnnotation.self)) == false) { callback() return } (anno as! CPDFRedactAnnotation).applyRedaction() } else if (type == .redactAll) { self?.listView.document?.applyRedactions() } else if (type == .eraserOne) { let anno = self!.listView.activeAnnotation if (anno == nil || (anno?.isKind(of: CPDFRedactAnnotation.self)) == false) { callback() return } anno?.page.erasureRedact(from: anno!.bounds) } else if (type == .eraserAll) { KMRedactTools.eraserDocument((self?.listView.document)!) { result, errorAnno in if (result == false) { callback() return } } } self!.listView.document?.write(to: panel.url) if (button.state == .on) { NSDocumentController.shared.openDocument(withContentsOf: panel.url!, display: true) { document, alreadyOpen, error in } } else { NSWorkspace.shared.activateFileViewerSelecting([panel.url!]) } callback() } } } // MARK: - Secure 【安全】 public func hiddenSecureLimitTip() { self.secureAlertView?.removeFromSuperview() self.secureAlertView = nil } override func mouseMoved(with event: NSEvent) { self.view.window?.mouseMoved(with: event) } func savePageNumberIfNeed() { if (KMPreferenceManager.shared.openLastUnlockedDocumentWhenAppStart) { let scaleFactor = self.listView.scaleFactor ?? 0 if scaleFactor <= 0 { return } if self.listView.document != nil { KMPreferenceManager.shared.setPageNumber(self.listView.currentPageIndex, forKey: self.listView.document.documentURL.path) KMPreferenceManager.shared.setPageScale(Float(self.listView.scaleFactor), forKey: self.listView.document.documentURL.path) } } } // MARK: - 显示加密弹窗 public func showSecureWindow(_ url: URL) { self.securityWindowController = KMSecurityWindowController(windowNibName: "KMSecurityWindowController") guard let securityWindowController = securityWindowController else { return } securityWindowController.documentURL = self.listView.document?.documentURL securityWindowController.batchAction = { [unowned self] controller, files in self.view.window?.endSheet((securityWindowController.window)!) let batchWindowController = KMBatchOperateWindowController.sharedWindowController let batchOperateFile = KMBatchOperateFile(filePath: self.document?.documentURL.path ?? "", type: .AddPassword) batchWindowController.switchToOperateType(.AddPassword, files: [batchOperateFile]) batchWindowController.window?.makeKeyAndOrderFront("") } securityWindowController.doneAction = { [unowned self] controller, options, attribute in let openPanel = NSOpenPanel() openPanel.canChooseFiles = false openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.beginSheetModal(for: NSWindow.currentWindow()) { (result) in if result == NSApplication.ModalResponse.OK { for fileURL in openPanel.urls { let document = CPDFDocument(url: self.document?.documentURL) if document != nil { document!.setDocumentAttributes(attribute) let path = fileURL.path.stringByAppendingPathComponent(url.deletingPathExtension().lastPathComponent) + "_SetPassword" + "." + url.pathExtension let success = document!.write(to: NSURL(fileURLWithPath: path) as URL, withOptions: options) if success { self.view.window?.endSheet((securityWindowController.window)!) NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)]) } } } } } } securityWindowController.cancelAction = { [unowned self] controller in self.view.window?.endSheet((securityWindowController.window)!) } NSWindow.currentWindow().beginSheet(securityWindowController.window!) } // MARK: - 保存文档 internal func needSaveDocument() -> Bool { if (self.isPDFDocumentEdited) { return self.isPDFDocumentEdited } if (self.needSave) { return self.needSave } let document: KMMainDocument? = self.myDocument as? KMMainDocument if (document?.isDocumentEdited == nil || document?.isDocumentEdited == false) { return false } return true } internal func saveDocument(overlookDocumentIfEdited overlook: Bool = false) { let document: KMMainDocument? = self.myDocument as? KMMainDocument if (overlook) { document?.save(nil) return } if (self.isPDFDocumentEdited) { self.clearIsPDFDocumentEdited() self.needSave = false document?.save(nil) return } if (document?.isDocumentEdited == nil || document?.isDocumentEdited == false) { return } document?.save(nil) } internal func asyncSaveDocument(overlookDocumentIfEdited overlook: Bool = false, callback:@escaping KMCommonBlock) { let document: KMMainDocument? = self.myDocument as? KMMainDocument if (overlook) { DispatchQueue.main.async { document?.save(nil) callback() } return } if (self.isPDFDocumentEdited) { self.clearIsPDFDocumentEdited() self.needSave = false DispatchQueue.main.async { document?.save(nil) callback() } return } if (document?.isDocumentEdited == nil || document?.isDocumentEdited == false) { callback() return } DispatchQueue.main.async { document?.save(nil) callback() } } internal func saveDocumentWithProgressAlert(callback:@escaping KMCommonBlock) { // 显示进度 AutoSaveManager.manager.isSaving = true self.showProgressWindow(message: NSLocalizedString("Save", comment: "") + "PDF") self.progressC?.maxValue = 3.0 self.progressC?.increment(by: 1.0) // 保存文档 self.asyncSaveDocument { [weak self] params in // 执行进度 [假进度] self?.progressC?.increment(by: 1.0) self?.progressC?.increment(by: 1.0) DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { // 隐藏进度 self?.hiddenProgressWindow() DispatchQueue.main.asyncAfter(deadline: .now()+1) { AutoSaveManager.manager.isSaving = false } // 回调 callback() } } } func SaveTempPDFDocumentToURLPath(tempPath: String) { self.document?.write(toFile: tempPath) } // MARK: - 定时保存 func addAutoSaveEvent() { if (self.autoSaveTimer != nil) { self.autoSaveTimer?.invalidate() self.autoSaveTimer = nil } if self.document != nil { self.autoSaveTimer = Timer.scheduledTimer(withTimeInterval: AutoSaveManager.manager.timeInterval * 60, repeats: true, block: { [weak self] timer in self?.autoSaveTimerAction(timer) }) } self.checkAutoSaveInfo() } func checkAutoSaveInfo() { guard let cnt = AutoSaveManager.manager.autoSavePaths?.count, cnt > 0 else { return } if AutoSaveManager.manager.autoSaveAlertShow { return } AutoSaveManager.manager.autoSaveDidEndAction = false AutoSaveManager.manager.autoSaveAlertShow = true let blockSaveWindow = AutoSavePopController() blockSaveWindow.cancelHandle = { [weak self] windowController in AutoSaveManager.manager.autoSaveDidEndAction = true AutoSaveManager.manager.clearCache() self?.km_quick_endSheet() } blockSaveWindow.confirmHandle = { [weak self] windowController in self?.km_quick_endSheet() self?.saveAutoSaveInfo() } self.km_beginSheet(windowC: blockSaveWindow) } func saveAutoSaveInfo() { let openPanel = NSOpenPanel() openPanel.canChooseDirectories = true openPanel.canChooseFiles = false openPanel.allowsMultipleSelection = false let win = NSApp.keyWindow != nil ? NSApp.keyWindow : self.view.window openPanel.beginSheetModal(for: win!) { result in if (result == .OK) { let folderPath = openPanel.url?.path ?? openPanel.url?.absoluteString for path in AutoSaveManager.manager.opendPaths ?? [] { let _path = path as? String var newPath = "\(folderPath ?? "")/\(_path?.lastPathComponent ?? "")" newPath = self.getValidFilePath(newPath) do { try FileManager.default.moveItem(atPath: _path ?? "", toPath: newPath) } catch { NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: newPath)]) } } AutoSaveManager.manager.clearCache() } AutoSaveManager.manager.autoSaveDidEndAction = true } } func autoSaveTimerAction(_ timer: Timer) { if (self.document == nil || self.listView.document?.documentURL.path == nil) { return } if AutoSaveManager.manager.autoSaveDidEndAction == false { //防止提示弹窗出现后,未进行任何操作又进入自动保存的机制 return } if let data = self.document?.isLocked, data { return } if AutoSaveManager.manager.autoSaveEnabled == false { return } let documentArray = NSDocumentController.shared.documents var didFileEdit = false for doc in documentArray { if doc.fileURL?.path == self.document?.documentURL.path { didFileEdit = doc.isDocumentEdited break } } if (didFileEdit == false) { return } AutoSaveManager.manager.isSaving = true let savePath = AutoSaveManager.manager.autoSaveWithPath(self.listView.document?.documentURL.path ?? "") if (!self.document!.isLocked) { self.document?.write(to: URL(fileURLWithPath: savePath)) } DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { AutoSaveManager.manager.isSaving = false } } func removeAutoSaveInfo() { if self.autoSaveTimer != nil { self.autoSaveTimer?.invalidate() self.autoSaveTimer = nil } if AutoSaveManager.manager.autoSaveDidEndAction == false { //防止提示弹窗出现后,未进行任何操作又进入自动保存的机制 return } if AutoSaveManager.manager.autoSaveEnabled == false { return } if self.document == nil || self.listView.document?.documentURL.path == nil { return } AutoSaveManager.manager.removeAutoSavePath(self.listView.document?.documentURL.path ?? "") } // MARK: - 选择 PDFDisplay 模式 public func setPDFDisplay(pdfViewMode: CPDFDisplayViewMode) { listView.setDisplay(pdfViewMode) } // MARK: - 选择缩放模式 @objc public func selectZoom(_ type: KMPDFZoomType) { switch type { case .width: self.listView.autoScales = true break case .fit: if let pageHeight = self.listView.currentPage()?.size.height, pageHeight > 0 { let pdfviewHeight = self.listView.bounds.size.height self.listView.scaleFactor = pdfviewHeight/pageHeight self.listView.autoScales = false } break case .actualSize: if self.listView.scaleFactor != 1.0 { self.listView.scaleFactor = 1.0 self.listView.autoScales = false } break } } internal func createPdf(index:Int) { } // MARK - Event 监听 private func addEventMonitor() { if (self.eventMonitor != nil) { self.removeEventMonitor() } self.eventMonitor = NSEvent.addLocalMonitorForEvents(matching: [.scrollWheel, .leftMouseDown, .leftMouseUp]) { [weak self] event in if (event.type == .scrollWheel && event.modifierFlags.contains(.option)) { // Alt + 鼠标滚轮 self?.listView.magnifyWheel(event) return nil } else if event.type == .leftMouseDown { let point = event.locationInView(self?.listView ?? NSView()) let presentationDrawView = self?.listView.presentationDrawView if let data = self?.interactionMode, data == .presentation,CGRectContainsPoint(self?.listView.frame ?? .zero, point),presentationDrawView?.isHidden == true { // 幻灯片模式下 if point.x >= (self?.listView.frame.maxX ?? 0) / 2 { let can = self?.listView.canGoToNextPage() ?? false if can { self?.listView.goToNextPage(nil) } } else { let can = self?.listView.canGoToPreviousPage() ?? false if can { self?.listView.goToPreviousPage(nil) } } return nil } } return event } } func addKeyEventMonitor() { if (self.keyEventMonitor != nil) { self.removeKeyEventMonitor() } keyEventMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in if event.keyCode == 53 { if let data = self?.interactionMode, data == .presentation { // 幻灯片模式下 self?.exitFullScreen() return event } if self?.listView.toolMode == .CEditPDFToolMode { 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.shouAddEditAreaType() == .image || self?.listView.shouAddEditAreaType() == .text { } 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.shouAddEditAreaType() == .image { self?.listView.change([.text, .image]) } self?.toggleCloseRightSide() } else if(self?.listView.shouAddEditAreaType() == .image || self!.listView.shouAddEditAreaType() == .text) { if self?.listView.shouAddEditAreaType() == .image || self?.listView.shouAddEditAreaType() == .text { } self?.listView.setShouAddEdit([]) self?.listView.change([.text, .image]) self?.toggleCloseRightSide() } } else { if self?.listView.shouAddEditAreaType() == .image || self?.listView.shouAddEditAreaType() == .text { } } } } } else { if let data = self?.interactionMode, data == .presentation { // 幻灯片模式下 self?.listView.keyDown(with: event) return event } else { let cmd = event.modifierFlags.contains(.command) let shift = event.modifierFlags.contains(.shift) if event.keyCode == 6 { // z let editPDFIng = self?.listView.isEditing() ?? false if cmd && shift { // 恢复 let can = self?.listView.canEditTextRedo() ?? false if can == false { return event } if editPDFIng { _ = CustomAlertView.alertView(message: NSLocalizedString("Redo", comment: ""), fromView: self!.view, withStyle: .black) } } else if cmd { // 撤回 let can = self?.listView.canEditTextUndo() ?? false if can == false { return event } if editPDFIng { _ = CustomAlertView.alertView(message: NSLocalizedString("Undo", comment: ""), fromView: self!.view, withStyle: .black) } } } } } return event } } func removeKeyEventMonitor() { if (self.keyEventMonitor != nil) { KMPrint("removeKeyEventMonitor 已移除事件监听") NSEvent.removeMonitor(self.keyEventMonitor as Any) self.keyEventMonitor = nil } } private func removeEventMonitor() { if (self.eventMonitor != nil) { KMPrint("已移除事件监听") NSEvent.removeMonitor(self.eventMonitor as Any) self.eventMonitor = nil } } // MARK: - Tools func pdfViewCanHorizontalScroll() -> Bool { let scroll = self.listView.scroll() if (scroll == nil) { return false } return scroll?.horizontalScroller?.isHidden == nil ? false : !(scroll!.horizontalScroller!.isHidden) } func pdfViewCanVerticalScroll() -> Bool { let scroll = self.listView.scroll() if (scroll == nil) { return false } return scroll?.verticalScroller?.isHidden == nil ? false : !(scroll!.verticalScroller!.isHidden) } // MARK: - Public Methods // 清理数据 [eg. 通知] public func clearData() { KMThumbnailCache.shared.clearCache() self.removeNotifications() if (self.listView.spellingTag() > 0) { NSSpellChecker.shared.closeSpellDocument(withTag: self.listView.spellingTag()) } self.removeAutoSaveInfo() self.myDocument = nil } public func clearSecureOptions() { self._secureOptions = nil self.documentAttribute = nil } public func clearRemoveSecureFlag() { self._removeSecureFlag = false } public func recordIsPDFDocumentEdited(type: KMSubscribeWaterMarkType = .none) { km_synchronized(self) { self.model.isPDFDocumentEdited = true if type == .editText || type == .editImage { } if let _document = self.myDocument { KMTools.setDocumentEditedState(document: _document) } } } public func clearIsPDFDocumentEdited() { km_synchronized(self) { self.model.isPDFDocumentEdited = false } } func showSnapshots(setups: NSArray?) { if self.listView.document != nil { for setup in setups ?? [] { let swc = KMSnapshotWindowController() swc.delegate = self swc.setPdfDocument(self.listView.document, setup: setup as? NSDictionary) swc.setForceOnTop(self.interactionMode != .normal) self.myDocument?.addWindowController(swc) } } } // MARK: - Noti Actions internal func documentDidUnlockNotification(_ sender: Notification) { if (self.listView.document != nil && self.listView.document.isEqual(to: sender.object)) { if (self.myDocument == nil) { return } if (self.listView.document.allowsPrinting && self.listView.document.allowsCopying) { self.hiddenSecureLimitTip() } let isUnlockFromKeychain = (self.myDocument as? KMMainDocument)?.isUnlockFromKeychain ?? false if (isUnlockFromKeychain || self.model.isSaveKeyChain == false) { return } let type = KMPreferenceManager.shared.savePasswordType if (type == .never) { return } if (type == .always) { self.myDocument?.savePasswordInKeychain(self.listView.document.password, self.listView.document) return } // 保存到钥匙串 let alert = NSAlert() alert.messageText = NSLocalizedString("Remember Password?", comment: "") alert.informativeText = NSLocalizedString("Do you want to save this password in your Keychain?", comment: "") alert.addButton(withTitle: NSLocalizedString("Yes", comment: "")) alert.addButton(withTitle: NSLocalizedString("No", comment: "")) if (alert.runModal() == .alertFirstButtonReturn) { // 保存密码 self.myDocument?.savePasswordInKeychain(self.listView.document.password, self.listView.document) return } } } internal func applicationWillTerminateNotification(_ sender: Notification) { self.savePageNumberIfNeed() self.saveDocument() } func CEditPDFToolModeChangeStateUnkownNotification(_ sender: Notification) { var editSelectd = false if (self.listView.shouAddEditAreaType() == .text || self.listView.shouAddEditAreaType() == .image) && self.listView.toolMode == .CEditPDFToolMode { editSelectd = true } if self.listView.toolMode == .CEditPDFToolMode { if editSelectd { } } } @objc func handlePageChangedNotification(_ sender: Notification) { if self.mwcFlags.isSwitchingFullScreen > 0 { return } let page = self.listView.currentPage() let pageIndex = page?.pageIndex() ?? 0 } @objc func handleDisplayBoxChangedNotification(_ sender: Notification) { } }