// // KMBatesPropertyController.swift // PDF Reader Pro // // Created by Niehaoyu on 2024/11/8. // import Cocoa import KMComponentLibrary @objc protocol KMBatesPropertyControllerDelegate: AnyObject { //水印数据有更新 @objc optional func batesPropertyControllerDidUpdate(_ controller: KMBatesPropertyController) //切换到模板界面 @objc optional func batesPropertyControllerDidChangetoTemplate(_ controller: KMBatesPropertyController) //成功保存到模板 @objc optional func batesPropertyControllerSaveTemplateSuccess(_ controller: KMBatesPropertyController, _ data: KMBatesModel) //取消修改模板信息 @objc optional func batesPropertyControllerCancelTemplateEdit(_ controller: KMBatesPropertyController) @objc optional func batesPropertyControllerFinishTemplateEdit(_ controller: KMBatesPropertyController) } class KMBatesPropertyController: NSViewController { @IBOutlet var contendView: NSView! @IBOutlet var titleLabel: NSTextField! @IBOutlet var templateButton: ComponentButton! @IBOutlet var leftTopButton: ComponentButton! //Font @IBOutlet var fontBGView: NSView! @IBOutlet var fontLabel: NSTextField! @IBOutlet var fontNameSelect: ComponentSelect! @IBOutlet var fontSizeSelect: ComponentSelect! @IBOutlet var fontColorView: ComponentCColorCustom! //Margin @IBOutlet var marginBGView: NSView! @IBOutlet var marginLabel: NSTextField! @IBOutlet var marginLeftInput: ComponentInputNumber! @IBOutlet var marginTopInput: ComponentInputNumber! @IBOutlet var marginRightInput: ComponentInputNumber! @IBOutlet var marginBottomInput: ComponentInputNumber! //Display @IBOutlet var displayBGView: NSView! @IBOutlet var displayLabel: NSTextField! @IBOutlet var prefixLabel: NSTextField! @IBOutlet var prefixInput: ComponentInput! @IBOutlet var suffixLabel: NSTextField! @IBOutlet var suffixInput: ComponentInput! @IBOutlet var digitsLabel: NSTextField! @IBOutlet var digitsInputNumber: ComponentInputNumber! @IBOutlet var startPageLabel: NSTextField! @IBOutlet var startPageSelect: ComponentSelect! //Layout&Content @IBOutlet var layoutBGView: NSView! @IBOutlet var layoutLabel: NSTextField! @IBOutlet var layoutInsertButton: ComponentButton! @IBOutlet var layoutPosition: ComponentCPosition! @IBOutlet var layoutTextarea: ComponentTextarea! //Save @IBOutlet var saveTemplateBGView: NSView! @IBOutlet var saveButton: ComponentButton! var groupView: ComponentGroup! private var familyNames = CPDFFont.familyNames var positionSelRow: Int = 1 var positionSelColumn: Int = 0 var batesModel: KMBatesModel = KMBatesModel() var totalPDFCount: Int = 1 var originalDataDict: Dictionary? var editSubType: KMPDFEditSubModeType = .none weak open var delegate: KMBatesPropertyControllerDelegate? override func viewDidLoad() { super.viewDidLoad() // Do view setup here. setupProperty() } func setupProperty() { contendView.wantsLayer = true contendView.layer?.backgroundColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle").cgColor titleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-bold") titleLabel.stringValue = KMLocalizedString("Add Bates Numbers") templateButton.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, onlyIcon: true, icon: NSImage(named: "icon_wm_template"), keepPressState: false) templateButton.setTarget(self, action: #selector(componentButtonClicked(_:))) leftTopButton.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, onlyIcon: true, icon: NSImage(named: "watermark_arrowLeft"), keepPressState: false) leftTopButton.setTarget(self, action: #selector(leftTopButtonClicked(_:))) //Font fontLabel.stringValue = KMLocalizedString("Font") fontLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") fontLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") fontNameSelect.properties = ComponentSelectProperties(size: .s, state: .normal, text: "") var menuItemArr: [ComponentMenuitemProperty] = [] for string in familyNames { let item = ComponentMenuitemProperty(type: .normal, text: string, identifier: string) menuItemArr.append(item) } fontNameSelect.updateMenuItemsArr(menuItemArr) fontNameSelect.delegate = self fontSizeSelect.properties = ComponentSelectProperties(size: .s, state: .normal, creatable: true, text: "12 pt", regexString: "0123456789 pt") if true { var sizeItemArr: [ComponentMenuitemProperty] = [] for string in KMHeaderFooterManager.getFontSize() { let item = ComponentMenuitemProperty(type: .normal, text: string, identifier: string) sizeItemArr.append(item) } fontSizeSelect.updateMenuItemsArr(sizeItemArr) } fontSizeSelect.delegate = self fontColorView.properties = ComponentCColorProperty(colorType: .colorPanel, state: .normal, isCustom: true, color: NSColor.black) //Margin marginLabel.stringValue = KMLocalizedString("Margin (mm)") marginLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") marginLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") marginLeftInput.properties = ComponentInputNumberProperty(alignment: .left, size: .s, minSize: 0, maxSize: 1000, text: "0") marginLeftInput.delegate = self marginTopInput.properties = ComponentInputNumberProperty(alignment: .left, size: .s, minSize: 0, maxSize: 1000, text: "0") marginTopInput.delegate = self marginRightInput.properties = ComponentInputNumberProperty(alignment: .left, size: .s, minSize: 0, maxSize: 1000, text: "0") marginRightInput.delegate = self marginBottomInput.properties = ComponentInputNumberProperty(alignment: .left, size: .s, minSize: 0, maxSize: 1000, text: "0") marginBottomInput.delegate = self //Display displayLabel.stringValue = KMLocalizedString("Display") displayLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") displayLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") prefixLabel.stringValue = KMLocalizedString("Prefix: ") prefixLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-nor") prefixLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular") prefixInput.properties = ComponentInputProperty(size: .s, text: "") prefixInput.delegate = self suffixLabel.stringValue = KMLocalizedString("Suffix: ") suffixLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-nor") suffixLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular") suffixInput.properties = ComponentInputProperty(size: .s, text: "") suffixInput.delegate = self digitsLabel.stringValue = KMLocalizedString("Numbers of Digits: ") digitsLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-nor") digitsLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular") digitsInputNumber.properties = ComponentInputNumberProperty(alignment: .left, size: .s, minSize: 0, maxSize: 99, valueType: .intType) digitsInputNumber.delegate = self startPageLabel.stringValue = KMLocalizedString("Start Page:") startPageLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-field/colorText-filled-nor") startPageLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular") startPageSelect.properties = ComponentSelectProperties(size: .s, state: .normal, creatable: false, text: "1") startPageSelect.delegate = self //Layout&Content layoutLabel.stringValue = KMLocalizedString("Layout & Content") layoutLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") layoutLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") layoutInsertButton.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, onlyIcon: true, icon: NSImage(named: "watermark_template_add"), keepPressState: false) layoutInsertButton.setTarget(self, action: #selector(componentButtonClicked(_:))) layoutPosition.properties = ComponentCPositionProperty(rowCount: 2, columnCount: 3, dash: true) layoutPosition.delegate = self layoutTextarea.properties = ComponentTextareaProperty(totalCount: -1) layoutTextarea.delegate = self //Save saveTemplateBGView.wantsLayer = true saveTemplateBGView.layer?.backgroundColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle").cgColor saveButton.properties = ComponentButtonProperty(type: .default_tertiary, size: .m, showLeftIcon: true, buttonText: KMLocalizedString("Save as Template"), icon: NSImage(named: "icon_wm_template_save"), keepPressState: false) saveButton.setTarget(self, action: #selector(componentButtonClicked(_:))) } func clearData() { positionSelRow = 1 positionSelColumn = 0 totalPDFCount = 1 } func reloadData() { titleLabel.stringValue = KMLocalizedString("Add Bates") leftTopButton.isHidden = true saveTemplateBGView.isHidden = false templateButton.properties.icon = NSImage(named: "icon_wm_template") if editSubType == .edit { titleLabel.stringValue = KMLocalizedString("Edit Bates") leftTopButton.isHidden = false saveTemplateBGView.isHidden = true templateButton.properties.icon = NSImage(named: "edit_save") } templateButton.reloadData() //Font if let index = familyNames.firstIndex(of: batesModel.fontName){ fontNameSelect.selectItemAtIndex(index) } fontNameSelect.properties.text = batesModel.fontName fontNameSelect.reloadData() let fontSizeStr = String(format: "%.0f", batesModel.fontsize) if let index = KMHeaderFooterManager.getFontSize().firstIndex(of: fontSizeStr) { fontSizeSelect.selectItemAtIndex(index) } fontSizeSelect.properties.text = String(format: "%.0f", batesModel.fontsize) + " pt" fontSizeSelect.reloadData() fontColorView.properties?.color = batesModel.color fontColorView.reloadData() //Margin marginLeftInput.properties.text = String(format: "%d", batesModel.leftMargin) marginLeftInput.reloadData() marginTopInput.properties.text = String(format: "%d", batesModel.topMargin) marginTopInput.reloadData() marginRightInput.properties.text = String(format: "%d", batesModel.rightMargin) marginRightInput.reloadData() marginBottomInput.properties.text = String(format: "%d", batesModel.bottomMargin) marginBottomInput.reloadData() //Display prefixInput.properties.text = batesModel.prefixString suffixInput.properties.text = batesModel.suffixString digitsInputNumber.properties.text = String(format: "%d", batesModel.digits) if true { var sizeItemArr: [ComponentMenuitemProperty] = [] var indexArr: [String] = [] for index in 0...totalPDFCount { indexArr.append(String(format: "%ld", index)) } for string in indexArr { let item = ComponentMenuitemProperty(type: .normal, text: string, identifier: string) sizeItemArr.append(item) } startPageSelect.updateMenuItemsArr(sizeItemArr) } if let index = KMHeaderFooterManager.getPageFormats().firstIndex(of: batesModel.startString) { startPageSelect.selectItemAtIndex(index) } startPageSelect.properties.text = batesModel.startString startPageSelect.reloadData() //Layout layoutPosition.properties.selRow = positionSelRow layoutPosition.properties.selColumn = positionSelColumn layoutPosition.reloadData() layoutTextarea.properties.text = "" layoutTextarea.reloadData() updateTextAreaText() //Save if batesModel.topLeftString.count == 0 && batesModel.topCenterString.count == 0 && batesModel.topRightString.count == 0 && batesModel.bottomLeftString.count == 0 && batesModel.bottomCenterString.count == 0 && batesModel.bottomRightString.count == 0 { saveButton.properties.isDisabled = true } else { saveButton.properties.isDisabled = false } saveButton.reloadData() } func updateTextAreaText() { if positionSelRow == 0 && positionSelColumn == 0 { //左下角 layoutTextarea.properties.text = batesModel.bottomLeftString } else if positionSelRow == 0 && positionSelColumn == 1 { layoutTextarea.properties.text = batesModel.bottomCenterString } else if positionSelRow == 0 && positionSelColumn == 2 { layoutTextarea.properties.text = batesModel.bottomRightString } else if positionSelRow == 1 && positionSelColumn == 0 { layoutTextarea.properties.text = batesModel.topLeftString } else if positionSelRow == 1 && positionSelColumn == 1 { layoutTextarea.properties.text = batesModel.topCenterString } else if positionSelRow == 1 && positionSelColumn == 2 { layoutTextarea.properties.text = batesModel.topRightString } layoutTextarea.reloadData() layoutPosition.setString(batesModel.bottomLeftString, to: 0, 0) layoutPosition.setString(batesModel.bottomCenterString, to: 0, 1) layoutPosition.setString(batesModel.bottomRightString, to: 0, 2) layoutPosition.setString(batesModel.topLeftString, to: 1, 0) layoutPosition.setString(batesModel.topCenterString, to: 1, 1) layoutPosition.setString(batesModel.topRightString, to: 1, 2) } //MARK: - Action @objc func leftTopButtonClicked(_ sender: ComponentButton) { if sender == leftTopButton { var didChanged = false if let dict = self.originalDataDict { didChanged = KMBatesManager.compareIsChangedModel(batesModel, withDict: dict as NSDictionary) } if didChanged { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("Save template changes?") alert.informativeText = KMLocalizedString("Cancel and they will not be saved.") alert.addButton(withTitle: KMLocalizedString("Save")) alert.addButton(withTitle: KMLocalizedString("Cancel")) alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in if response == NSApplication.ModalResponse.alertFirstButtonReturn { let _ = KMBatesManager.defaultManager.updateTemplate(self.batesModel) self.delegate?.batesPropertyControllerFinishTemplateEdit?(self) } else { if let dict = self.originalDataDict { KMBatesManager.defaultManager.updateModel(self.batesModel, with: dict as NSDictionary) let _ = KMBatesManager.defaultManager.updateTemplate(self.batesModel) } self.delegate?.batesPropertyControllerCancelTemplateEdit?(self) } } } else { delegate?.batesPropertyControllerCancelTemplateEdit?(self) } } } @objc func componentButtonClicked(_ sender: ComponentButton) { if sender == templateButton { delegate?.batesPropertyControllerDidChangetoTemplate?(self) } else if sender == layoutInsertButton { var menuItemArr: [ComponentMenuitemProperty] = [] let items: [(String, String)] = [("Insert Bates", "InsertBatesKey")] for (i, value) in items { let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: KMLocalizedString(i), identifier: value) menuItemArr.append(properties_Menuitem) } if groupView == nil { groupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) } groupView.groupDelegate = self groupView?.frame = CGRectMake(0, 0, 160, 44) groupView.updateGroupInfo(menuItemArr) if let point: CGPoint = sender.superview?.convert(sender.frame.origin, to: self.view.window?.contentView) { groupView.showWithPoint(CGPoint(x: point.x, y: point.y - CGRectGetHeight(groupView.frame)-4), relativeTo: self.view) } } else if sender == saveButton { batesModel.prefixString = prefixInput.properties.text batesModel.suffixString = suffixInput.properties.text let saveWindow: KMWatermarkSaveWindow = KMWatermarkSaveWindow(windowNibName: "KMWatermarkSaveWindow") saveWindow.nameValue = KMBatesManager.defaultManager.fetchBatesAvailableName() saveWindow.saveHandler = {[weak self] string in guard let weakSelf = self else { return } DispatchQueue.main.async { weakSelf.batesModel.name = string ?? "" if KMBatesManager.defaultManager.addTemplate(weakSelf.batesModel){ weakSelf.delegate?.batesPropertyControllerSaveTemplateSuccess?(weakSelf, weakSelf.batesModel) } } } saveWindow.own_beginSheetModal(for: view.window) { string in } } } //MARK: - Mouse override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) view.window?.makeFirstResponder(nil) } } //MARK: - ComponentInputNumberDelegate extension KMBatesPropertyController: ComponentInputNumberDelegate { func componentInputNumberDidValueChanged(inputNumber: ComponentInputNumber?) { if inputNumber == marginLeftInput { if let text = inputNumber?.properties.text { batesModel.leftMargin = Int(text) ?? 30 } } else if inputNumber == marginTopInput { if let text = inputNumber?.properties.text { batesModel.topMargin = Int(text) ?? 30 } } else if inputNumber == marginRightInput { if let text = inputNumber?.properties.text { batesModel.rightMargin = Int(text) ?? 30 } } else if inputNumber == marginBottomInput { if let text = inputNumber?.properties.text { batesModel.bottomMargin = Int(text) ?? 30 } } else if inputNumber == digitsInputNumber { if let text = inputNumber?.properties.text { batesModel.digits = Int(text) ?? 1 } } reloadData() delegate?.batesPropertyControllerDidUpdate?(self) } } //MARK: - ComponentInputDelegate extension KMBatesPropertyController: ComponentInputDelegate { } //MARK: - ComponentSelectDelegate extension KMBatesPropertyController: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { if view == fontNameSelect { batesModel.fontName = menuItemProperty?.text ?? "" } else if view == fontSizeSelect { if let text = menuItemProperty?.text { let result = text.stringByDeleteCharString(" pt") batesModel.fontsize = result.stringToCGFloat() } } else if view == startPageSelect { if let text = menuItemProperty?.text { batesModel.startString = text } } reloadData() delegate?.batesPropertyControllerDidUpdate?(self) } } //MARK: - ComponentGroupDelegate extension KMBatesPropertyController: ComponentGroupDelegate { func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) { if menuItemProperty?.identifier == "InsertBatesKey" { guard let digitsText = digitsInputNumber.properties.text else { return } guard let startPageText = startPageSelect.properties.text else { return } batesModel.digits = Int(digitsText) ?? 1 var tString = "<<#\((digitsText))#\(startPageText)" if !self.prefixInput.properties.text.isEmpty { tString += "#\(self.prefixInput.properties.text)" } else if self.prefixInput.properties.text.isEmpty && !self.suffixInput.properties.text.isEmpty { tString += "#" } if !self.suffixInput.properties.text.isEmpty { tString += "#\(self.suffixInput.properties.text)" } tString += ">>" if positionSelRow == 0 && positionSelColumn == 0 { //左下角 batesModel.bottomLeftString = batesModel.bottomLeftString + tString } else if positionSelRow == 0 && positionSelColumn == 1 { batesModel.bottomCenterString = batesModel.bottomCenterString + tString } else if positionSelRow == 0 && positionSelColumn == 2 { batesModel.bottomRightString = batesModel.bottomRightString + tString } else if positionSelRow == 1 && positionSelColumn == 0 { batesModel.topLeftString = batesModel.topLeftString + tString } else if positionSelRow == 1 && positionSelColumn == 1 { batesModel.topCenterString = batesModel.topCenterString + tString } else if positionSelRow == 1 && positionSelColumn == 2 { batesModel.topRightString = batesModel.topRightString + tString } } reloadData() delegate?.batesPropertyControllerDidUpdate?(self) } } //MARK: - ComponentCPositionDelegate extension KMBatesPropertyController: ComponentCPositionDelegate { func componentCPositionDidChoose(_ view: NSView, _ row: Int, _ column: Int) { if view == layoutPosition { view.window?.makeFirstResponder(nil) positionSelRow = row positionSelColumn = column reloadData() delegate?.batesPropertyControllerDidUpdate?(self) } } } //MARK: - ComponentTextareaDelegate extension KMBatesPropertyController: ComponentTextareaDelegate { func componentTextareaTextDidChange(_ view: ComponentTextarea) { if positionSelRow == 0 && positionSelColumn == 0 { //左下角 batesModel.bottomLeftString = layoutTextarea.properties.text } else if positionSelRow == 0 && positionSelColumn == 1 { batesModel.bottomCenterString = layoutTextarea.properties.text } else if positionSelRow == 0 && positionSelColumn == 2 { batesModel.bottomRightString = layoutTextarea.properties.text } else if positionSelRow == 1 && positionSelColumn == 0 { batesModel.topLeftString = layoutTextarea.properties.text } else if positionSelRow == 1 && positionSelColumn == 1 { batesModel.topCenterString = layoutTextarea.properties.text } else if positionSelRow == 1 && positionSelColumn == 2 { batesModel.topRightString = layoutTextarea.properties.text } reloadData() delegate?.batesPropertyControllerDidUpdate?(self) } func componentTextareaTextDidEndEditing(_ view: ComponentTextarea) { } }