// // KMNPDFInsertPDFWindowController.swift // PDF Reader Pro // // Created by 丁林圭 on 2024/10/22. // import Cocoa import KMComponentLibrary class KMNPDFInsertPDFWindowController: KMNBaseWindowController { @IBOutlet var titleLabel: NSTextField! @IBOutlet var fileLabel: NSTextField! @IBOutlet var fileNameInput: ComponentInput! @IBOutlet var selectFileInput: ComponentInputAddon! @IBOutlet var pageRangeLabel: NSTextField! @IBOutlet var pageRangeSelect: ComponentSelect! @IBOutlet var positionLabel: NSTextField! @IBOutlet var firstRadioButton: ComponentRadio! @IBOutlet var lastRadioButton: ComponentRadio! @IBOutlet var pageRadioButton: ComponentRadio! @IBOutlet var pageNumInput: ComponentInputNumber! @IBOutlet var pageCountLabel: NSTextField! @IBOutlet var positionSelect: ComponentSelect! @IBOutlet var cancelButton: ComponentButton! @IBOutlet var insertButton: ComponentButton! @IBOutlet var cancelWidthButton:NSLayoutConstraint! @IBOutlet var insertWidthButton:NSLayoutConstraint! @IBOutlet var pageRadioWidthButton:NSLayoutConstraint! private var orgDocument:CPDFDocument? private var insertFilePath:String? private var insertPDFPassword:String? private var insertDocument:CPDFDocument? private var selectionIndexPaths:Set? var pdfCallback: ((KMNFileAttribute, Int) -> Void)? var fileCallback: ((String, Int) -> Void)? convenience init(_ document: CPDFDocument?, selectionIndexPaths: Set?) { self.init(windowNibName: "KMNPDFInsertPDFWindowController") orgDocument = document self.selectionIndexPaths = selectionIndexPaths } convenience init(_ document: CPDFDocument?,filePath: String,password:String?,selectionIndexPaths: Set?) { self.init(windowNibName: "KMNPDFInsertPDFWindowController") orgDocument = document insertPDFPassword = password insertFilePath = filePath self.selectionIndexPaths = selectionIndexPaths } override func windowDidLoad() { super.windowDidLoad() if insertFilePath?.isEmpty == false && insertFilePath?.pathExtension == "pdf" { insertDocument = CPDFDocument(url: NSURL.fileURL(withPath: insertFilePath ?? "")) if let data = insertDocument?.isLocked, data { insertDocument?.unlock(withPassword: insertPDFPassword) } } } override func beginSheetFinish() { super.beginSheetFinish() pageCountLabel.stringValue = "/" + String(format: "%d", orgDocument?.pageCount ?? 0) pageRangeSelect.selectItemAtIndex(0) positionSelect.selectItemAtIndex(0) if(selectionIndexPaths?.count ?? 0 > 0) { pageRadioButton.properties.checkboxType = .selected let maxmumIndexPath = selectionIndexPaths?.max(by: { $0 < $1 }) pageNumInput.properties.text = String((maxmumIndexPath?.item ?? 0)+1) pageRadioButton.reloadData() pageNumInput.reloadData() } else { firstRadioButton.properties.checkboxType = .selected pageRadioButton.properties.checkboxType = .normal positionSelect.properties.isDisabled = true pageNumInput.properties.isDisabled = true firstRadioButton.reloadData() pageRadioButton.reloadData() pageNumInput.reloadData() positionSelect.reloadData() } self.updateInsertPDF() } private func setUpPageSelctProperty() { var menuItemString:[String] = [KMLocalizedString("All Pages"), KMLocalizedString("Odd Pages Only"), KMLocalizedString("Even Pages Only"), KMLocalizedString("e.g. 1,3-5,10")] if insertDocument?.pageCount ?? 0 <= 1 { menuItemString.removeObject(KMLocalizedString("Even Pages Only")) } var menuItemArr: [ComponentMenuitemProperty] = [] for language in menuItemString { let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: language) menuItemArr.append(itemProperty) } pageRangeSelect.updateMenuItemsArr(menuItemArr) } private func setUpPositionSelctProperty() { var menuItemArr: [ComponentMenuitemProperty] = [] for language in [KMLocalizedString("After"),KMLocalizedString("Before")] { let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: language) menuItemArr.append(itemProperty) } positionSelect.updateMenuItemsArr(menuItemArr) } override func updateUIThemeColor() { super.updateUIThemeColor() window?.contentView?.wantsLayer = true window?.contentView?.layer?.backgroundColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/popUp").cgColor titleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/1") fileLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") pageRangeLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-nor") positionLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") firstRadioButton.reloadData() lastRadioButton.reloadData() pageRadioButton.reloadData() insertButton.reloadData() cancelButton.reloadData() selectFileInput.reloadData() pageRangeSelect.reloadData() positionSelect.reloadData() } override func updateUILanguage() { super.updateUILanguage() titleLabel.stringValue = KMLocalizedString("Insert File") fileLabel.stringValue = KMLocalizedString("From PDF") pageRangeLabel.stringValue = KMLocalizedString("Page Range:") positionLabel.stringValue = KMLocalizedString("Where to insert?") firstRadioButton.properties.text = KMLocalizedString("First") lastRadioButton.properties.text = KMLocalizedString("Last") pageRadioButton.properties.text = KMLocalizedString("Page") firstRadioButton.reloadData() lastRadioButton.reloadData() pageRadioButton.reloadData() insertButton.properties.buttonText = KMLocalizedString("Insert") cancelButton.properties.buttonText = KMLocalizedString("Cancel") insertButton.reloadData() cancelButton.reloadData() selectFileInput.properties.text = KMLocalizedString("Browse") selectFileInput.reloadData() setUpPageSelctProperty() setUpPositionSelctProperty() let pageRangeSelectIndex = pageRangeSelect.indexOfSelect() if pageRangeSelectIndex == 0 { pageRangeSelect.properties.text = KMLocalizedString("All Pages") } else if(pageRangeSelectIndex == 1) { pageRangeSelect.properties.text = KMLocalizedString("Odd Pages Only") } else { if(orgDocument?.pageCount ?? 0 > 1 && pageRangeSelectIndex == 2) { pageRangeSelect.properties.text = KMLocalizedString("Even Pages Only") } } let positionSelectIndex = positionSelect.indexOfSelect() if positionSelectIndex == 0 { positionSelect.properties.text = KMLocalizedString("After") } else { positionSelect.properties.text = KMLocalizedString("Before") } pageRangeSelect.reloadData() positionSelect.reloadData() pageRadioWidthButton.constant = pageRadioButton.properties.propertyInfo.viewWidth cancelWidthButton.constant = cancelButton.properties.propertyInfo.viewWidth insertWidthButton.constant = insertButton.properties.propertyInfo.viewWidth } override func initContentView() { super.initContentView() titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") fileLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") pageRangeLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular") positionLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") firstRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("First"), checkboxType: .normal) lastRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Last"), checkboxType: .normal) pageRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Page"), checkboxType: .normal) insertButton.properties = ComponentButtonProperty(type: .primary, size: .s, state: .normal, isDisable: true, buttonText: KMLocalizedString("Insert")) insertButton.setTarget(self, action: #selector(insertButtonClicked(_ :))) insertWidthButton.constant = insertButton.properties.propertyInfo.viewWidth cancelButton.properties = ComponentButtonProperty(type: .default_tertiary, size: .s, state: .normal, buttonText: KMLocalizedString("Cancel")) cancelButton.setTarget(self, action: #selector(cancelButtonClicked(_ :))) cancelWidthButton.constant = cancelButton.properties.propertyInfo.viewWidth firstRadioButton.setTarget(self, action: #selector(insertPositionAction(_:))) lastRadioButton.setTarget(self, action: #selector(insertPositionAction(_:))) pageRadioButton.setTarget(self, action: #selector(insertPositionAction(_:))) pageNumInput.properties = ComponentInputNumberProperty(alignment: .left, size: .s, state: .normal, isError: false, showErrorInfo: false, isDisabled: false, showPrefix: false, showSuffix: false, minSize: 1, maxSize: Int(orgDocument?.pageCount ?? 1), text: "") pageNumInput.delegate = self let inputWithAddonProperty = ComponentInputProperty(size: .s, state: .normal, isError: false, showPrefix: false, showSuffix: false, showClear: false, isDisabled: false, placeholder: KMLocalizedString("Please enter..."), text: "", creatable: false) fileNameInput.properties = inputWithAddonProperty fileNameInput.properties.propertyInfo.cornerRadius_topRight = 0 fileNameInput.properties.propertyInfo.cornerRadius_bottomRight = 0 fileNameInput.reloadData() selectFileInput.properties = ComponentInputAddonProperty(size: .s, state: .normal, addOnBefore: false, onlyRead: false, addonType: .textWithColor, text: KMLocalizedString("Browse")) selectFileInput.setTarget(self, action: #selector(chooseURLAction(_ :))) pageRangeSelect.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: true, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("All Pages", comment: "")) positionSelect.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: false, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("After", comment: "")) setUpPositionSelctProperty() setUpPageSelctProperty() positionSelect.delegate = self pageRangeSelect.delegate = self pageRadioWidthButton.constant = pageRadioButton.properties.propertyInfo.viewWidth cancelWidthButton.constant = cancelButton.properties.propertyInfo.viewWidth insertWidthButton.constant = insertButton.properties.propertyInfo.viewWidth } private func updateInsertPDF() { fileNameInput.properties.text = insertFilePath ?? "" fileNameInput.reloadData() window?.makeFirstResponder(self) if(insertDocument != nil) { pageRangeSelect.properties.isDisabled = false pageRangeLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-nor") setUpPageSelctProperty() pageRangeSelect.selectItemAtIndex(0) pageRangeSelect.reloadData() } else { pageRangeSelect.properties.isDisabled = true pageRangeLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-dis") pageRangeSelect.selectItemAtIndex(0) pageRangeSelect.reloadData() } if(insertFilePath?.isEmpty == false) { if insertButton.properties.isDisabled == true { insertButton.properties.isDisabled = false insertButton.reloadData() } } } //MARK: - Action @objc func cancelButtonClicked(_ sender: NSView) { own_closeEndSheet() } @objc func insertButtonClicked(_ sender: NSView) { var insetPageDex:Int = 0 if firstRadioButton.properties.checkboxType == .selected { insetPageDex = 0 } else if lastRadioButton.properties.checkboxType == .selected { insetPageDex = Int(orgDocument?.pageCount ?? 0) } else if pageRadioButton.properties.checkboxType == .selected { insetPageDex = Int(pageNumInput.properties.text ?? "0") ?? 0 let positionSelectIndex = positionSelect.indexOfSelect() if (1 == positionSelectIndex) { insetPageDex -= 1 } } if(insertDocument != nil) { let pageRangeSelectIndex = pageRangeSelect.indexOfSelect() let fileAttribute = KMNFileAttribute() fileAttribute.pdfDocument = insertDocument fileAttribute.password = insertDocument?.password ?? "" fileAttribute.filePath = insertDocument?.documentURL.path ?? "" if pageRangeSelectIndex == 0 { fileAttribute.bAllPage = true fileAttribute.pagesType = .AllPages } else if pageRangeSelectIndex == 1 { fileAttribute.bAllPage = false fileAttribute.pagesType = .OnlyOdd } else { if(insertDocument?.pageCount ?? 0 <= 1) { fileAttribute.bAllPage = false fileAttribute.pagesType = .PagesString fileAttribute.pagesString = pageRangeSelect.properties.text ?? "" } else { fileAttribute.bAllPage = false if(pageRangeSelectIndex == 2) { fileAttribute.pagesType = .OnlyEven } else { fileAttribute.bAllPage = false fileAttribute.pagesType = .PagesString fileAttribute.pagesString = pageRangeSelect.properties.text ?? "" } } } if (fileAttribute.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() return } pdfCallback?(fileAttribute,insetPageDex) } else { fileCallback?(insertFilePath ?? "",insetPageDex) } own_closeEndSheet() } @objc func insertPositionAction(_ sender: NSView) { var oldSelectRadioBtn:ComponentRadio? = nil if sender == lastRadioButton { if(firstRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = firstRadioButton } else if (pageRadioButton.properties.checkboxType == .selected){ oldSelectRadioBtn = pageRadioButton pageNumInput.properties.isDisabled = true positionSelect.properties.isDisabled = true pageNumInput.reloadData() positionSelect.reloadData() } } else if sender == firstRadioButton { if(lastRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = lastRadioButton } else if (pageRadioButton.properties.checkboxType == .selected){ oldSelectRadioBtn = pageRadioButton pageNumInput.properties.isDisabled = true positionSelect.properties.isDisabled = true pageNumInput.reloadData() positionSelect.reloadData() } } else if sender == pageRadioButton { if(lastRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = lastRadioButton } else if (firstRadioButton.properties.checkboxType == .selected){ oldSelectRadioBtn = firstRadioButton } pageNumInput.properties.isDisabled = false positionSelect.properties.isDisabled = false pageNumInput.reloadData() positionSelect.reloadData() } if(oldSelectRadioBtn != nil) { oldSelectRadioBtn?.properties.checkboxType = .normal oldSelectRadioBtn?.reloadData() } } @objc func chooseURLAction(_ sender: NSView) { let openPanel = NSOpenPanel() let supportFiles = KMNConvertTool.pdfExtensions + KMConvertPDFManager.supportFileType() openPanel.allowedFileTypes = supportFiles openPanel.allowsMultipleSelection = false openPanel.beginSheetModal(for: self.window!) { [self] result in if (result == .OK) { let fileURL = openPanel.url if(fileURL?.pathExtension == "pdf") { let pdfDoc = CPDFDocument(url: fileURL) if let data = pdfDoc?.isLocked, data { DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { self.window?.windowController?.showCheckPassword(url: fileURL ?? NSURL.fileURL(withPath: ""), type: .owner, completion: { [weak self] success, resultPassword in if success && resultPassword.isEmpty == false { self?.insertDocument = CPDFDocument(url: fileURL) if let data = self?.insertDocument?.isLocked, data { self?.insertDocument?.unlock(withPassword: resultPassword) } self?.insertFilePath = fileURL?.path self?.updateInsertPDF() } }) } } else { self.insertDocument = CPDFDocument(url: fileURL) self.insertFilePath = fileURL?.path self.updateInsertPDF() } } else { self.insertDocument = nil self.insertFilePath = fileURL?.path self.updateInsertPDF() } } } } } //MARK: - ComponentInputNumberDelegate extension KMNPDFInsertPDFWindowController: ComponentInputNumberDelegate { func componentInputNumberDidValueChanged(inputNumber: ComponentInputNumber?) { if(inputNumber == pageNumInput) { } } } //MARK: - ComponentSelectDelegate extension KMNPDFInsertPDFWindowController: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { if(view == pageRangeSelect) { let pageRangeSelectIndex = pageRangeSelect.indexOfSelect() var isEditIndex:Int = 3 if(insertDocument?.pageCount ?? 0 <= 1) { isEditIndex = 2 } if (pageRangeSelectIndex == isEditIndex) { pageRangeSelect.properties.text = "" pageRangeSelect.properties.placeholder = KMLocalizedString("e.g. 1,3-5,10") pageRangeSelect.properties.creatable = true } else { pageRangeSelect.properties.placeholder = "" pageRangeSelect.properties.creatable = false } pageRangeSelect.reloadData() } } }