// // KMLinkViewController.swift // PDF Reader Pro // // Created by Niehaoyu on 2024/10/18. // import Cocoa import KMComponentLibrary @objc public enum PDFLinkType: Int, CaseIterable{ case Page = 0 // case Web // case Email // } @objc public enum PDFLinkPopupType: Int, CaseIterable{ case None = 0 //默认类型 case Page // case Web // case Email // case MultiSelect //Popup弹窗 } /** 未选中注释:修改默认添加类型。 选中注释: - 切换类型:判断类型->修改显示信息。 - 输入文字:修改跳转内容。 */ @objc protocol KMLinkViewControllerDelegate: AnyObject { @objc optional func kmLinkViewControllerDidUpdateMode(_ controller: KMLinkViewController) } //MARK: - KMLinkViewController @objcMembers class KMLinkViewController: NSViewController { @IBOutlet var contendBox: NSBox! @IBOutlet var infoContendView: NSView! @IBOutlet var tabsBGView: NSView! @IBOutlet var tabsView: ComponentTabs! @IBOutlet var typeContendView: NSView! @IBOutlet var linkPageView: KMLinkPageView! @IBOutlet var linkEmailView: KMLinkEmailView! @IBOutlet var linkWebView: KMLinkWebView! @IBOutlet var emptyContendView: ComponentEmpty! private weak var _pdfView: CPDFListView? = nil private var annotations: [CPDFLinkAnnotation] = [] private var current_Annotation: CPDFLinkAnnotation? = nil var multiController: KMNAlignmentController = KMNAlignmentController.init() //注释多选界面 let pageProperty = ComponentTabsProperty(tabsType: .underline_Fill, state: .normal, showIcon: false, title: NSLocalizedString("Page", comment: "")) let webProperty = ComponentTabsProperty(tabsType: .underline_Fill, state: .normal, showIcon: false, title: NSLocalizedString("Web", comment: "")) let emailProperty = ComponentTabsProperty(tabsType: .underline_Fill, state: .normal, showIcon: false, title: NSLocalizedString("Email", comment: "")) weak open var delegate: KMLinkViewControllerDelegate? public override func viewDidLoad() { super.viewDidLoad() // Do view setup here. setUpUI() } func setUpUI() { contendBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle") tabsView.updateItemProperty([pageProperty, webProperty, emailProperty]) tabsView.delegate = self linkPageView.delegate = self linkWebView.delegate = self linkEmailView.delegate = self multiController.delegate = self emptyContendView.properties = ComponentEmptyProperty(emptyType: .noLink, text: KMLocalizedString("Add Link"), subText: KMLocalizedString("Select an area or text on the page to add a link.")) } //MARK: - Setter var pdfLinkType: PDFLinkType = .Page { didSet { view.window?.makeFirstResponder(nil) } } weak var pdfView: CPDFListView? { get { return _pdfView } set { _pdfView = newValue } } //MARK: - func public func reloadData() { guard let pdfView = self.pdfView else { return } typeContendView.isHidden = true emptyContendView.isHidden = true multiController.view.isHidden = true tabsBGView.isHidden = false let pdfAnnotations: [CPDFAnnotation] = pdfView.activeAnnotations as? [CPDFAnnotation] ?? [] var linkAnnotations: [CPDFLinkAnnotation] = [] for annotation in pdfAnnotations { if annotation is CPDFLinkAnnotation { linkAnnotations.append((annotation as! CPDFLinkAnnotation)) } } annotations = linkAnnotations if annotations.count == 0 { emptyContendView.isHidden = false current_Annotation = nil linkPageView.clearData() linkWebView.clearData() linkEmailView.clearData() } else if annotations.count == 1 { if let annotation = annotations.first { if current_Annotation != annotation { current_Annotation = annotation linkPageView.clearData() linkWebView.clearData() linkEmailView.clearData() } } multiController.view.isHidden = true typeContendView.isHidden = false linkPageView.isHidden = true linkEmailView.isHidden = true linkWebView.isHidden = true if let url = current_Annotation?.url() { if url.hasPrefix("mailto:") { pdfLinkType = .Email } else { pdfLinkType = .Web } } else if let _ = current_Annotation?.destination() { pdfLinkType = .Page } if pdfLinkType == .Page { linkPageView.isHidden = false linkPageView.pdfView = pdfView linkPageView.annotation = current_Annotation linkPageView.reloadData() } else if pdfLinkType == .Web { linkWebView.isHidden = false linkWebView.annotation = current_Annotation } else if pdfLinkType == .Email { linkEmailView.isHidden = false linkEmailView.annotation = current_Annotation } } else { multiController.view.frame = CGRectMake((CGRectGetWidth(infoContendView.frame) - 232)/2, CGRectGetHeight(infoContendView.frame)-112, 232, 112) multiController.view.autoresizingMask = [.width, .maxYMargin] infoContendView.addSubview(multiController.view) multiController.view.isHidden = false tabsBGView.isHidden = true if annotations.count > 2 { multiController.aligHorizontalXButton.properties.isDisabled = false multiController.aligVerticalYButton.properties.isDisabled = false } else { multiController.aligHorizontalXButton.properties.isDisabled = true multiController.aligVerticalYButton.properties.isDisabled = true } multiController.aligHorizontalXButton.reloadData() multiController.aligVerticalYButton.reloadData() } pageProperty.state = .normal webProperty.state = .normal emailProperty.state = .normal if pdfLinkType == .Page { pageProperty.state = .pressed } else if pdfLinkType == .Web { webProperty.state = .pressed } else if pdfLinkType == .Email { emailProperty.state = .pressed } tabsView.refreshItems() } func pdfLinkTypeChanged() { guard let _ = current_Annotation else { return } linkPageView.isHidden = true linkEmailView.isHidden = true linkWebView.isHidden = true if pdfLinkType == .Page { linkPageView.isHidden = false linkPageView.reloadData() } else if pdfLinkType == .Web { linkWebView.isHidden = false } else if pdfLinkType == .Email { linkEmailView.isHidden = false } } //MARK: - MouseEvent public override func mouseUp(with event: NSEvent) { super.mouseUp(with: event) } } //MARK: - ComponentTabsDelegate extension KMLinkViewController: ComponentTabsDelegate { public func componentTabsDidSelected(_ view: ComponentTabs, _ property: ComponentTabsProperty) { if let annotation = current_Annotation { if property == pageProperty { pdfLinkType = .Page annotation.setURL(nil) if let page = pdfView?.document.page(at: UInt(linkPageView.choosedIndex-1)) { let bounds = page.bounds(for: .cropBox) let destination = CPDFDestination(page: page, at: NSPoint(x: 0, y: bounds.size.height)) annotation.setDestination(destination) } } else if property == webProperty { pdfLinkType = .Web annotation.setDestination(nil) let linkUrlPath = KMNTools.judgeWebURL(linkWebView.inputTextarea.properties.text) annotation.setURL(linkUrlPath) } else if property == emailProperty { pdfLinkType = .Email annotation.setDestination(nil) let linkUrlPath = KMNTools.judgeEmailURL(linkEmailView.inputTextarea.properties.text) annotation.setURL(linkUrlPath) } pdfLinkTypeChanged() } CPDFLinkAnnotation.updateDefault_AddLinkType(pdfLinkType.rawValue) delegate?.kmLinkViewControllerDidUpdateMode?(self) } } //MARK: - KMLinkPageViewDelegate extension KMLinkViewController: KMLinkPageViewDelegate { func kmLinkPageViewDidGoToPage(_ view: KMLinkPageView, _ pageIndex: Int) { if let _ = pdfView?.document.page(at: UInt(pageIndex-1)) { pdfView?.go(toPageIndex: pageIndex-1, animated: false) } } } //MARK: - KMLinkPageViewDelegate extension KMLinkViewController: KMLinkWebViewDelegate { func kmLinkWebViewDidGo(_ view: KMLinkWebView, _ webString: String) { guard let activeAnnotation = current_Annotation else { return } let linkUrlPath = KMNTools.judgeWebURL(webString) activeAnnotation.setURL(linkUrlPath) if let url = activeAnnotation.url() { if let data = URL(string: url) { NSWorkspace.shared.open(data) } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Invalid URL. Please try again.", comment: "") alert.runModal() } } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Invalid URL. Please try again.", comment: "") alert.runModal() } } } //MARK: - KMLinkEmailViewDelegate extension KMLinkViewController: KMLinkEmailViewDelegate { func kmLinkEmailViewDidGo(_ view: KMLinkEmailView, _ emailString: String) { guard let activeAnnotation = current_Annotation else { return } if !KMNTools.isValidateEmail(emailString) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Invalid Email. Please try again.", comment: "") alert.runModal() return } if let url = activeAnnotation.url() { NSWorkspace.shared.open(URL(string: url)!) } } } //MARK: - KMNAlignmentControllerDelegate extension KMLinkViewController: KMNAlignmentControllerDelegate { func alignmentControllerDidClick(_ controller: KMNAlignmentController, _ alignmentType: KMPDFActiveFormsAlignType) { pdfView?.change(annotations, alignmentType: alignmentType) pdfView?.setNeedsDisplayForVisiblePages() } } //MARK: - KMLinkViewController Class Method extension KMLinkViewController { }