KMPDFRedactViewController.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //
  2. // KMPDFRedactViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by tangchao on 2023/12/18.
  6. //
  7. import Cocoa
  8. class KMPDFRedactViewController: NSViewController {
  9. var scaleFactor: CGFloat = 0 {
  10. didSet {
  11. self.redactPdfView.scaleFactor = scaleFactor
  12. }
  13. }
  14. var callback: ((Bool, Int, Bool, URL?)->Void)?
  15. var titleBack: ((String)->Void)?
  16. @IBOutlet var redactPdfView: KMRedactPDFView!
  17. @IBOutlet weak var redactTipLabel: NSTextField!
  18. @IBOutlet weak var propertiesLabel: NSTextField!
  19. @IBOutlet weak var redactTextLabel: NSTextField!
  20. @IBOutlet weak var exitBox: KMBox!
  21. @IBOutlet weak var applyBox: KMBox!
  22. @IBOutlet weak var exitButton: NSButton!
  23. @IBOutlet weak var applyButton: NSButton!
  24. @IBOutlet weak var toolView: NSView!
  25. @IBOutlet weak var redactTextBox: NSBox!
  26. @IBOutlet weak var propertiesBox: NSBox!
  27. @IBOutlet weak var redactTextButton: KMCustomButton!
  28. @IBOutlet weak var propertiesButton: KMCustomButton!
  29. private var _url: URL?
  30. private var url: URL? {
  31. get {
  32. return self._url
  33. }
  34. }
  35. private var _password: String?
  36. private var _indicator: NSProgressIndicator?
  37. deinit {
  38. KMPrint("KMPDFRedactViewController deinit.")
  39. NotificationCenter.default.removeObserver(self)
  40. self.redactPdfView.delegate = nil
  41. }
  42. convenience init(url: URL, password: String?) {
  43. self.init()
  44. self._url = url
  45. self._password = password
  46. }
  47. override func loadView() {
  48. super.loadView()
  49. self.propertiesBox.wantsLayer = true
  50. self.redactTextBox.wantsLayer = true
  51. self.redactTextBox.fillColor = KMAppearance.Layout.w30Color()
  52. self.redactTextBox.layer?.cornerRadius = 6
  53. self.redactTextLabel.textColor = KMAppearance.Layout.w0Color()
  54. self.propertiesLabel.textColor = KMAppearance.Layout.w0Color()
  55. self.redactTextLabel.stringValue = KMLocalizedString("Redact Text", nil)
  56. self.propertiesLabel.stringValue = KMLocalizedString("Properties", nil)
  57. self.propertiesButton.mouseMoveCallback = { [weak self] mouseEntered in
  58. self?.propertiesBox.layer?.cornerRadius = 6
  59. if mouseEntered {
  60. self?.propertiesBox.fillColor = KMAppearance.Layout.w30Color()
  61. } else {
  62. self?.propertiesBox.fillColor = .clear
  63. }
  64. }
  65. // Do view setup here.
  66. self.redactTipLabel.stringValue = KMLocalizedString("You are under redact mode", nil)
  67. self.applyButton.title = KMLocalizedString("Apply", nil)
  68. self.exitButton.toolTip = KMLocalizedString("Exit", nil)
  69. self.exitBox.fillColor = .clear
  70. self.exitBox.borderColor = KMAppearance.Layout.w70Color()
  71. self.exitBox.borderWidth = 1.0
  72. self.exitButton.title = KMLocalizedString("Exit", nil)
  73. self.exitButton.setTitleColor(KMAppearance.Layout.w0Color())
  74. self.applyButton.setTitleColor(KMAppearance.Interactive.a0Color())
  75. self.applyButton.wantsLayer = true
  76. self.applyBox.downCallback = { [weak self] downEntered, mouseBox, event in
  77. if downEntered {
  78. self?.apply_button(nil)
  79. }
  80. }
  81. self.exitBox.downCallback = { [weak self] downEntered, mouseBox, event in
  82. if downEntered {
  83. self?.exit_button(nil)
  84. }
  85. }
  86. self.toolView.wantsLayer = true
  87. self.toolView.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor
  88. let document = CPDFDocument(url: self.url!)
  89. if let pwd = self._password, pwd.isEmpty == false {
  90. document?.unlock(withPassword: pwd)
  91. }
  92. self.redactPdfView.document = document
  93. // self.redactPdfView.scaleFactor = self.scaleFactor;
  94. self.redactPdfView.autoScales = true
  95. self.redactPdfView.delegate = self
  96. // self.redactPdfView.toolMode = .redactToolMode
  97. self.redactPdfView.operationType = .redact
  98. // [self.redactPdfView layoutDocumentView];
  99. let frame = NSMakeRect((self.redactPdfView.frame.size.width-32)/2.0, (self.redactPdfView.frame.size.height-32)/2.0, 32, 32)
  100. self._indicator = NSProgressIndicator(frame: frame)
  101. self._indicator?.autoresizingMask = [.minXMargin, .maxXMargin, .minYMargin, .maxYMargin]
  102. self._indicator?.style = .spinning
  103. self._indicator?.controlSize = .regular
  104. self._indicator?.isIndeterminate = true
  105. self._indicator?.startAnimation(nil)
  106. self.redactPdfView.addSubview(self._indicator!)
  107. self._indicator?.isHidden = true
  108. }
  109. override func viewDidLoad() {
  110. super.viewDidLoad()
  111. NotificationCenter.default.addObserver(self, selector: #selector(showCurrentRedactAnnotationProperties), name: KMRedactPDFView.showCurrentRedactAnnotationNotificationName, object: nil)
  112. NotificationCenter.default.addObserver(self, selector: #selector(apply), name: KMRedactPDFView.redactAnnotationApplyNotificationName, object: nil)
  113. NotificationCenter.default.addObserver(self, selector: #selector(across), name: KMRedactPDFView.redactAnnotationAcrossNotificationName, object: nil)
  114. }
  115. func setCurrentPageIndex(_ currentPageIndex: Int) {
  116. self.redactPdfView.go(toPageIndex: currentPageIndex, animated: false)
  117. }
  118. // MARK: - Button Actions
  119. @IBAction func showProperties_button(_ sender: AnyObject?) {
  120. let properties = KMRedactPropertiesWindowController()
  121. self.km_beginSheet(windowC: properties)
  122. properties.callback = { annotation in
  123. }
  124. }
  125. @IBAction func apply_button(_ sender: AnyObject?) {
  126. var isApply = false
  127. for i in 0 ..< self.redactPdfView.document.pageCount {
  128. let page = self.redactPdfView.document.page(at: i)
  129. for anno in page?.annotations ?? [] {
  130. if anno.isKind(of: CPDFRedactAnnotation.self) {
  131. isApply = true
  132. }
  133. }
  134. }
  135. if(self.redactPdfView.newAddAnnotation.count == 0 && !isApply) {
  136. return
  137. }
  138. let returnCode = KMAlertTool.runModelForMainThread_r(message: "", informative: KMLocalizedString("This will permanently remove the redacted information from this document. Once you save this document, you won’t be able to retrieve the redacted information.", nil), buttons: [KMLocalizedString("Apply", nil), KMLocalizedString("Cancel", nil)])
  139. if returnCode == .alertFirstButtonReturn {
  140. self.saveAsPath()
  141. }
  142. }
  143. @IBAction func exit_button(_ sender: AnyObject?) {
  144. guard let block = self.callback else {
  145. return
  146. }
  147. block(false, self.redactPdfView.currentPageIndex, false, nil)
  148. }
  149. func saveAsPath() {
  150. let saveAccessCtr = KMSavePanelAccessoryController()
  151. var fileName = self.redactPdfView.document.documentURL.deletingPathExtension().lastPathComponent
  152. fileName = String(format: "%@_%@.pdf", fileName, "Redact")
  153. let outputSavePanel = NSSavePanel()
  154. outputSavePanel.allowedFileTypes = ["pdf"]
  155. outputSavePanel.nameFieldStringValue = fileName
  156. outputSavePanel.accessoryView = saveAccessCtr.view
  157. outputSavePanel.beginSheetModal(for: NSApp.mainWindow!) { result in
  158. if result == .OK {
  159. self.redactPdfView.document.applyRedactions()
  160. self._indicator?.isHidden = false
  161. self._indicator?.startAnimation(nil)
  162. let savePDFPath = outputSavePanel.url!.path
  163. let isSuccess = self.redactPdfView.document.write(toFile: savePDFPath)
  164. if (isSuccess) {
  165. // [self.redactPdfView.newAddAnnotation removeAllObjects];
  166. if (saveAccessCtr.openAutomaticButton.state == .on) {
  167. NSDocumentController.shared.km_safe_openDocument(withContentsOf: outputSavePanel.url!, display: true) { _, _, _ in
  168. }
  169. } else {
  170. KMTools.viewFile(at: savePDFPath)
  171. }
  172. }
  173. self._indicator?.stopAnimation(nil)
  174. self._indicator?.isHidden = true
  175. guard let block = self.callback else {
  176. return
  177. }
  178. block(true, self.redactPdfView.currentPageIndex, false, outputSavePanel.url)
  179. }
  180. }
  181. }
  182. // MARK: - Button notice
  183. @objc func showCurrentRedactAnnotationProperties(_ notice: NSNotification) {
  184. guard let pdfview = notice.object as? KMRedactPDFView else {
  185. return
  186. }
  187. if(pdfview == self.redactPdfView) {
  188. let properties = KMRedactPropertiesWindowController()
  189. properties.readactAnnotation = self.redactPdfView.currentAnnotation
  190. // __block KMPDFRedactViewController *weak_self = self;
  191. self.km_beginSheet(windowC: properties)
  192. properties.callback = { [weak self] annotation in
  193. if let page = self?.redactPdfView.currentAnnotation?.page {
  194. if let anno = annotation {
  195. self?.redactPdfView.newAddAnnotation.append(anno)
  196. }
  197. self?.redactPdfView.setNeedsDisplayAnnotationViewFor(page)
  198. }
  199. }
  200. }
  201. }
  202. @objc func apply(_ notice: NSNotification) {
  203. guard let pdfview = notice.object as? KMRedactPDFView else {
  204. return
  205. }
  206. if(pdfview == self.redactPdfView) {
  207. self.apply_button(nil)
  208. }
  209. }
  210. @objc func across(_ notice: NSNotification) {
  211. guard let pdfview = notice.object as? KMRedactPDFView else {
  212. return
  213. }
  214. if(pdfview == self.redactPdfView) {
  215. let pagesWindowController = KMRedactSelectPagesWindowController(document: self.redactPdfView.document)
  216. self.km_beginSheet(windowC: pagesWindowController)
  217. pagesWindowController.callback = { [unowned self] pages in
  218. if pages.count > 0 {
  219. self.redactPdfView.acrossAddAnnotations(pages)
  220. }
  221. }
  222. }
  223. }
  224. }
  225. extension KMPDFRedactViewController: CPDFViewDelegate {
  226. func pdfViewCurrentPageDidChanged(_ pdfView: CPDFView!) {
  227. let fileName = pdfView.document.documentURL.deletingLastPathComponent().lastPathComponent
  228. let title = String(format: KMLocalizedString("%@ (page %ld / %ld)", "Window title format"), fileName, pdfView.currentPageIndex+1, pdfView.document.pageCount)
  229. if(self.titleBack != nil) {
  230. self.titleBack!(title)
  231. }
  232. }
  233. }