// // DSignatureFileListViewController.swift // PDF Reader Pro Edition // // Created by Niehaoyu on 2023/9/27. // import Cocoa @objcMembers class DSignatureFileListViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource, NSMenuDelegate { @IBOutlet weak var contendView: NSView! @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var subTitleLabel: NSTextField! @IBOutlet weak var tableView: NSTableView! @IBOutlet weak var updateButton: NSButton! @IBOutlet weak var closeButton: NSButton! @IBOutlet weak var createButton: NSButton! @IBOutlet weak var cancelButton: NSButton! @IBOutlet weak var continueButton: NSButton! @IBOutlet weak var progressMaskView: NSView! @IBOutlet weak var progressIndicator: NSProgressIndicator! var _isFileList: Bool = false var currentModel: KMDSignatureModel? private var signatureArrays: NSArray? var actionBlock: ((_ fileListVC: DSignatureFileListViewController, _ type: DSignatureActionType)->Void)? var viewCertDetailBlock: ((_ fileListVC: DSignatureFileListViewController, _ certificate: CPDFSignatureCertificate, _ isDigitalFile: Bool)->Void)? deinit { NotificationCenter.default.removeObserver(self) } override func viewWillAppear() { super.viewWillAppear() self.reloadData() } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. self.tableView.delegate = self self.tableView.dataSource = self self.tableView.backgroundColor = NSColor.clear self.tableView.allowsEmptySelection = false self.localizedLanguage() self.progressMaskView.isHidden = true let menu = NSMenu.init() menu.delegate = self; self.tableView.menu = menu NotificationCenter.default.addObserver(self, selector: #selector(signatureDidStartLoadNoti), name: NSNotification.Name(rawValue: DSignatureDidStartLoadNotification), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(signatureDidFinishLoadNoti), name: NSNotification.Name(rawValue: DSignatureDidFinishLoadNotification), object: nil) } //MARK: Setter var isFileList: Bool { set { _isFileList = newValue; if(_isFileList) { self.titleLabel.stringValue = NSLocalizedString("Add digital IDs from a file:", comment: "") self.subTitleLabel.stringValue = NSLocalizedString("The following digital ID will be added to your list of digital ID that you can use for digitally signing:", comment: "") self.cancelButton.title = NSLocalizedString("Previous Step", comment: "") self.createButton.isHidden = true self.updateButton.isHidden = true }else { self.titleLabel.stringValue = NSLocalizedString("Sign with a Digital ID", comment: "") self.subTitleLabel.stringValue = NSLocalizedString("Choose the digital ID that you want to use for signing:", comment: "") self.cancelButton.title = NSLocalizedString("Cancel", comment: "") self.createButton.isHidden = false self.updateButton.isHidden = false } self.reloadData() } get { return _isFileList; } } //MARK: Public Method func localizedLanguage() { self.titleLabel.stringValue = NSLocalizedString("Sign with a Digital ID", comment: "") self.subTitleLabel.stringValue = NSLocalizedString("Choose the digital ID that you want to use for signing:", comment: "") self.createButton.title = NSLocalizedString("Configure New Digital ID", comment: "") self.cancelButton.title = NSLocalizedString("Cancel", comment: "") self.updateButton.isHidden = false self.titleLabel.textColor = NSColor.labelColor self.subTitleLabel.textColor = NSColor.labelColor self.continueButton.title = NSLocalizedString("Continue", comment: "") self.updateButton.title = NSLocalizedString("Refresh", comment: "") } func reloadData() { self.signatureArrays = KMDSignatureManager.default().signatures self.tableView.reloadData() if let cnt = self.signatureArrays?.count, cnt > 0 { self.tableView.selectRowIndexes([0], byExtendingSelection: true) self.currentModel = self.signatureArrays?.firstObject as? KMDSignatureModel self.continueButton.isEnabled = true } else { self.continueButton.isEnabled = false } } func refreshSelectedState() { let selectRow = self.tableView.selectedRow for index in 0...self.tableView.numberOfRows-1 { let rowView = self.tableView.rowView(atRow: index, makeIfNecessary: true) let cellView = rowView?.view(atColumn: 0) as? DSignatureFileListCellView if (index == selectRow) { cellView?.radioBtn.state = .on } else { cellView?.radioBtn.state = .off } } } func menuItemClick_Delete() { let row = self.tableView.clickedRow let cnt = self.signatureArrays?.count ?? 0 if row > -1 && row < cnt { let model = self.signatureArrays?[row] as? KMDSignatureModel let isFormKeyChain = model?.isFormKeyChain ?? true if self.isFileList == false && isFormKeyChain == false { KMDSignatureManager.default().removeSignatureCertPath(model?.filePath ?? "") } self.reloadData() } } //MARK: IBAction @IBAction func closeAction(_ sender: Any) { guard let callBack = self.actionBlock else { return } callBack(self, .cancel) } @IBAction func refreshAction(_ sender: Any) { DispatchQueue.main.async { self.progressIndicator.startAnimation(nil) self.progressMaskView.isHidden = false DispatchQueue.global().async { KMDSignatureManager.default().loadAllKeyChainCertificates() DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { self.progressIndicator.stopAnimation(nil) self.progressMaskView.isHidden = true } } } } @IBAction func configNewAction(_ sender: Any) { guard let callBack = self.actionBlock else { return } callBack(self, .createNewDsign) } @IBAction func cancelAction(_ sender: Any) { guard let callBack = self.actionBlock else { return } callBack(self, .cancel) } @IBAction func continueAction(_ sender: Any) { guard let callBack = self.actionBlock else { return } callBack(self, .confirm) } //MARK: NSTableViewDelegate func numberOfRows(in tableView: NSTableView) -> Int { if self.isFileList { return 1 } return self.signatureArrays?.count ?? 0 } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { return 66.0 } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { let row = KMCustomTableRowView.init() return row } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let cellView = DSignatureFileListCellView() cellView.itemIndex = row let cnt = self.signatureArrays?.count ?? 0 if (cnt > row) { let model = self.signatureArrays?[row] as? KMDSignatureModel cellView.signModel = model } if (cellView.signModel == self.currentModel) { cellView.radioBtn.state = .on } else { cellView.radioBtn.state = .off } weak var weakSelf = self cellView.radioActionHandle = {_ in if weakSelf!.tableView.numberOfRows > cellView.itemIndex { weakSelf?.tableView.selectRowIndexes([cellView.itemIndex], byExtendingSelection: false) } weakSelf?.currentModel = weakSelf!.signatureArrays?[weakSelf!.tableView.selectedRow] as? KMDSignatureModel weakSelf?.refreshSelectedState() } cellView.viewDetailBlock = {cellView in var filePath: NSString? var save: Bool = true var password: String = "" if cellView.signModel?.isFormKeyChain == true { let folderPath = kDSignatureFolderPath if FileManager.default.fileExists(atPath: folderPath) == false { let success: ()? = try?FileManager.default.createDirectory(atPath: folderPath, withIntermediateDirectories: false) if success == nil { save = false } } filePath = kDSignatureFolderPath.appending("/KMDSignatures.p12") as NSString save = KMDSignatureManager.exportKeyChain(withP12FilePath: filePath as String?, signatureModel: cellView.signModel, passWord: password as String?) cellView.signModel?.filePath = filePath as? String } else { if cellView.signModel?.password != nil { password = (cellView.signModel?.password) ?? "" } if cellView.signModel?.filePath != nil { filePath = cellView.signModel?.filePath as? NSString } } if save { var certificate: CPDFSignatureCertificate? certificate = CPDFSignatureCertificate(pkcs12Path: filePath as String?, password: password as String?) if certificate != nil { guard let callBack = self.viewCertDetailBlock else { return } callBack(self, certificate!, !(cellView.signModel?.isFormKeyChain ?? false)) } } else { let alert = NSAlert.init() alert.messageText = NSLocalizedString("Failed to get certificate details!", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } } return cellView } func tableViewSelectionDidChange(_ notification: Notification) { let cnt = self.signatureArrays?.count ?? 0 if (cnt > self.tableView.selectedRow) { self.currentModel = self.signatureArrays?[self.tableView.selectedRow] as? KMDSignatureModel self.refreshSelectedState() } } //MARK: NSMenuDelegate func menuNeedsUpdate(_ menu: NSMenu) { menu.removeAllItems() let row = self.tableView.clickedRow let cnt = self.signatureArrays?.count ?? 0 if row > -1 && row < cnt { let model = self.signatureArrays?[row] as? KMDSignatureModel let isFormKeyChain = model?.isFormKeyChain ?? true if self.isFileList == false && isFormKeyChain == false { menu.addItem(withTitle: NSLocalizedString("Delete", comment: ""), action: #selector(menuItemClick_Delete), keyEquivalent: "") } } } //MARK: Noti func signatureDidStartLoadNoti() { DispatchQueue.main.async { self.progressIndicator.startAnimation(nil) self.progressMaskView.isHidden = false } } func signatureDidFinishLoadNoti() { DispatchQueue.main.async { self.progressIndicator.stopAnimation(nil) self.progressMaskView.isHidden = true self.reloadData() } } }