// // KMNPDFInsertBlankWindowController.swift // PDF Reader Pro // // Created by 丁林圭 on 2024/10/23. // import Cocoa import KMComponentLibrary class KMNPDFInsertBlankWindowController: KMNBaseWindowController { @IBOutlet var titleLabel: NSTextField! @IBOutlet var sizeLabel: NSTextField! @IBOutlet var currentRadioButton: ComponentRadio! @IBOutlet var standardRadioButton: ComponentRadio! @IBOutlet var standardSelect: ComponentSelect! @IBOutlet var customizationRadioButton: ComponentRadio! @IBOutlet var widthInput: ComponentInput! @IBOutlet var heightInput: ComponentInput! @IBOutlet var unitSelect: ComponentSelect! @IBOutlet var directionLabel: NSTextField! @IBOutlet var verticalRadioButton: ComponentRadio! @IBOutlet var horizontalRadioButton: ComponentRadio! @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 standardRadioWidthButton:NSLayoutConstraint! @IBOutlet var customizationRadioWidthButton:NSLayoutConstraint! @IBOutlet var verticalRadioWidthButton:NSLayoutConstraint! @IBOutlet var cancelWidthButton:NSLayoutConstraint! @IBOutlet var insertWidthButton:NSLayoutConstraint! @IBOutlet var pageRadioWidthButton:NSLayoutConstraint! private var orgDocument:CPDFDocument? private var selectionIndexPaths:Set? private var lastUnitString: String = "mm" var callback: ((CGSize, Int) -> Void)? convenience init(_ document: CPDFDocument?, selectionIndexPaths: Set?) { self.init(windowNibName: "KMNPDFInsertBlankWindowController") orgDocument = document self.selectionIndexPaths = selectionIndexPaths } convenience init(_ filePath: String,password:String?) { self.init(windowNibName: "KMNPDFInsertBlankWindowController") let document = CPDFDocument.init(url: URL(fileURLWithPath: filePath)) if password != nil { document?.unlock(withPassword: password as String?) } orgDocument = document } 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) } private func setUpUnitSelctProperty() { var menuItemArr: [ComponentMenuitemProperty] = [] for language in ["mm","cm","in"] { let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: language) menuItemArr.append(itemProperty) } unitSelect.updateMenuItemsArr(menuItemArr) } private func setUpPageSizeSelctProperty() { let paperArray = KMNPageSizeTool.paperSize() var menuItemArr: [ComponentMenuitemProperty] = [] for pageSizeString in paperArray { let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: pageSizeString) menuItemArr.append(itemProperty) } standardSelect.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") sizeLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") directionLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") positionLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") currentRadioButton.reloadData() standardRadioButton.reloadData() customizationRadioButton.reloadData() firstRadioButton.reloadData() lastRadioButton.reloadData() pageRadioButton.reloadData() insertButton.reloadData() cancelButton.reloadData() unitSelect.reloadData() standardSelect.reloadData() positionSelect.reloadData() } override func updateUILanguage() { super.updateUILanguage() titleLabel.stringValue = KMLocalizedString("Insert Blank Page") sizeLabel.stringValue = KMLocalizedString("Page Size") directionLabel.stringValue = KMLocalizedString("Direction") positionLabel.stringValue = KMLocalizedString("Where to insert?") currentRadioButton.properties.text = KMLocalizedString("Current Size") standardRadioButton.properties.text = KMLocalizedString("Standard") customizationRadioButton.properties.text = KMLocalizedString("Custom") firstRadioButton.properties.text = KMLocalizedString("First") lastRadioButton.properties.text = KMLocalizedString(("Last")) pageRadioButton.properties.text = KMLocalizedString("Page") verticalRadioButton.properties.text = KMLocalizedString("Landscape pages") horizontalRadioButton.properties.text = KMLocalizedString("Portrait pages") setUpPositionSelctProperty() setUpUnitSelctProperty() setUpPageSizeSelctProperty() insertButton.properties.buttonText = KMLocalizedString("Insert") cancelButton.properties.buttonText = KMLocalizedString("Cancel") let positionSelectIndex = positionSelect.indexOfSelect() if positionSelectIndex == 0 { positionSelect.properties.text = KMLocalizedString("After") } else { positionSelect.properties.text = KMLocalizedString("Before") } currentRadioButton.reloadData() standardRadioButton.reloadData() customizationRadioButton.reloadData() firstRadioButton.reloadData() lastRadioButton.reloadData() pageRadioButton.reloadData() insertButton.reloadData() cancelButton.reloadData() positionSelect.reloadData() } override func initContentView() { super.initContentView() titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") sizeLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") directionLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") sizeLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") positionLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") var currentPageDex = 0 if(selectionIndexPaths?.count ?? 0 > 0) { pageRadioButton.properties.checkboxType = .selected let maxmumIndexPath = selectionIndexPaths?.max(by: { $0 < $1 }) currentPageDex = maxmumIndexPath?.item ?? 0 } let page = self.orgDocument?.page(at: UInt(currentPageDex)) as? CPDFPage let rect = page?.bounds ?? CGRectZero var width = KMNPageSizeTool.conversion(withUnit: "mm", value: (NSWidth(rect)/595 * 210)) var height = KMNPageSizeTool.conversion(withUnit: "mm", value: (NSHeight(rect)/842 * 297)) if((page?.rotation ?? 0) % 180 != 0) { width = KMNPageSizeTool.conversion(withUnit: "mm", value: (NSHeight(rect)/595 * 210)) height = KMNPageSizeTool.conversion(withUnit: "mm", value: (NSWidth(rect)/842 * 297)) } currentRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: String(format: "%@(%@ x %@mm)", KMLocalizedString("Current Size"),width,height), checkboxType: .selected) standardRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Standard"), checkboxType: .normal) customizationRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Custom"), checkboxType: .normal) 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) verticalRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Landscape pages"), checkboxType: .normal) horizontalRadioButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Portrait pages"), checkboxType: .selected) unitSelect.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: true, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("mm", comment: "")) unitSelect.delegate = self standardSelect.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: true, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("A4", comment: "")) standardSelect.delegate = self positionSelect.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: false, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("After", comment: "")) positionSelect.delegate = self insertButton.properties = ComponentButtonProperty(type: .primary, size: .s, state: .normal, isDisable: false, 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(_:))) verticalRadioButton.setTarget(self, action: #selector(insertDirectionAction(_:))) horizontalRadioButton.setTarget(self, action: #selector(insertDirectionAction(_:))) currentRadioButton.setTarget(self, action: #selector(insertPageSizeAction(_:))) standardRadioButton.setTarget(self, action: #selector(insertPageSizeAction(_:))) customizationRadioButton.setTarget(self, action: #selector(insertPageSizeAction(_:))) pageNumInput.properties = ComponentInputNumberProperty(alignment: .left, size: .s, state: .normal, isError: false, showErrorInfo: false, isDisabled: true, showPrefix: false, showSuffix: false, minSize: 1, maxSize: Int(orgDocument?.pageCount ?? 1), text: SettingsManager.sharedInstance.autoSaveMinutes) pageNumInput.delegate = self let inputWidthProperty: ComponentInputProperty = ComponentInputProperty(size: .s, state:.pressed , isError: false, showPrefix: false, showSuffix: false, showClear: false, isDisabled: true, placeholder: "210", text: "210") widthInput.properties = inputWidthProperty widthInput.delegate = self let inputHeightProperty: ComponentInputProperty = ComponentInputProperty(size: .s, state:.pressed , isError: false, showPrefix: false, showSuffix: false, showClear: false, isDisabled: true, placeholder: "297", text: "297") heightInput.properties = inputHeightProperty heightInput.delegate = self pageCountLabel.stringValue = "/" + String(format: "%d", orgDocument?.pageCount ?? 0) setUpPositionSelctProperty() setUpUnitSelctProperty() setUpPageSizeSelctProperty() pageRadioWidthButton.constant = pageRadioButton.properties.propertyInfo.viewWidth cancelWidthButton.constant = cancelButton.properties.propertyInfo.viewWidth insertWidthButton.constant = insertButton.properties.propertyInfo.viewWidth standardRadioWidthButton.constant = standardRadioButton.properties.propertyInfo.viewWidth customizationRadioWidthButton.constant = customizationRadioButton.properties.propertyInfo.viewWidth verticalRadioWidthButton.constant = verticalRadioButton.properties.propertyInfo.viewWidth } override func windowDidLoad() { super.windowDidLoad() positionSelect.selectItemAtIndex(0) unitSelect.selectItemAtIndex(0) standardSelect.selectItemAtIndex(1) pageCountLabel.stringValue = "/" + String(format: "%d", orgDocument?.pageCount ?? 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) pageNumInput.properties.isDisabled = false 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() } } //MARK: - Action @objc func cancelButtonClicked(_ sender: NSView) { own_closeEndSheet() } @objc func insertButtonClicked(_ sender: NSView) { self.window?.makeFirstResponder(nil) var currentPageDex = 0 if(selectionIndexPaths?.count ?? 0 > 0) { pageRadioButton.properties.checkboxType = .selected let maxmumIndexPath = selectionIndexPaths?.max(by: { $0 < $1 }) currentPageDex = maxmumIndexPath?.item ?? 0 } var height: CGFloat = 0 var width: CGFloat = 0 if currentRadioButton.properties.checkboxType == .selected { let page = self.orgDocument?.page(at: UInt(currentPageDex)) as? CPDFPage let rect = page?.bounds ?? .zero width = rect.size.width height = rect.size.height let w = KMPageSizeTool.conversion(withUnit: "mm", value: (NSWidth(rect)/595 * 210)) let h = KMPageSizeTool.conversion(withUnit: "mm", value: (NSHeight(rect)/842 * 297)) width = w.stringToCGFloat() height = h.stringToCGFloat() if((page?.rotation ?? 0) % 180 != 0) { width = h.stringToCGFloat() height = w.stringToCGFloat() } } else if standardRadioButton.properties.checkboxType == .selected { let sizeString = standardSelect.properties.text ?? KMNPaperSizeNameA4 let tSize = KMPageSizeTool.getPaperSize(paperName: sizeString) width = KMPageSizeTool.conversion(withUnit: "mm", value: tSize.width).stringToCGFloat() height = KMPageSizeTool.conversion(withUnit: "mm", value: tSize.height).stringToCGFloat() } else if customizationRadioButton.properties.checkboxType == .selected { let unitString = unitSelect.properties.text ?? "mm" height = widthInput.properties.text.stringToCGFloat() width = heightInput.properties.text.stringToCGFloat() width = KMPageSizeTool.conversion(with: "mm", from: unitString, value: width).stringToCGFloat() height = KMPageSizeTool.conversion(with: "mm", from: unitString, value: height).stringToCGFloat() if(!(width > 0 && height > 0)) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("Please enter the correct size.") alert.runModal() return } } width *= 595 / 210 height *= 842 / 297 var insertSize = CGSize(width: width, height: height) if(verticalRadioButton.properties.checkboxType == .selected) { if(width < height) { insertSize = CGSize(width: height, height: width) } } else if(horizontalRadioButton.properties.checkboxType == .selected){ if(width > height) { insertSize = CGSize(width: height, height: width) } } 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 } } callback?(insertSize, 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 insertDirectionAction(_ sender: NSView) { var oldSelectRadioBtn:ComponentRadio? = nil if sender == verticalRadioButton { if(horizontalRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = horizontalRadioButton } } else if sender == horizontalRadioButton { if(verticalRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = verticalRadioButton } } if(oldSelectRadioBtn != nil) { oldSelectRadioBtn?.properties.checkboxType = .normal oldSelectRadioBtn?.reloadData() } let widthString = widthInput.properties.text let heightString = heightInput.properties.text var width = widthString.stringToCGFloat() var height = heightString.stringToCGFloat() if(verticalRadioButton.properties.checkboxType == .selected) { if(width < height) { widthInput.properties.text = heightString heightInput.properties.text = widthString widthInput.reloadData() heightInput.reloadData() } } else if(horizontalRadioButton.properties.checkboxType == .selected){ if(width > height) { widthInput.properties.text = heightString heightInput.properties.text = widthString widthInput.reloadData() heightInput.reloadData() } } } @objc func insertPageSizeAction(_ sender: NSView) { var oldSelectRadioBtn:ComponentRadio? = nil if sender == currentRadioButton { if(standardRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = standardRadioButton standardSelect.properties.isDisabled = true standardSelect.reloadData() } else if (customizationRadioButton.properties.checkboxType == .selected){ oldSelectRadioBtn = customizationRadioButton widthInput.properties.isDisabled = true widthInput.reloadData() heightInput.properties.isDisabled = true heightInput.reloadData() unitSelect.properties.isDisabled = true unitSelect.reloadData() } } else if sender == standardRadioButton { if(currentRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = currentRadioButton } else if (customizationRadioButton.properties.checkboxType == .selected){ oldSelectRadioBtn = customizationRadioButton widthInput.properties.isDisabled = true widthInput.reloadData() heightInput.properties.isDisabled = true heightInput.reloadData() unitSelect.properties.isDisabled = true unitSelect.reloadData() } standardSelect.properties.isDisabled = false standardSelect.reloadData() } else if sender == customizationRadioButton { if(currentRadioButton.properties.checkboxType == .selected) { oldSelectRadioBtn = currentRadioButton } else if (standardRadioButton.properties.checkboxType == .selected){ oldSelectRadioBtn = standardRadioButton standardSelect.properties.isDisabled = true standardSelect.reloadData() } widthInput.properties.isDisabled = false widthInput.reloadData() heightInput.properties.isDisabled = false heightInput.reloadData() unitSelect.properties.isDisabled = false unitSelect.reloadData() } if(oldSelectRadioBtn != nil) { oldSelectRadioBtn?.properties.checkboxType = .normal oldSelectRadioBtn?.reloadData() } } } //MARK: - ComponentInputNumberDelegate extension KMNPDFInsertBlankWindowController: ComponentInputNumberDelegate { func componentInputNumberDidValueChanged(inputNumber: ComponentInputNumber?) { if(inputNumber == pageNumInput) { } } } //MARK: - ComponentSelectDelegate extension KMNPDFInsertBlankWindowController: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { if(view == unitSelect) { let width = widthInput.properties.text.stringToCGFloat() let height = heightInput.properties.text.stringToCGFloat() widthInput.properties.text = KMNPageSizeTool.conversion(with: unitSelect.properties.text ?? "mm", from: lastUnitString, value: width) heightInput.properties.text = KMNPageSizeTool.conversion(with: unitSelect.properties.text ?? "mm", from: lastUnitString, value: height) lastUnitString = unitSelect.properties.text ?? "mm" widthInput.reloadData() heightInput.reloadData() } else if (view == standardSelect) { } else if (view == positionSelect) { } } } //MARK: - ComponentInputDelegate extension KMNPDFInsertBlankWindowController: ComponentInputDelegate { //文字变化 func componentInputDidChanged(inputView: ComponentInput) { if (inputView == widthInput) { let fValue = widthInput.properties.text.stringToCGFloat() if fValue > heightInput.properties.text.stringToCGFloat() { verticalRadioButton.properties.checkboxType = .selected horizontalRadioButton.properties.checkboxType = .normal } else { verticalRadioButton.properties.checkboxType = .normal horizontalRadioButton.properties.checkboxType = .selected } verticalRadioButton.reloadData() horizontalRadioButton.reloadData() } else if (inputView == heightInput) { let fValue = heightInput.properties.text.stringToCGFloat() if fValue > widthInput.properties.text.stringToCGFloat() { verticalRadioButton.properties.checkboxType = .normal horizontalRadioButton.properties.checkboxType = .selected } else { verticalRadioButton.properties.checkboxType = .selected horizontalRadioButton.properties.checkboxType = .normal } verticalRadioButton.reloadData() horizontalRadioButton.reloadData() } } }