KMSignatureViewController.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. //
  2. // KMSignatureViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lxy on 2022/11/17.
  6. //
  7. import Cocoa
  8. @objc protocol KMSignatureViewControllerDelegate {
  9. @objc optional func removeDocumentSignatues(signatures:[CPDFSignature])
  10. }
  11. class KMSignatureViewController: NSViewController {
  12. @IBOutlet weak var sigOutlineView: KMOutlineView!
  13. @IBOutlet weak var deleteButton: NSButton!
  14. @IBOutlet weak var validationButton: NSButton!
  15. @IBOutlet weak var tipTextField: NSTextField!
  16. @IBOutlet weak var emptyLabel: NSTextField!
  17. @IBOutlet weak var emptyView: NSView!
  18. var listView : CPDFListView!
  19. var signatures : [CPDFSignature] = []
  20. open weak var delete: KMSignatureViewControllerDelegate?
  21. override func viewDidLoad() {
  22. super.viewDidLoad()
  23. // Do view setup here.
  24. self.view.wantsLayer = true
  25. self.view.layer?.backgroundColor = NSColor.yellow.cgColor
  26. self.tipTextField.stringValue = NSLocalizedString("Digitally Sign", comment: "");
  27. self.deleteButton.toolTip = NSLocalizedString("Delete", comment: "");
  28. self.validationButton.toolTip = NSLocalizedString("Validate All Signatures", comment: "");
  29. self.emptyLabel.stringValue = NSLocalizedString("No digital signature was added", comment: "");
  30. let signatures : [CPDFSignature] = self.listView.document.signatures() ?? []
  31. var mSignatures : [CPDFSignature] = []
  32. for sign in signatures {
  33. if sign.signers.count > 0 {
  34. mSignatures.append(sign)
  35. }
  36. }
  37. self.signatures = mSignatures
  38. self.sigOutlineView.delegate = self
  39. self.sigOutlineView.dataSource = self
  40. let menu = NSMenu()
  41. menu.delegate = self
  42. self.sigOutlineView.menu = menu
  43. self.sigOutlineView.doubleAction = #selector(tableViewAction)
  44. }
  45. //MAAK: Accessors
  46. public func reloadData() {
  47. self.sigOutlineView.reloadData()
  48. }
  49. private func outlineForItem(item:Any) -> [Any] {
  50. var itemChildren : [Any] = []
  51. if (item is String) && ((item as! String) == "") {
  52. if self.signatures.count > 0 {
  53. let lastSignates : CPDFSignature = self.signatures.last ?? CPDFSignature()
  54. if (lastSignates.permissions > 0) {
  55. var mutableArr : [Any] = self.signatures
  56. mutableArr.append(" \(NSLocalizedString("Already locked by", comment: ""))\(String(describing: lastSignates.fieldName))")
  57. itemChildren = mutableArr
  58. } else {
  59. itemChildren = self.signatures
  60. }
  61. } else {
  62. itemChildren = self.signatures
  63. }
  64. } else if (item is CPDFSignature) {
  65. itemChildren = (item as! CPDFSignature).numberOfChildren(document: self.listView.document)
  66. } else if (item is [String:Any]) {
  67. let key = (item as! [String:Any]).keys.first ?? ""
  68. itemChildren = (item as! [String:Any])[key] as! [Any]
  69. }
  70. return itemChildren
  71. }
  72. @IBAction func deleteButtonAction(_ sender: Any) {
  73. let alert = NSAlert()
  74. alert.alertStyle = .critical
  75. alert.messageText = NSLocalizedString("Are you sure you want to clear all signature fields in this document?", comment: "")
  76. alert.informativeText = NSLocalizedString("You cannot undo this operation.", comment: "")
  77. alert.addButton(withTitle: NSLocalizedString("Yes", comment: ""))
  78. alert.addButton(withTitle: NSLocalizedString("No", comment: ""))
  79. alert.beginSheetModal(for: self.view.window!, completionHandler: { result in
  80. if result != .OK {
  81. }
  82. })
  83. }
  84. @IBAction func validationButtonAction(_ sender: Any) {
  85. }
  86. @IBAction func jumpItemAction(item: NSMenuItem) {
  87. let indexSet : NSIndexSet = item.representedObject as! NSIndexSet
  88. let outlineItem = self.sigOutlineView.item(atRow: indexSet.firstIndex)
  89. if outlineItem is CPDFSignature {
  90. let index: Int = Int((outlineItem as! CPDFSignature).pageIndex(with: listView.document))
  91. if self.listView.currentPageIndex != index {
  92. self.listView.go(toPageIndex: index, animated: true)
  93. }
  94. }
  95. }
  96. @IBAction func removeItemAction(item:NSMenuItem) {
  97. let index : NSIndexSet = item.representedObject as! NSIndexSet
  98. let outlineItem = self.sigOutlineView.item(atRow: index.firstIndex)
  99. if outlineItem is CPDFSignature {
  100. let index: Int = Int((outlineItem as! CPDFSignature).pageIndex(with: listView.document))
  101. if self.listView.currentPageIndex != index {
  102. self.delete?.removeDocumentSignatues?(signatures: [outlineItem as! CPDFSignature])
  103. }
  104. }
  105. }
  106. @IBAction func validateItemAction(item:NSMenuItem) {
  107. let index : NSIndexSet = item.representedObject as! NSIndexSet
  108. let outlineItem = self.sigOutlineView.item(atRow: index.firstIndex)
  109. if outlineItem is CPDFSignature {
  110. }
  111. }
  112. @IBAction func showItemAction(item:NSMenuItem) {
  113. let index : NSIndexSet = item.representedObject as! NSIndexSet
  114. let outlineItem = self.sigOutlineView.item(atRow: index.firstIndex)
  115. if outlineItem is CPDFSignature {
  116. let index: Int = Int((outlineItem as! CPDFSignature).pageIndex(with: listView.document))
  117. if self.listView.currentPageIndex != index {
  118. }
  119. }
  120. }
  121. @IBAction func tableViewAction(sender:Any) {
  122. let row = self.sigOutlineView.clickedRow
  123. if (row >= 0) && (row < self.signatures.count) {
  124. let outlineItem : CPDFSignature = self.sigOutlineView.item(atRow: row) as! CPDFSignature
  125. let index: Int = Int((outlineItem).pageIndex(with: listView.document))
  126. if self.listView.currentPageIndex != index {
  127. if self.listView.currentPageIndex != index {
  128. self.listView.go(toPageIndex: index, animated: true)
  129. }
  130. }
  131. }
  132. }
  133. }
  134. extension KMSignatureViewController : NSOutlineViewDelegate,NSOutlineViewDataSource {
  135. func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
  136. var count = self.outlineForItem(item: item ?? "").count
  137. if case Optional<Any>.none = item {
  138. if count > 0 {
  139. self.emptyView.isHidden = true
  140. self.deleteButton.isEnabled = true
  141. self.validationButton.isEnabled = true
  142. } else {
  143. self.emptyView.isHidden = false
  144. self.deleteButton.isEnabled = false
  145. self.validationButton.isEnabled = false
  146. }
  147. } else if item is [String:Any] {
  148. count = 1
  149. }
  150. return count
  151. }
  152. func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
  153. return self.outlineForItem(item: item ?? "")[index]
  154. }
  155. func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
  156. return self.outlineForItem(item: item).count > 0
  157. }
  158. func outlineView(_ outlineView: NSOutlineView, shouldShowOutlineCellForItem item: Any) -> Bool {
  159. return true
  160. }
  161. func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
  162. let cell : KMSignatureCellView = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMSignatureCellView"), owner: self) as! KMSignatureCellView
  163. var contentString = ""
  164. if item is CPDFSignature {
  165. let signer : CPDFSigner = (item as! CPDFSignature).signers.first ?? CPDFSigner()
  166. contentString = "\(NSLocalizedString("Signature by", comment: ""))\(signer.timestampSignature.name ?? "")"
  167. if signer.isSignVerified && signer.isCertTrusted {
  168. cell.signatureImageView.image = NSImage(named: "KMImageNameSigntureVerifySuccess")
  169. } else if signer.isSignVerified && !signer.isCertTrusted {
  170. cell.signatureImageView.image = NSImage(named: "KMImageNameSigntureVerifySuccess")
  171. } else {
  172. cell.signatureImageView.image = NSImage(named: "KMImageNameSigntureVerifySuccess")
  173. }
  174. cell.signatureImageView.isHidden = false
  175. cell.leftOffset.constant = 36
  176. cell.contenLabel.font = NSFont.systemFont(ofSize: 13)
  177. } else if item is String {
  178. cell.signatureImageView.isHidden = true
  179. cell.leftOffset.constant = 4
  180. cell.contenLabel.font = NSFont.systemFont(ofSize: 12)
  181. contentString = item as! String
  182. } else if item is [String:Any] {
  183. cell.signatureImageView.isHidden = true
  184. cell.leftOffset.constant = 4
  185. cell.contenLabel.font = NSFont.systemFont(ofSize: 12)
  186. contentString = (item as! [String:Any]).keys.first ?? ""
  187. }
  188. cell.contenLabel.stringValue = contentString
  189. return cell
  190. }
  191. func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView? {
  192. let rowView = KMCustomTableRowView()
  193. return rowView
  194. }
  195. func outlineView(_ outlineView: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
  196. var contentString = ""
  197. var font = NSFont.systemFont(ofSize: 12)
  198. if item is CPDFSignature {
  199. let signer = (item as! CPDFSignature).signers.first
  200. contentString = "\(NSLocalizedString("Signature by", comment: ""))\(String(describing: signer?.timestampSignature.name))"
  201. font = NSFont.systemFont(ofSize: 13)
  202. } else if (item is String){
  203. contentString = item as! String
  204. } else if (item is [String : Any]) {
  205. contentString = (item as! [String:Any]).keys.first ?? ""
  206. }
  207. let paragraphStyle = NSMutableParagraphStyle()
  208. paragraphStyle.lineBreakMode = .byWordWrapping
  209. var attribute = [NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : paragraphStyle]
  210. let rect = NSString(string: contentString).boundingRect(with: NSSize(width: outlineView.frame.size.width-20, height:CGFloat(MAXFLOAT)),options: NSString.DrawingOptions(rawValue: 3), attributes: attribute).size
  211. if(rect.height < 40) {
  212. return 40
  213. } else {
  214. return rect.height
  215. }
  216. }
  217. func outlineView(_ outlineView: NSOutlineView, shouldSelect tableColumn: NSTableColumn?) -> Bool {
  218. return true
  219. }
  220. }
  221. //MARK: NSMenuDelegate
  222. extension KMSignatureViewController : NSMenuDelegate {
  223. func menuNeedsUpdate(_ menu: NSMenu) {
  224. menu.removeAllItems()
  225. let clickedRow = self.sigOutlineView.clickedRow
  226. let item = self.sigOutlineView.item(atRow: clickedRow)
  227. if clickedRow > 0 && (item is CPDFSignature) {
  228. var item = NSMenuItem()
  229. item = menu.addItem(withTitle: NSLocalizedString("Jump To The Signature Field", comment: ""), action: #selector(jumpItemAction), target: self)!
  230. item.representedObject = NSIndexSet(index: clickedRow)
  231. menu.addItem(NSMenuItem.separator())
  232. item = menu.addItem(withTitle: NSLocalizedString("Remove Signature", comment: ""), action: #selector(removeItemAction), target: self)!
  233. item.representedObject = NSIndexSet(index: clickedRow)
  234. item = menu.addItem(withTitle: NSLocalizedString("Remove Signature", comment: ""), action: #selector(validateItemAction), target: self)!
  235. item.representedObject = NSIndexSet(index: clickedRow)
  236. menu.addItem(NSMenuItem.separator())
  237. item = menu.addItem(withTitle: NSLocalizedString("Show Signature Properties…", comment: ""), action: #selector(showItemAction), target: self)!
  238. item.representedObject = NSIndexSet(index: clickedRow)
  239. }
  240. }
  241. }
  242. //MARK: CPDFSignature
  243. extension CPDFSignature {
  244. func numberOfChildren(document:CPDFDocument) -> [Any] {
  245. var datas : [Any] = []
  246. let signer = self.signers.first
  247. var validString = ""
  248. if signer?.isSignVerified != nil {
  249. validString = NSLocalizedString("Signature is valid", comment: "")
  250. } else {
  251. validString = NSLocalizedString("Signature is invalid", comment: "")
  252. }
  253. var certTrusted = ""
  254. if signer?.isCertTrusted != nil {
  255. certTrusted = NSLocalizedString("Signer's identity is valid", comment: "")
  256. } else {
  257. certTrusted = NSLocalizedString("Signer's identity is invalid", comment: "")
  258. }
  259. var timestampSigners = ""
  260. if signer?.timestampSignature.signers != nil {
  261. let tSign = signer?.timestampSignature.signers.first
  262. if tSign?.isSignVerified != nil && tSign?.isSignVerified != nil {
  263. timestampSigners = NSLocalizedString("The signature includes an embedded timestamp.", comment: "")
  264. } else {
  265. timestampSigners = NSLocalizedString("The signature includes an embedded timestamp but it could not be verified.", comment: "")
  266. }
  267. }
  268. var str3 = "\(validString)\n\n \(certTrusted)"
  269. if timestampSigners.lengthOfBytes(using: String.Encoding(rawValue: String.Encoding.utf16.rawValue)) > 0 {
  270. str3 = "\(str3)\n\n \(timestampSigners)"
  271. }
  272. datas.append(str3)
  273. var dic : [String:Any] = [:]
  274. let array = [NSLocalizedString("Certificate Details...", comment: ""),signer ?? CPDFSigner()] as [Any]
  275. dic[NSLocalizedString("Signature Details...", comment: "")] = array
  276. datas.append(dic)
  277. if signer?.timestampSignature.signers != nil && signer?.timestampSignature.signers.first?.authenDate != nil{
  278. var dateFormatter = DateFormatter()
  279. dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
  280. let strDate = dateFormatter.string(from: signer?.timestampSignature.signers.first?.authenDate ?? Date())
  281. datas.append("\(NSLocalizedString("Last Checked:", comment: ""))\(strDate)")
  282. } else {
  283. datas.append("\(NSLocalizedString("Last Checked:", comment: ""))\(NSLocalizedString("Never", comment: ""))")
  284. }
  285. let pageIndex = self.pageIndex(with: document)
  286. datas.append("\(NSLocalizedString("Field:", comment: ""))\(self.fieldName.description)\(NSLocalizedString("on Page", comment: ""))\(pageIndex+1)")
  287. return datas
  288. }
  289. }