StringCompareViewController.swift 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. //
  2. // CompareViewController.swift
  3. // KdanAuto
  4. //
  5. // Created by 朱东勇 on 2023/2/2.
  6. //
  7. import Foundation
  8. import AppKit
  9. import PDFKit
  10. class StringCompareViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate, NSPopoverDelegate {
  11. @IBOutlet var listView : NSTableView!
  12. @IBOutlet var filterBtn : NSButton!
  13. @IBOutlet var closeBtn : NSButton!
  14. @IBOutlet var progressIndicator : NSProgressIndicator!
  15. var _files : NSArray!
  16. var _showFiles : NSMutableArray!
  17. var _popover: NSPopover!
  18. static var sharedSCViewController : StringCompareViewController? = nil
  19. class func shared() -> StringCompareViewController {
  20. if nil == sharedSCViewController {
  21. var objects : NSArray!
  22. Bundle.main.loadNibNamed("StringCompareViewController", owner: nil, topLevelObjects: &objects)
  23. for tView in objects {
  24. if let tv = tView as? StringCompareViewController {
  25. sharedSCViewController = tv
  26. }
  27. }
  28. }
  29. return sharedSCViewController!
  30. }
  31. override func viewDidLoad() {
  32. self.listView.register(NSNib.init(nibNamed: NSNib.Name.init(NSString(string: "StringCompareCellView")),
  33. bundle: Bundle.main), forIdentifier: NSUserInterfaceItemIdentifier.init("StringCompareCellView"))
  34. }
  35. // IBAction
  36. @IBAction func filterSimilarItemAction(_ sender:NSButton) {
  37. self.setFiles(_files);
  38. }
  39. @IBAction func exportAction(_ sender:NSButton) {
  40. if (_files.count == 0) {
  41. let alert = NSAlert.init()
  42. alert.messageText = "无测试对比项导出";
  43. alert.runModal();
  44. return
  45. }else if (_showFiles.count == 0) {
  46. let alert = NSAlert.init()
  47. alert.messageText = "所有对比项均无差异";
  48. alert.runModal();
  49. return
  50. }
  51. let savePanel = NSSavePanel.init();
  52. let checkBox = NSButton(checkboxWithTitle: "过滤无差异项", target: self, action: nil);
  53. checkBox.state = self.filterBtn.state;
  54. checkBox.frame = CGRectMake(0, 0, 150, 45);
  55. if #available(macOS 11.0, *) {
  56. savePanel.allowedContentTypes = [.rtf]
  57. } else {
  58. savePanel.allowedFileTypes = ["rtf", "rrtf"]
  59. }
  60. savePanel.accessoryView = checkBox
  61. if (savePanel.runModal() == .OK) {
  62. var exportFiles = NSMutableArray()
  63. if (checkBox.state == .on) {
  64. for tfile in NSArray(array: _files) {
  65. let file = tfile as! NSMutableDictionary;
  66. let degree = file.degree()
  67. if (fabs(degree - 100) > 0) {
  68. exportFiles.add(file);
  69. }
  70. }
  71. if (exportFiles.count == 0) {
  72. let alert = NSAlert.init()
  73. alert.messageText = "所有对比项均无差异";
  74. alert.runModal();
  75. return
  76. }
  77. }else {
  78. exportFiles = NSMutableArray(array: _files)
  79. }
  80. let url = savePanel.url!;
  81. NSLog("\(url)")
  82. let attString = NSMutableAttributedString(string: "");
  83. let needFilter = checkBox.state == .on
  84. self.progressIndicator.isHidden = false;
  85. self.progressIndicator.doubleValue = 0;
  86. processNextImages(attString, index: 0, files:exportFiles, url: url, needFilter: needFilter)
  87. }
  88. }
  89. // Save PDF
  90. func processNextImages(_ attString:NSMutableAttributedString, index:Int32, files:NSMutableArray, url:URL, needFilter:Bool) -> Void {
  91. let file = files[Int(index)] as! NSMutableDictionary
  92. let resultPath = NSString(string: file.resultPath()).appendingPathExtension("rtf")!
  93. let checkData = NSData.init(contentsOfFile: resultPath as String)! as Data
  94. var documentAttributes:NSDictionary!
  95. let tAttString = NSAttributedString.init(rtf: checkData, documentAttributes: &documentAttributes)
  96. if (tAttString != nil) {
  97. attString.append(NSMutableAttributedString(string: "\n\n"));
  98. attString.append(tAttString!)
  99. }
  100. self.closeBtn.isEnabled = false;
  101. DispatchQueue.global().async {
  102. if ((index+1) < files.count) {
  103. DispatchQueue.main.asyncAfter(deadline: DispatchTime.init(uptimeNanoseconds: 100)) {
  104. self.progressIndicator.doubleValue = Double(Int(index) * 100/files.count);
  105. self.processNextImages(attString, index: index+1, files: files, url: url, needFilter: needFilter);
  106. };
  107. }else {
  108. DispatchQueue.global().async {
  109. autoreleasepool {
  110. // 写入文件
  111. do {
  112. let rtfData = try? attString.data(from: .init(location: 0, length: attString.length),
  113. documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf])
  114. let path = NSString(string: resultPath).appendingPathExtension("rtf")
  115. try? FileManager.default.removeItem(at: url)
  116. try? rtfData?.write(to: url)
  117. } catch {
  118. }
  119. DispatchQueue.main.async {
  120. self.progressIndicator.isHidden = true;
  121. self.progressIndicator.doubleValue = 100.0;
  122. self.closeBtn.isEnabled = true;
  123. NSWorkspace.shared.activateFileViewerSelecting([url])
  124. }
  125. }
  126. }
  127. }
  128. }
  129. }
  130. // Show
  131. func showIn(_ view:NSView, rect:NSRect) {
  132. if _popover == nil {
  133. _popover = NSPopover.init()
  134. _popover.contentViewController = self;
  135. _popover.delegate = self
  136. }
  137. _popover.contentSize = self.view.frame.size
  138. _popover.show(relativeTo: rect, of: view, preferredEdge: NSRectEdge.minY)
  139. }
  140. // Getter & Setter
  141. func setFiles(_ files:NSArray) {
  142. _files = files
  143. if (self.filterBtn.state == .on) {
  144. _showFiles = NSMutableArray()
  145. for tfile in NSArray(array: _files) {
  146. let file = tfile as! NSMutableDictionary;
  147. let degree = file.degree()
  148. if (fabs(degree - 100) > 0) {
  149. _showFiles.add(file);
  150. }
  151. }
  152. }else {
  153. _showFiles = NSMutableArray (array: _files);
  154. }
  155. listView.reloadData()
  156. }
  157. // IBAction
  158. @IBAction func closeAction(_ sender: NSButton) {
  159. _popover.close()
  160. }
  161. // TableView Delegate
  162. func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
  163. return autoreleasepool {
  164. var cellView = tableView.makeView(withIdentifier: .init("StringCompareCellView"), owner: nil) as! StringCompareCellView?
  165. if (nil == cellView) {
  166. cellView = StringCompareCellView.shared() ?? nil
  167. }
  168. if (_showFiles.count > row) {
  169. let fileInfo = _showFiles[row] as! NSMutableDictionary
  170. cellView?.setFileInfo(fileInfo)
  171. }
  172. return cellView
  173. }
  174. }
  175. func selectionShouldChange(in tableView: NSTableView) -> Bool {
  176. return true
  177. }
  178. func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
  179. return false
  180. }
  181. func tableView(_ tableView: NSTableView, shouldSelect tableColumn: NSTableColumn?) -> Bool {
  182. return false
  183. }
  184. func tableView(_ tableView: NSTableView, mouseDownInHeaderOf tableColumn: NSTableColumn) {
  185. }
  186. func tableView(_ tableView: NSTableView, didClick tableColumn: NSTableColumn) {
  187. }
  188. func tableView(_ tableView: NSTableView, didDrag tableColumn: NSTableColumn) {
  189. }
  190. func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
  191. if (_showFiles.count > row) {
  192. let fileInfo = _showFiles[row] as! NSMutableDictionary
  193. return StringCompareCellView.heightFor(fileInfo)
  194. }
  195. return 0
  196. }
  197. func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
  198. return false
  199. }
  200. func tableView(_ tableView: NSTableView, sizeToFitWidthOfColumn column: Int) -> CGFloat {
  201. return tableView.frame.width
  202. }
  203. func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] {
  204. return []
  205. }
  206. func tableViewSelectionDidChange(_ notification: Notification) {
  207. }
  208. // TableView Data Source
  209. func numberOfRows(in tableView: NSTableView) -> Int {
  210. if nil == _showFiles {
  211. return 0
  212. }
  213. return _showFiles.count
  214. }
  215. //
  216. func popoverShouldClose(_ popover: NSPopover) -> Bool {
  217. return true
  218. }
  219. }