// // KMURLCreatePDFWindowController.swift // PDF Reader Pro // // Created by Niehaoyu on 2024/10/9. // import Cocoa import KMComponentLibrary let kUrlToPDFFolderPath = (try? FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(Bundle.main.bundleIdentifier ?? "").appendingPathComponent("WebPage"))?.path ?? "" @objc protocol KMURLCreatePDFWindowControllerDelegate: AnyObject { //选择打开文件 @objc optional func urlCreateWCDidChooseFileToOpen(_ vc: KMURLCreatePDFWindowController, _ fileURL: URL) } class KMURLCreatePDFWindowController: NSWindowController { @IBOutlet var contendBox: NSBox! @IBOutlet var titleLabel: NSTextField! @IBOutlet var urlRadio: ComponentRadio! @IBOutlet var fileRadio: ComponentRadio! @IBOutlet var inputView: ComponentInput! @IBOutlet var fileInputBGView: NSView! @IBOutlet var fileInputView: ComponentInput! @IBOutlet var fileInputAddon: ComponentInputAddon! @IBOutlet var cancelButton: ComponentButton! @IBOutlet var openButton: ComponentButton! private var _isFromURL: Bool = true private var parentWindow: NSWindow? private var handler: ((String?) -> Void)! private var posterMaskView: KMBookletMaskView? var choosedFilePath: String? var filePath: String? weak open var delegate: KMURLCreatePDFWindowControllerDelegate? override func windowDidLoad() { super.windowDidLoad() // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. setUpProperty() reloadData() } var isFromURL: Bool { get { return _isFromURL } set { _isFromURL = newValue reloadData() } } func setUpProperty() { titleLabel.stringValue = NSLocalizedString("New From Web Page", comment: "") titleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/1") titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") urlRadio.properties = ComponentCheckBoxProperty(size: .s, state: .normal, text: KMLocalizedString("URL"), checkboxType: .normal) urlRadio.setTarget(self, action: #selector(typeRadioChanged(_:))) fileRadio.properties = ComponentCheckBoxProperty(size: .s, state: .normal, text: KMLocalizedString("File"), checkboxType: .normal) fileRadio.setTarget(self, action: #selector(typeRadioChanged(_:))) inputView.properties = ComponentInputProperty(size: .s, state: .normal, isError: false, isDisabled: false, placeholder: KMLocalizedString("https://pdfreaderpro.com")) inputView.delegate = self fileInputView.properties = ComponentInputProperty(size: .s, state: .normal, isError: false, isDisabled: false, placeholder: KMLocalizedString("Select Files(.html,.webarchive)"), creatable: false) fileInputView.properties.propertyInfo.cornerRadius_topRight = 0 fileInputView.properties.propertyInfo.cornerRadius_bottomRight = 0 fileInputAddon.properties = ComponentInputAddonProperty(size: .s, state: .normal, addOnBefore: false, onlyRead: false, addonType: .imageWithColor, iconImage: NSImage(named: "file_icon")) fileInputAddon.setTarget(self, action: #selector(chooseURLAction(_ :))) cancelButton.properties = ComponentButtonProperty(type: .default_tertiary, size: .s, state: .normal, buttonText: KMLocalizedString("Cancel"), keepPressState: false) cancelButton.setTarget(self, action: #selector(cancelButtonClicked(_ :))) cancelButton.keyEquivalent = KMKeyEquivalent.esc.string() openButton.properties = ComponentButtonProperty(type: .primary, size: .s, state: .normal, buttonText: KMLocalizedString("Open"), keepPressState: false) openButton.setTarget(self, action: #selector(openButtonClicked(_ :))) openButton.keyEquivalent = KMKeyEquivalent.enter // Enter key } func reloadData() { urlRadio.properties.checkboxType = isFromURL ? .selected : .normal fileRadio.properties.checkboxType = isFromURL ? .normal : .selected fileInputBGView.isHidden = isFromURL ? true : false inputView.isHidden = isFromURL ? false : true cancelButton.properties.state = .normal openButton.properties.state = .normal if let filePath = choosedFilePath { fileInputView.properties.text = filePath } else { fileInputView.properties.text = "" } if isFromURL { if inputView.properties.text.count > 0 { openButton.properties.isDisabled = false } else { openButton.properties.isDisabled = true } } else { if fileInputView.properties.text.count > 0 { openButton.properties.isDisabled = false } else { openButton.properties.isDisabled = true } } inputView.reloadData() fileInputView.reloadData() fileInputAddon.reloadData() urlRadio.reloadData() fileRadio.reloadData() cancelButton.reloadData() openButton.reloadData() fileInputView.reloadData() } //MARK: - Action @objc func typeRadioChanged(_ sender: NSView) { if sender == fileRadio { isFromURL = false } else if sender == self.urlRadio { isFromURL = true } } @objc func cancelButtonClicked(_ sender: NSView) { choosedFilePath = nil inputView.properties.text = "" hideWaitting() reloadData() KMURLToPDF.shareInstance.stopLoading() handler?(nil) parentWindow?.endSheet(self.window!) } @objc func openButtonClicked(_ sender: NSView) { convertInfoToPDF() } @objc func chooseURLAction(_ sender: NSView) { let openPanel = NSOpenPanel() openPanel.allowedFileTypes = ["html", "HTML"] openPanel.allowsMultipleSelection = false openPanel.beginSheetModal(for: self.window!) { [weak self] result in if result == NSApplication.ModalResponse.OK { if let url = openPanel.url { self?.choosedFilePath = url.path self?.reloadData() } } } } func convertInfoToPDF() { if !FileManager.default.fileExists(atPath: kUrlToPDFFolderPath) { try? FileManager.default.createDirectory(atPath: kUrlToPDFFolderPath, withIntermediateDirectories: false, attributes: nil) } var url: URL? if isFromURL { var urlString = inputView.properties.text var tUrl = URL(string: urlString) if tUrl?.scheme?.count ?? 0 < 1 { if urlString.hasSuffix(".com") == false { urlString = urlString + ".com" } tUrl = URL(string: "http://\(urlString)") } url = tUrl } else { if let choosedFilePath = choosedFilePath { url = URL(fileURLWithPath: choosedFilePath) } } if let url = url { inputView.properties.text = url.absoluteString inputView.reloadData() showWaitting() let outPutPath = kUrlToPDFFolderPath if isFromURL { KMURLToPDF.shareInstance.convertLinkString(string: url.absoluteString, toPath: outPutPath) {[weak self] url, error in self?.hideWaitting() if error == nil && url?.path.isEmpty == false { self?.choosedFilePath = nil self?.inputView.properties.text = "" self?.reloadData() self?.handler?(url?.path) if let window = self?.window { self?.parentWindow?.endSheet(window) } } else { if let window = self?.window { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Conversion Failed", comment: "") if let description = error?.localizedDescription { alert.messageText = description } alert.beginSheetModal(for: window) { [weak self] result in } } } } } else { KMURLToPDF.shareInstance.convertHtmlFileToPDF(fromPath: url.path, toPath: outPutPath) {[weak self] url, error in self?.hideWaitting() if error == nil && url?.path.isEmpty == false { self?.choosedFilePath = nil self?.inputView.properties.text = "" self?.reloadData() self?.handler?(url?.path) if let window = self?.window { self?.parentWindow?.endSheet(window) } } else { if let window = self?.window { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Conversion Failed", comment: "") alert.beginSheetModal(for: window) { [weak self] result in } } } } } } } //MARK: - WaitingView func showWaitting() { if posterMaskView == nil { posterMaskView = KMBookletMaskView(frame: NSMakeRect(0, 0, window?.frame.size.width ?? 0, window?.frame.size.height ?? 0)) } contendBox.contentView?.addSubview(posterMaskView!, positioned: .below, relativeTo: self.cancelButton) } func hideWaitting() { posterMaskView?.removeFromSuperview() } //MARK: - public func own_beginSheetModal(for window: NSWindow?, completionHandler handler: ((String?) -> Void)?) { self.window?.makeFirstResponder(nil) if window != nil { parentWindow = window window!.beginSheet(self.window!) { ModalResponse in self.handler?(nil) } choosedFilePath = nil self.handler = handler hideWaitting() reloadData() } } override func becomeFirstResponder() -> Bool { return true } func formatFloat(_ f: Float) -> String { if f.truncatingRemainder(dividingBy: 1) == 0 { return String(format: "%.0f", f) } else if (f * 10).truncatingRemainder(dividingBy: 1) == 0 { return String(format: "%.1f", f) } else { return String(format: "%.2f", f) } } func isUrl(_ urlString: String?) -> Bool { guard let urlString = urlString else { return false } // 实现方法有问题,暂不使用 var url: String if urlString.count > 4, urlString.prefix(4) == "www." { url = "http://\(urlString)" } else { url = urlString } let urlRegex = "\\bhttps?://[a-zA-Z0-9\\-.]+(?::(\\d+))?(?:(?:/[a-zA-Z0-9\\-._?,'+\\&%$=~*!():@\\\\]*)+)?" let urlTest = NSPredicate(format: "SELF MATCHES %@", urlRegex) return urlTest.evaluate(with: url) } func urlValueEncode(_ str: String) -> String? { let allowedCharacterSet = CharacterSet(charactersIn: "!*'();:@&=+$,?%#[]{}").inverted return str.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) } //MARK: - MouseEvent override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) window?.makeFirstResponder(nil) } } //MARK: - ComponentInputDelegate extension KMURLCreatePDFWindowController: ComponentInputDelegate { func componentInputDidChanged(inputView: ComponentInput) { reloadData() } }