KMCompareView.swift 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. //
  2. // KMCompareView.swift
  3. // PDF Master
  4. //
  5. // Created by lizhe on 2023/11/14.
  6. //
  7. import Cocoa
  8. typealias KMCompareViewCancelAction = (_ view: KMCompareView) -> Void
  9. enum KMCompareFilesType {
  10. case content
  11. case coverting
  12. }
  13. let CPDFOldFileQKSelectedPathsKey = "CPDFOldFileQKSelectedPathsKey"
  14. let CPDFNewFileQKSelectedPathsKey = "CPDFNewFileQKSelectedPathsKey"
  15. let CPDFMaxQKSelectedPathsCount = 5
  16. class KMCompareView: KMBaseXibView {
  17. @IBOutlet weak var cancelButton: NSButton!
  18. @IBOutlet weak var doneButton: NSButton!
  19. @IBOutlet weak var compareTypeSegment: NSSegmentedControl!
  20. @IBOutlet weak var typeSegWidthConst: NSLayoutConstraint!
  21. @IBOutlet weak var comparePreviewBox: NSBox!
  22. @IBOutlet weak var oldDocumentsTitle: NSTextField!
  23. @IBOutlet weak var compareOldPreviewView: KMCompareFilesView!
  24. @IBOutlet weak var oldFileQKSelectedBox: NSComboBox!
  25. @IBOutlet weak var oldFileSelectBtn: NSButton!
  26. @IBOutlet weak var oldPDFView: PDFView!
  27. @IBOutlet weak var currentOldPageLabel: NSTextField!
  28. @IBOutlet weak var totalPaOldgeLabel: NSTextField!
  29. @IBOutlet weak var compareNewPreviewView: KMCompareFilesView!
  30. @IBOutlet weak var documentsNewTitle: NSTextField!
  31. @IBOutlet weak var fileQKNewSelectedBox: NSComboBox!
  32. @IBOutlet weak var fileSelectNewBtn: NSButton!
  33. @IBOutlet weak var pdfNewView: PDFView!
  34. @IBOutlet weak var addFileContentView: KMCompareFilesView!
  35. @IBOutlet weak var addFileImageView: NSImageView!
  36. @IBOutlet weak var addFileAddImageFramView: KMCompareFilesView!
  37. @IBOutlet weak var currentNewPageLabel: NSTextField!
  38. @IBOutlet weak var totalPaNewgeLabel: NSTextField!
  39. @IBOutlet weak var addFileTitle: NSTextField!
  40. @IBOutlet weak var addFileMag: NSTextField!
  41. @IBOutlet weak var pageRangeField: NSTextField!
  42. @IBOutlet weak var oldFileRangeField: NSTextField!
  43. @IBOutlet weak var pageRangeOldComboBox: NSComboBox!
  44. @IBOutlet weak var fileNewRangeField: NSTextField!
  45. @IBOutlet weak var pageRangeNewComboBox: NSComboBox!
  46. @IBOutlet weak var compareTextTypeBtn: NSButton!
  47. @IBOutlet weak var compareImageTypeBtn: NSButton!
  48. @IBOutlet weak var compareSettingsBtn: NSButton!
  49. @IBOutlet weak var settingBtnTopLayout: NSLayoutConstraint!
  50. var pdfCompareContent: CPDFCompareContent?
  51. var pdfOldDocument: PDFDocument?
  52. var oldFileQKSelectedPaths: [String] = []
  53. var pdfNewDocument: PDFDocument?
  54. var fileQKNewSelectedPaths: [String] = []
  55. var fileType: KMCompareFilesType = .content
  56. var cancelAction: KMCompareViewCancelAction?
  57. convenience init(pdfDocument: PDFDocument) {
  58. self.init()
  59. self.pdfOldDocument = pdfDocument
  60. let document: CPDFDocument = CPDFDocument.init(url: pdfDocument.documentURL)
  61. let file: KMFileAttribute = KMFileAttribute()
  62. file.pdfDocument = document
  63. let config: KMCompareFilesConfig = KMCompareFilesConfig.init()
  64. config.fileOldAttribute = file
  65. }
  66. convenience init(filePath: String, password: String) {
  67. self.init()
  68. self.pdfOldDocument = PDFDocument.init(url: NSURL(fileURLWithPath: filePath) as URL)
  69. let pdfDocument = CPDFDocument.init(url: NSURL(fileURLWithPath: filePath) as URL)
  70. if pdfDocument!.isLocked {
  71. pdfDocument!.unlock(withPassword: password)
  72. }
  73. if self.pdfOldDocument!.isLocked {
  74. self.pdfOldDocument!.unlock(withPassword: password)
  75. }
  76. let file: KMFileAttribute = KMFileAttribute()
  77. file.pdfDocument = pdfDocument
  78. let config = KMCompareFilesConfig.defaultConfig
  79. config.fileOldAttribute = file
  80. config.fileOldAttribute.password = password
  81. }
  82. override func setup() {
  83. fileQKNewSelectedBox.delegate = self
  84. oldFileQKSelectedBox.delegate = self
  85. compareTypeSegment.action = #selector(segmentedControlClicked)
  86. compareTypeSegment.target = self
  87. compareTypeSegment.wantsLayer = true
  88. addFileContentView.wantsLayer = true
  89. addFileImageView.ignoresMultiClick = true
  90. fileQKNewSelectedBox.isEnabled = false
  91. oldFileQKSelectedBox.isEnabled = false
  92. fileQKNewSelectedBox.cell!.isEnabled = false
  93. oldFileQKSelectedBox.cell!.isEnabled = false
  94. currentOldPageLabel.delegate = self
  95. currentNewPageLabel.delegate = self
  96. oldPDFView.wantsLayer = true
  97. pdfNewView.wantsLayer = true
  98. // vsMaskView.wantsLayer = true;
  99. oldPDFView.layer?.backgroundColor = NSColor.clear.cgColor
  100. pdfNewView.layer?.backgroundColor = NSColor.clear.cgColor
  101. // vsMaskView.layer.backgroundColor = NSColor.clear.CGColor
  102. compareTypeSegment.wantsLayer = true
  103. compareTypeSegment.layer?.cornerRadius = 5.0
  104. compareTypeSegment.layer?.masksToBounds = true
  105. compareTypeSegment.layer?.backgroundColor = NSColor.clear.cgColor
  106. addFileContentView.wantsLayer = true
  107. addFileAddImageFramView.wantsLayer = true
  108. addFileAddImageFramView.layer?.backgroundColor = NSColor.clear.cgColor
  109. self.compareOldPreviewView.dragSuccessBlock = { [unowned self] filePath in
  110. self.updateDocument(filePath: filePath) { fileAttitude in
  111. }
  112. }
  113. self.compareNewPreviewView.dragSuccessBlock = { [unowned self] filePath in
  114. self.updateDocument(filePath: filePath, isNew: true) { fileAttitude in
  115. }
  116. }
  117. self.addFileContentView.dragSuccessBlock = { [unowned self] filePath in
  118. self.updateDocument(filePath: filePath, isNew: true) { fileAttitude in
  119. }
  120. }
  121. self.addFileAddImageFramView.dragSuccessBlock = { [unowned self] filePath in
  122. self.updateDocument(filePath: filePath, isNew: true) { fileAttitude in
  123. }
  124. }
  125. self.addFileContentView.mouseUpBack = { [unowned self] view in
  126. self.chooseFileAction()
  127. }
  128. }
  129. override func updateLanguage() {
  130. compareTypeSegment.setLabel(NSLocalizedString("Side-by-Side View", comment: ""), forSegment: 0)
  131. compareTypeSegment.setLabel(NSLocalizedString("Compare by File Overlay", comment: ""), forSegment: 1)
  132. compareTypeSegment.setToolTip(NSLocalizedString("Side-by-Side View", comment: ""), forSegment: 0)
  133. compareTypeSegment.setToolTip(NSLocalizedString("Compare by File Overlay", comment: ""), forSegment: 1)
  134. oldDocumentsTitle.stringValue = NSLocalizedString("Old File", comment: "")
  135. documentsNewTitle.stringValue = NSLocalizedString("New File", comment: "")
  136. oldFileSelectBtn.title = NSLocalizedString("Choose...", comment: "")
  137. fileSelectNewBtn.title = NSLocalizedString("Choose...", comment: "")
  138. oldFileSelectBtn.toolTip = NSLocalizedString("Choose...", comment: "")
  139. fileSelectNewBtn.toolTip = NSLocalizedString("Choose...", comment: "")
  140. addFileTitle.stringValue = NSLocalizedString("Select File", comment: "")
  141. addFileMag.stringValue = NSLocalizedString("Click to add", comment: "")
  142. oldFileRangeField.stringValue = NSLocalizedString("Old File:", comment: "")
  143. fileNewRangeField.stringValue = NSLocalizedString("New File:", comment: "")
  144. pageRangeField.stringValue = NSLocalizedString("Page Range", comment: "")
  145. pageRangeOldComboBox.removeAllItems()
  146. pageRangeOldComboBox.addItems(withObjectValues: [NSLocalizedString("All Pages", comment: ""),
  147. NSLocalizedString("Odd Pages Only", comment: ""),
  148. NSLocalizedString("Even Pages Only",comment: ""),
  149. NSLocalizedString("e.g. 1,3-5,10",comment: "")])
  150. pageRangeOldComboBox.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "")
  151. pageRangeNewComboBox.addItems(withObjectValues: [NSLocalizedString("All Pages", comment: ""),
  152. NSLocalizedString("Odd Pages Only", comment: ""),
  153. NSLocalizedString("Even Pages Only",comment: ""),
  154. NSLocalizedString("e.g. 1,3-5,10",comment: "")])
  155. self.pageRangeNewComboBox.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "")
  156. self.compareTextTypeBtn.title = NSLocalizedString("Compare text", comment: "")
  157. self.compareImageTypeBtn.title = NSLocalizedString("Compare image", comment: "")
  158. let settingsString = " " + NSLocalizedString("Settings", comment: "")
  159. compareSettingsBtn.title = settingsString
  160. compareSettingsBtn.state = .off
  161. compareSettingsBtn.setTitleColor(KMAppearance.Layout.h1Color())
  162. cancelButton.title = NSLocalizedString("Cancel", comment: "")
  163. doneButton.title = NSLocalizedString("Compare", comment: "")
  164. }
  165. override func updateUI() {
  166. if KMAppearance.isDarkMode() {
  167. self.compareTypeSegment.layer?.backgroundColor = NSColor(red: 50.0/255.0, green: 53.0/255.0, blue: 54.0/255.0, alpha: 1).cgColor
  168. self.addFileContentView.layer?.backgroundColor = NSColor.black.cgColor
  169. } else {
  170. self.compareTypeSegment.layer?.backgroundColor = NSColor(red: 247.0/255.0, green: 247.0/255.0, blue: 247.0/255.0, alpha: 1).cgColor
  171. self.addFileContentView.layer?.backgroundColor = NSColor.white.cgColor
  172. }
  173. }
  174. override func reloadData() {
  175. if(pageRangeOldComboBox.indexOfSelectedItem == 3) {
  176. self.window?.makeFirstResponder(pageRangeOldComboBox)
  177. pageRangeOldComboBox.stringValue = ""
  178. pageRangeOldComboBox.isSelectable = true
  179. }
  180. self.updatePageRangeData(view: pageRangeNewComboBox, file: KMCompareFilesConfig.defaultConfig.fileNewAttribute, isNew: true)
  181. self.updatePageRangeData(view: pageRangeOldComboBox, file: KMCompareFilesConfig.defaultConfig.fileOldAttribute)
  182. if (KMCompareFilesConfig.defaultConfig.isCompareText)() {
  183. self.compareTextTypeBtn.state = .on;
  184. } else {
  185. self.compareTextTypeBtn.state = .off;
  186. }
  187. if (KMCompareFilesConfig.defaultConfig.isCompareImage)() {
  188. self.compareImageTypeBtn.state = .on;
  189. } else {
  190. self.compareImageTypeBtn.state = .off;
  191. }
  192. self.updateSelectBoxData()
  193. self.updatePageState()
  194. self.updatePageState(isNew: true)
  195. }
  196. }
  197. extension KMCompareView {
  198. func addFileQKSelectPath(filePath: String, isNewFile: Bool = false) {
  199. let pdfdocument = CPDFDocument(url: NSURL(fileURLWithPath: filePath) as URL)
  200. guard let pdfdocument = pdfdocument else { return }
  201. var key = ""
  202. if isNewFile {
  203. key = CPDFNewFileQKSelectedPathsKey
  204. } else {
  205. key = CPDFOldFileQKSelectedPathsKey
  206. }
  207. var filePaths: [String] = UserDefaults.standard.object(forKey: key) as? [String] ?? []
  208. if filePaths.count > CPDFMaxQKSelectedPathsCount {
  209. filePaths.removeLast()
  210. }
  211. filePaths.insert(filePath, at: 0)
  212. }
  213. func updateSelectBoxData() {
  214. self.oldFileQKSelectedPaths = self.updateSelectBoxItemData()
  215. self.oldFileQKSelectedBox.removeAllItems()
  216. self.oldFileQKSelectedBox.addItems(withObjectValues: self.oldFileQKSelectedPaths)
  217. self.fileQKNewSelectedPaths = self.updateSelectBoxItemData(isNew: true)
  218. self.fileQKNewSelectedBox.removeAllItems()
  219. self.fileQKNewSelectedBox.addItems(withObjectValues: self.fileQKNewSelectedPaths)
  220. if self.fileQKNewSelectedPaths.count > 0 {
  221. self.fileQKNewSelectedBox.isEnabled = true
  222. } else {
  223. self.fileQKNewSelectedBox.isEnabled = false
  224. }
  225. }
  226. func updateSelectBoxItemData(isNew: Bool = false) -> [String] {
  227. let defaults = UserDefaults.standard
  228. var fileSelectedCachePaths: [String] = []
  229. if isNew {
  230. fileSelectedCachePaths = defaults.value(forKey: CPDFOldFileQKSelectedPathsKey) as? [String] ?? []
  231. } else {
  232. fileSelectedCachePaths = defaults.value(forKey: CPDFNewFileQKSelectedPathsKey) as? [String] ?? []
  233. }
  234. var fileSelectedPaths: [String] = []
  235. let fileManager = FileManager.default
  236. for path in fileSelectedCachePaths {
  237. if fileManager.fileExists(atPath: path) {
  238. // #if VERSION_DMG
  239. fileSelectedPaths.append(path)
  240. // #else
  241. // let url = URL(fileURLWithPath: path)
  242. //
  243. // if let bookmarkData = try? url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil) {
  244. // AppSandboxFileAccess.fileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, forURL: url)
  245. // AppSandboxFileAccess.fileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, forURL: URL(fileURLWithPath: url.path ?? url.absoluteString))
  246. //
  247. // fileOldSelectedPaths.append(path)
  248. // } else {
  249. // AppSandboxFileAccess.fileAccess().accessFileURL(url, persistPermission: yearMask) {
  250. // if let bookmarkData = try? url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil) {
  251. // fileOldSelectedPaths.append(path)
  252. // }
  253. // }
  254. // }
  255. // #endif
  256. }
  257. }
  258. return fileSelectedPaths
  259. }
  260. func updatePageState(isNew: Bool = false) {
  261. var pageDocument = PDFDocument()
  262. var pdfView = PDFView()
  263. var currentPageLabel = NSTextField()
  264. var totalPageLabel = NSTextField()
  265. guard let pdfNewDocument = pdfNewDocument else { return }
  266. guard let pdfOldDocument = pdfOldDocument else { return }
  267. if isNew {
  268. pageDocument = pdfNewDocument
  269. pdfView = pdfNewView
  270. currentPageLabel = currentNewPageLabel
  271. totalPageLabel = totalPaNewgeLabel
  272. } else {
  273. pageDocument = pdfOldDocument
  274. pdfView = oldPDFView
  275. currentPageLabel = currentOldPageLabel
  276. totalPageLabel = totalPaOldgeLabel
  277. }
  278. // 隐藏PDFView滑动条
  279. pdfView.documentView?.enclosingScrollView?.hasVerticalScroller = false
  280. pdfView.documentView?.enclosingScrollView?.hasHorizontalScroller = false
  281. let pageCount = pageDocument.pageCount
  282. var currentPageIndex = 0
  283. if(pdfView.currentPage != nil) {
  284. currentPageIndex = pageDocument.index(for: pdfView.currentPage!)
  285. }
  286. if(pageCount > 0) {
  287. currentPageLabel.stringValue = "\(currentPageIndex + 1)"
  288. } else {
  289. currentPageLabel.stringValue = "\(currentPageIndex)"
  290. }
  291. totalPageLabel.stringValue = "/ \(pageCount)"
  292. }
  293. func updateDocument(filePath: String, isNew: Bool = false, completion: @escaping (_ fileAttitude: KMFileAttribute?) -> Void) {
  294. var pdfDocument = CPDFDocument()
  295. if isNew {
  296. pdfDocument = KMCompareFilesConfig.defaultConfig.fileOldAttribute.pdfDocument ?? CPDFDocument()
  297. } else {
  298. pdfDocument = KMCompareFilesConfig.defaultConfig.fileNewAttribute.pdfDocument ?? CPDFDocument()
  299. }
  300. guard let pdfDocument = pdfDocument else {
  301. completion(nil)
  302. return
  303. }
  304. if (pdfDocument.documentURL.path == filePath) {
  305. let alert = NSAlert()
  306. alert.alertStyle = NSAlert.Style.critical
  307. alert.messageText = NSLocalizedString("There is no difference between the two documents.", comment: "")
  308. alert.runModal()
  309. completion(nil)
  310. return
  311. } else {
  312. KMBaseWindowController.checkPassword(url: NSURL(fileURLWithPath: filePath) as URL) { success, resultPassword in
  313. if success {
  314. let file = KMFileAttribute()
  315. file.pdfDocument = pdfDocument
  316. file.password = resultPassword
  317. completion(file)
  318. } else {
  319. completion(nil)
  320. }
  321. }
  322. }
  323. }
  324. func updatePageRangeData(view: NSComboBox, file: KMFileAttribute, isNew: Bool = false) {
  325. switch (file.pagesType) {
  326. case .all:
  327. view.selectItem(at: 0)
  328. view.isEditable = false
  329. view.delegate = nil
  330. break;
  331. case .odd:
  332. view.selectItem(at: 1)
  333. view.isEditable = false
  334. view.delegate = nil
  335. break;
  336. case .even:
  337. view.selectItem(at: 2)
  338. view.isEditable = false
  339. view.delegate = nil
  340. break;
  341. case .custom:
  342. view.delegate = self
  343. view.stringValue = file.pagesString
  344. view.isEditable = true
  345. break;
  346. default: break
  347. }
  348. }
  349. func updateFileCompareType(fileType: KMCompareFilesType) {
  350. if fileType == .content {
  351. compareTypeSegment.selectedSegment = 0
  352. compareTextTypeBtn.isHidden = false
  353. compareImageTypeBtn.isHidden = false
  354. settingBtnTopLayout.constant = 81
  355. } else {
  356. compareTypeSegment.selectedSegment = 1
  357. compareTextTypeBtn.isHidden = true
  358. compareImageTypeBtn.isHidden = true
  359. settingBtnTopLayout.constant = 20
  360. }
  361. }
  362. }
  363. extension KMCompareView {
  364. @IBAction func cancelButtonAction(_ sender: Any) {
  365. guard let callBack = cancelAction else { return }
  366. callBack(self)
  367. }
  368. @IBAction func convertButtonAction(_ sender: Any) {
  369. }
  370. @objc func segmentedControlClicked(sender: NSSegmentedControl) {
  371. }
  372. func chooseFileAction(isNew: Bool = false) {
  373. // fileQKNewSelectedBox.resignFirstResponder()
  374. self.window?.makeFirstResponder(nil)
  375. let openPanel = NSOpenPanel()
  376. openPanel.allowedFileTypes = ["pdf"]
  377. openPanel.allowsMultipleSelection = false
  378. openPanel.beginSheetModal(for: self.window!) { (result) in
  379. if result == NSApplication.ModalResponse.OK {
  380. #if VERSION_DMG
  381. // Add code for VERSION_DMG
  382. #else
  383. // if let url = openPanel.url {
  384. // do {
  385. // let bookmarkData = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil)
  386. // AppSandboxFileAccess.fileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, forURL: url)
  387. // AppSandboxFileAccess.fileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, forURL: URL(fileURLWithPath: url.path ?? url.absoluteString))
  388. // } catch {
  389. // // Handle error
  390. // print("Error creating bookmark data: \(error)")
  391. // }
  392. // }
  393. #endif
  394. if let filePath = openPanel.url?.path {
  395. self.updateDocument(filePath: filePath, isNew: isNew) { file in
  396. }
  397. }
  398. }
  399. }
  400. }
  401. }
  402. extension KMCompareView: NSComboBoxDelegate {
  403. }