// // KMCompareWindowController.swift // PDF Reader Pro // // Created by lizhe on 2023/11/14. // import Cocoa typealias KMCompareWindowControllerContentComplete = (_ controller: KMCompareWindowController, _ pdfCompareContent: CPDFCompareContent, _ results: [CPDFCompareResults] ,_ oldDocument: CPDFDocument, _ document: CPDFDocument) -> Void typealias KMCompareWindowControllerCoveringComplete = (_ controller: KMCompareWindowController, _ document: CPDFDocument) -> Void class KMCompareWindowController: KMBaseWindowController { @IBOutlet weak var compareView: KMCompareView! var pdfCompareContent: CPDFCompareContent? var maskView: KMBookletMaskView? var progressController: SKProgressController? var filePath: String = "" { didSet { if compareView != nil { compareView.filePath = filePath } } } var fileType: KMCompareFilesType = .content { didSet { if compareView != nil { compareView.fileType = fileType } } } var password: String = "" { didSet { if compareView != nil { self.compareView.password = password } } } var contentComplete: KMCompareWindowControllerContentComplete? var coveringComplete :KMCompareWindowControllerCoveringComplete? override func windowDidLoad() { super.windowDidLoad() // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. compareView.password = password compareView.filePath = filePath compareView.fileType = fileType compareView.cancelAction = { [unowned self] view in cancelAction?(self) } compareView.doneAction = { [weak self] view, config in self?.compareAction(config: config) } } func compareAction(config: KMCompareFilesConfig) { self.showWaitting() guard let pdfOldDocument = config.fileOldAttribute.pdfDocument, let pdfNewDocument = config.fileNewAttribute.pdfDocument else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Please select two files to compare", comment: "") alert.runModal() self.hideWaitting() return } let fileManager = FileManager.default let fileOldPath = config.fileOldAttribute.pdfDocument?.documentURL.path let fileNewPath = config.fileNewAttribute.pdfDocument?.documentURL.path if !fileManager.fileExists(atPath: fileOldPath!) || !fileManager.fileExists(atPath: fileNewPath!){ let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("The file has been deleted, please reselect a file.", comment: "") alert.runModal() self.hideWaitting() return } if (config.fileNewAttribute.fetchSelectPages().count == 0) || (!config.fileNewAttribute.bAllPage && config.fileNewAttribute.pagesString.count < 1) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@ %@", (config.fileNewAttribute.pdfDocument?.documentURL.path.lastPathComponent.lastPathComponent)!, NSLocalizedString("Invalid page range. Please reselect the page range.", comment: "")) alert.runModal() config.fileNewAttribute.bAllPage = true config.fileNewAttribute.pagesType = .all compareView.reloadData() self.hideWaitting() return } if (config.fileOldAttribute.fetchSelectPages().count == 0) || (!config.fileOldAttribute.bAllPage && config.fileOldAttribute.pagesString.count < 1) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@ %@", (config.fileOldAttribute.pdfDocument?.documentURL.path.lastPathComponent.lastPathComponent)!, NSLocalizedString("Invalid page range. Please reselect the page range.", comment: "")) alert.runModal() config.fileOldAttribute.bAllPage = true config.fileOldAttribute.pagesType = .all compareView.reloadData() self.hideWaitting() return } let filePath = config.fileOldAttribute.pdfDocument?.documentURL.path let pdfDocument = CPDFDocument(url: URL(fileURLWithPath: filePath!)) let filePath1 = config.fileNewAttribute.pdfDocument?.documentURL.path let pdfDocument1 = CPDFDocument(url: URL(fileURLWithPath: filePath1!)) DispatchQueue.global().async { let oldDoc = CPDFDocument(url: config.fileOldAttribute.pdfDocument?.documentURL) oldDoc!.unlock(withPassword: config.fileOldAttribute.password) let doc = CPDFDocument(url: config.fileNewAttribute.pdfDocument?.documentURL) doc!.unlock(withPassword: config.fileNewAttribute.password) if self.compareView.fileType == .coverting { let pdfCompareOverlay = CPDFCompareOverlay(oldDocument: oldDoc, oldPageRange: config.fileOldAttribute.pagesString, newDocument: doc, newPageRange: config.fileNewAttribute.pagesString) let oldStrokeColor = config.oldStrokeColor pdfCompareOverlay?.setOldDocumentStroke(oldStrokeColor()) pdfCompareOverlay?.setOldDocumentStrokeOpacity(config.oldStrokeOpacity()) let newStrokeColor = config.newStrokeColor pdfCompareOverlay?.setNewDocumentStroke(newStrokeColor()) pdfCompareOverlay?.setNewDocumentStrokeOpacity(config.newStrokeOpacity()) pdfCompareOverlay?.setNewDocumentFillOpacity(config.newFillOpacity()) pdfCompareOverlay?.setOldDocumentFillOpacity(config.oldFillOpacity()) pdfCompareOverlay?.setNoFill(config.isNOFill()) pdfCompareOverlay?.setBlendMod(config.blendMod()) if (pdfCompareOverlay?.compare() == true) { DispatchQueue.main.async { self.progressController?.doubleValue = 30.0 } guard let document = pdfCompareOverlay?.comparisonDocument() else { DispatchQueue.main.async { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Failure", comment: "") alert.runModal() self.hideWaitting() } return } DispatchQueue.main.async { self.hideWaitting() self.coveringComplete?(self, document) } debugPrint("合并成功") } } else { var results: [CPDFCompareResults] = [] var pdfCompareContent: CPDFCompareContent? = nil // if let _pdfCompareContent = self._pdfCompareContent { // pdfCompareContent = _pdfCompareContent // } // // if self._compareCancel { // return // } pdfCompareContent = CPDFCompareContent(oldDocument: oldDoc, newDocument: doc) pdfCompareContent?.setDelete(config.deleteColor()) pdfCompareContent?.setReplace(config.replaceColor()) pdfCompareContent?.setInsert(config.insertColor()) pdfCompareContent?.setDeleteOpacity(config.deleteOpacity()) pdfCompareContent?.setReplaceOpacity(config.replaceOpacity()) pdfCompareContent?.setInsertOpacity(config.insertOpacity()) let maxIndex = max(config.fileOldAttribute.fetchSelectPages().count, config.fileNewAttribute.fetchSelectPages().count) var compareType: CPDFCompareType = .all if config.isCompareText() && !config.isCompareImage() { compareType = .text } else if !config.isCompareText() && config.isCompareImage() { compareType = .image } // if self._compareCancel { // return // } DispatchQueue.main.async { self.progressController?.doubleValue = 30.0 } for i in 0..= config.fileOldAttribute.fetchSelectPages().count { oldPageIndex = Int(oldDoc!.pageCount) + i } else { oldPageIndex = Int(truncating: config.fileOldAttribute.fetchSelectPages()[i] as NSNumber) - 1 } let newPageIndex: Int if i >= config.fileNewAttribute.fetchSelectPages().count { newPageIndex = Int(doc!.pageCount) + i } else { newPageIndex = Int(truncating: config.fileNewAttribute.fetchSelectPages()[i] as NSNumber) - 1 } if let compareResults = pdfCompareContent?.compareOldPageIndex(oldPageIndex, newPageIndex: newPageIndex, type: compareType, isDrawHighlight: true) { results.append(compareResults) } // DispatchQueue.main.async { // if let compareLoadingWVC = self.compareLoadingWVC { // compareLoadingWVC.progress = CGFloat(i) / CGFloat(maxIndex) // } // } } DispatchQueue.main.async { self.hideWaitting() self.contentComplete?(self, pdfCompareContent!, results, oldDoc!, doc!) if results.count > 0 { // Handle success case } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("There is no difference between the two documents.", comment: "") alert.runModal() } } } } } } extension KMCompareWindowController { func showWaitting() { compareView.doneButton.isEnabled = false if self.maskView == nil { self.maskView = KMBookletMaskView(frame: CGRect(x: 0, y: 0, width: self.window?.frame.size.width ?? 0, height: self.window?.frame.size.height ?? 0)) } self.window?.contentView?.addSubview(self.maskView!) let progress = SKProgressController() progress.window?.backgroundColor = NSColor.km_init(hex: "#36383B") progress.window?.contentView?.wantsLayer = true progress.window?.contentView?.layer?.backgroundColor = NSColor.km_init(hex: "#36383B").cgColor progress.progressField.textColor = NSColor.white progress.message = NSLocalizedString("Comparing documents...", comment: "") progress.closeBlock = { [weak self] in } self.progressController = progress self.window?.beginSheet(progress.window!) } func hideWaitting() { compareView.doneButton.isEnabled = true DispatchQueue.main.async { self.progressController?.doubleValue = 99.0 } self.maskView?.removeFromSuperview() if (self.progressController != nil) { self.window?.endSheet((self.progressController?.window)!) self.progressController = nil } } }