// // KMBatchOperateLeftViewController.swift // PDF Reader Pro // // Created by kdanmobile on 2023/10/26. // import Cocoa let KMBatchDragType = "KMBatchDragType" class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NSTableViewDataSource{ @IBOutlet var selectFileButton: KMLongerButton! @IBOutlet var deleteFileButton: NSButton! @IBOutlet var tableView: NSTableView! @IBOutlet var indexTableColumn: NSTableColumn! @IBOutlet var fileNameTableColumn: NSTableColumn! @IBOutlet var pageRangeTableColumn: NSTableColumn! @IBOutlet var sizeTableColumn: NSTableColumn! @IBOutlet var stateTableColumn: NSTableColumn! @IBOutlet var DPIColumn: NSTableColumn! @IBOutlet var dimensionsTableColumn: NSTableColumn! @IBOutlet var headerOperateView: NSView! @IBOutlet var showInFinderMenuItem: NSMenuItem! @IBOutlet var deleteMenuItem: NSMenuItem! @IBOutlet var blankView: KMBlankView! var files: [KMBatchOperateFile] = [] var type: KMBatchOperationType? var lockFilePathArr: NSMutableArray? var lockFileIndex: Int = 0 var popOver: NSPopover? var progressInt: Int = 0 deinit { NotificationCenter.default.removeObserver(self) DistributedNotificationCenter.default().removeObserver(self) } override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self.tableView!, selector: #selector(self.reloadData), name: NSNotification.Name(kNeedChangePageRangeNotification), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(imageToPDFSuccessNotification(aNotification:)), name: NSNotification.Name("KMBatchOperateImageToPDFSuccessNotification"), object: nil) DistributedNotificationCenter.default.addObserver(self, selector: #selector(themeChanged(notification:)), name: NSNotification.Name("AppleInterfaceThemeChangedNotification"), object: nil) for i in 0..<self.tableView.tableColumns.count { let column = self.tableView.tableColumns[i] column.headerCell = KMTableHeaderCell(textCell: column.title) } self.deleteFileButton.addHoverEffect = true self.indexTableColumn.resizingMask = [] self.fileNameTableColumn.resizingMask = .autoresizingMask self.pageRangeTableColumn.resizingMask = [] self.sizeTableColumn.resizingMask = [] self.stateTableColumn.resizingMask = [] self.DPIColumn.resizingMask = [] self.dimensionsTableColumn.resizingMask = [] self.tableView.moveColumn(5, toColumn: 2) self.indexTableColumn.title = " \(NSLocalizedString("Index", comment: ""))" self.fileNameTableColumn.title = NSLocalizedString("File Name", comment: "") self.pageRangeTableColumn.title = NSLocalizedString("Page Range", comment: "") self.sizeTableColumn.title = NSLocalizedString("Size", comment: "") self.stateTableColumn.title = NSLocalizedString("Status", comment: "") self.DPIColumn.title = NSLocalizedString("DPI", comment: "") self.dimensionsTableColumn.title = NSLocalizedString("Dimensions", comment: "") self.DPIColumn.isHidden = true self.tableView.intercellSpacing = CGSize(width: 0, height: 0) self.tableView.backgroundColor = KMAppearance.Layout.bgColor() self.tableView.allowsColumnReordering = false self.tableView.allowsMultipleSelection = true self.tableView.enclosingScrollView?.borderType = .noBorder self.headerOperateView.wantsLayer = true self.tableView.registerForDraggedTypes([NSPasteboard.PasteboardType.string,NSPasteboard.PasteboardType.fileURL]) //[KMBatchDragType,NSFilenamesPboardType] self.lockFilePathArr = NSMutableArray() self.lockFileIndex = 0 self.progressInt = 0 self.selectFileButton.title = " " + NSLocalizedString("Add Files", comment: "") self.selectFileButton.wantsLayer = true self.selectFileButton.layer?.borderWidth = 1.0 self.selectFileButton.layer?.borderColor = KMAppearance.Interactive.m0Color().cgColor self.selectFileButton.layer?.cornerRadius = 1.0 self.selectFileButton.setTitleColor(KMAppearance.Layout.mColor()) self.selectFileButton.containerViewController = self self.showInFinderMenuItem.title = NSLocalizedString("Show in Finder", comment: "") self.deleteMenuItem.title = NSLocalizedString("Delete", comment: "") self.blankView.wantsLayer = true self.blankView.layer?.backgroundColor = NSColor.clear.cgColor self.blankView.titleLabel.stringValue = NSLocalizedString("Select Files", comment: "") self.blankView.imageView.isHidden = true self.blankView.addButton.isHidden = false self.blankView.secondTitleLabel.stringValue = NSLocalizedString("Drop files here or Click Add Files at upper left corner. You can drag files to reorder as you need.", comment: "") self.blankView.mouseActionCallBack = { [weak self] mouseType in guard let self = self else { return } if mouseType == .mouseEnter { self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov") } else if mouseType == .mouseExit { self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListNor") } else if mouseType == .mouseDown { self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListPre") self.chooseFile() } else if mouseType == .mouseUp { self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov") } } updateViewColor() } @objc func reloadData() { if Thread.isMainThread { tableView.reloadData() } else { DispatchQueue.main.async { self.tableView.reloadData() } } } @objc func imageToPDFSuccessNotification(aNotification: Notification) { guard let dict = aNotification.userInfo, let isSuccess = dict["isSuccess"] as? Bool else { return } if isSuccess { progressInt = 1 } else { progressInt = -1 } DispatchQueue.main.async { self.tableView.reloadData() } } @objc func themeChanged(notification: Notification) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: { self.updateViewColor() }) } func updateViewColor() { self.view.wantsLayer = true if KMAppearance.isDarkMode() { self.headerOperateView.layer?.backgroundColor = NSColor(red: 0.055, green: 0.067, blue: 0.078, alpha: 1).cgColor } else { self.headerOperateView.layer?.backgroundColor = NSColor(red: 0.922, green: 0.925, blue: 0.941, alpha: 1).cgColor } } func chooseFile() { #if VERSION_FREE if KMMemberInfo.shared.isMemberAllFunction == false { if files.count >= 1 { let winC = KMProductCompareWC.shared if type == .CreatePDF { winC.kEventName = "Onbrd_ImagetoPDF_BuyNow" } KMMemberInfo.shared.advancedFunctionUsage(type: .batch) return } } #endif self.progressInt = 0 let panel = NSOpenPanel() if type == .CreatePDF { panel.allowedFileTypes = KMImageToPDFMethod.supportedImageTypes() } else { panel.allowedFileTypes = ["pdf", "PDF"] } if KMMemberInfo.shared.isMemberAllFunction { panel.allowsMultipleSelection = true panel.canChooseDirectories = true } panel.canChooseFiles = true #if VERSION_FREE #else panel.message = NSLocalizedString("To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "") #endif panel.beginSheetModal(for: self.view.window!) { (result) in if result.rawValue == NSApplication.ModalResponse.OK.rawValue { let addArray = NSMutableArray() for fileURL in panel.urls { let filePath = fileURL.path var isDirectory = ObjCBool(false) FileManager.default.fileExists(atPath: filePath, isDirectory: &isDirectory) if isDirectory.boolValue { let containFiles = self.fetchAvailableFiles(in: filePath) addArray.addObjects(from: containFiles) } else { let typeIdentifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, filePath.customPathExtension as CFString, nil) let TypeCFString = typeIdentifier!.takeRetainedValue() as String if self.type == .CreatePDF { if UTTypeConformsTo(TypeCFString as CFString, kUTTypeImage) { addArray.add(filePath) } } else { if UTTypeConformsTo(TypeCFString as CFString, kUTTypePDF) { addArray.add(filePath) } } } } self.addFilesToList(addArray: addArray) } } } func fetchAvailableFiles(in folderPath: String) -> [String] { let array = NSMutableArray() let subFileArray = (FileManager.default.subpaths(atPath: folderPath)! as NSArray).mutableCopy() as? NSMutableArray for i in 0..<subFileArray!.count { if let path = (folderPath as NSString).appendingPathComponent(subFileArray!.object(at: i) as! String) as String? { if let UTTypeString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, path.customPathExtension as CFString, nil)?.takeRetainedValue() as String? { let TypeCFString = UTTypeString as CFString if self.type == .CreatePDF { if UTTypeConformsTo(TypeCFString, kUTTypeImage) { array.add(path) } } else { if UTTypeConformsTo(TypeCFString, kUTTypePDF) { array.add(path) } } } } } return array as! [String] } func addFilesToList(addArray: NSMutableArray) { self.lockFilePathArr!.removeAllObjects() self.lockFileIndex = 0 for i in 0..<addArray.count { let filePath = addArray[i] as! String let UTTypeString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, filePath.customPathExtension as CFString, nil)!.takeRetainedValue() as String let TypeCFString = UTTypeString as CFString if UTTypeConformsTo(TypeCFString, kUTTypePDF) { let document = CPDFDocument(url: URL(fileURLWithPath: filePath)) if document?.isLocked == true { var isContaint = false for file in self.files { if (file as AnyObject).filePath == filePath { isContaint = true break } } if !isContaint { self.lockFilePathArr!.add(filePath) } } else { let file = KMBatchOperateFile(filePath: addArray[i] as! String, type: self.type!) if !self.files.contains(file) { self.files.append(file) } } } else { let file = KMBatchOperateFile(filePath: addArray[i] as! String, type: self.type!) if !self.files.contains(file) { self.files.append(file) } } } self.tableView.reloadData() if self.lockFilePathArr!.count > 0 { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.openPasswordWindow() } } } func openPasswordWindow() { if lockFilePathArr!.count > lockFileIndex { let filePath = lockFilePathArr![lockFileIndex] as! String KMBaseWindowController.checkPassword(url: URL(fileURLWithPath: filePath), type: .owner) { [unowned self] success, resultPassword in self.closePwd() if !resultPassword.isEmpty { let file = KMBatchOperateFile(filePath: filePath, type: self.type!) file.password = resultPassword self.files.append(file) self.tableView.reloadData() } self.lockFileIndex += 1 if self.lockFilePathArr?.count ?? 0 > self.lockFileIndex { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.openPasswordWindow() } } else { self.tableView.reloadData() } } } } func closePwd() { self.km_endSheet() } func chooseFileFromCamera() { self.progressInt = 0 let vc = KMDeviceBrowserWindowController.shared vc.type = .camera vc.importCameraFileCallback = { [weak self](url: NSURL) -> Void in self?.addFilesToList(addArray: [url.path!]) } vc.showWindow(nil) } func chooseFileFromScanner() { self.progressInt = 0 let vc = KMDeviceBrowserWindowController.shared vc.type = .scanner vc.importScannerFileCallback = { [weak self](url: NSURL) -> Void in self?.addFilesToList(addArray: [url.path!]) } vc.showWindow(nil) } @IBAction func buttonClicked_SelectFile(_ sender: Any) { } @IBAction func blankViewAddFileAction(_ sender: Any) { self.chooseFile() } @IBAction func buttonClicked_DeleteFile(_ sender: Any) { let set = self.tableView.selectedRowIndexes let newArr: NSMutableArray = NSMutableArray.init(array: self.files) let arr = newArr.objects(at: set) if arr.count > 0 { newArr.removeObjects(in: arr) self.files = newArr as! [KMBatchOperateFile] self.tableView.reloadData() } else { // if KMAlertWindowController.needShowRemoveAllFilesHint() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Clear All Recents", comment: "")+"?" alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) alert.beginSheetModal(for: self.view.window!) {[weak self] response in if response == NSApplication.ModalResponse.alertFirstButtonReturn { self?.files.removeAll() self?.tableView.reloadData() } } // } else { // self.files.removeAll() // self.tableView.reloadData() // } } } func fetchAvailableFilesInFolder(_ folderPath: String) -> [String] { var array: [String] = [] let subFileArray = FileManager().subpaths(atPath: folderPath) for i in 0..<subFileArray!.count { let path = folderPath.stringByAppendingPathComponent(subFileArray![i]) let TypeCFString = KMTools.UTIforFileExtension(path.customPathExtension) as CFString if self.type == .CreatePDF { if UTTypeConformsTo(TypeCFString, kUTTypeImage) { array.append(path) } } else { if UTTypeConformsTo(TypeCFString, kUTTypePDF) { array.append(path) } } // UTTypeString?.release() } return array } func folderContainAvailableFile(_ folderPath: String) -> Bool { var containFile = false guard let subFileArray = FileManager.default.subpaths(atPath: folderPath) else { return containFile } for i in 0..<subFileArray.count { let path = folderPath.stringByAppendingPathComponent(subFileArray[i] ) let TypeCFString = KMTools.UTIforFileExtension(path.customPathExtension) as CFString if type == .CreatePDF { if UTTypeConformsTo(TypeCFString, kUTTypeImage) { containFile = true } } else { if UTTypeConformsTo(TypeCFString, kUTTypePDF) { containFile = true } } // UTTypeString?.release() if containFile { break } } return containFile } func switchToOperateType(_ type: KMBatchOperationType) { self.type = type self.indexTableColumn.isHidden = false self.fileNameTableColumn.isHidden = false self.pageRangeTableColumn.isHidden = false self.sizeTableColumn.isHidden = false self.stateTableColumn.isHidden = false self.DPIColumn.isHidden = true self.dimensionsTableColumn.isHidden = true if type == .Compress || type == .AddPassword || type == .RemovePassword || type == .RemoveWatermark || type == .RemoveBackground || type == .RemoveHeaderFooter || type == .RemoveBates || type == .CreatePDF { self.pageRangeTableColumn.isHidden = true } else { self.pageRangeTableColumn.isHidden = false } self.selectFileButton.isImageToPDF = type == .CreatePDF if type == .CreatePDF { self.pageRangeTableColumn.isHidden = false self.pageRangeTableColumn.title = NSLocalizedString("Dimensions", comment: "") } for i in 0..<self.files.count { let file = self.files[i] file.currentOperateType = type } self.tableView.sizeToFit() self.tableView.reloadData() } @IBAction func menuItem_ShowInFinder(_ sender: Any) { let row = self.tableView.clickedRow let file: KMBatchOperateFile = self.files[row] if file.currentOperateInfo?.status == .Success { NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: file.currentOperateInfo!.outPutPath!)]) }else { NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: file.filePath)]) } } @IBAction func menuItem_Delete(_ sender: Any) { let row = self.tableView.clickedRow self.files.remove(at: row) self.tableView.reloadData() } func addOpendFile() { let documentArray = NSDocumentController.shared.documents var pdfArray = NSMutableArray() for i in 0..<documentArray.count { let document = documentArray[i] let path: String = document.fileURL?.path ?? "" let UTTypeString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, path.customPathExtension as CFString, nil)?.takeRetainedValue() as String? let TypeCFString = UTTypeString as CFString? if UTTypeConformsTo(TypeCFString!, kUTTypePDF) { pdfArray.add(path as Any) } else { } } if KMMemberInfo.shared.isMemberAllFunction == false { if self.files.count < 1 { pdfArray = NSMutableArray(array: [pdfArray.firstObject as Any]) } else { KMMemberInfo.shared.advancedFunctionUsage(type: .batch) return } } addFilesToList(addArray: pdfArray) } func numberOfRows(in tableView: NSTableView) -> Int { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMBatchFilesCountNotification"), object: self.files, userInfo: [kObjectKey : self]) self.deleteFileButton.isEnabled = self.files.count > 0 self.blankView.isHidden = self.files.count > 0 return self.files.count; } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let identifier = tableColumn?.identifier let file = self.files[row] if identifier?.rawValue == "index" { let cellView = KMBatchTableCellView(type: .Size) _ = row + 1 cellView.textField?.stringValue = String(format: "%d", row + 1); return cellView; } else if identifier?.rawValue == "pageRange"{ if (file.currentOperateType == .CreatePDF) { let cellView = KMBatchTableCellView(type: .Size) if (file.fileType == .Image) { let image = NSImage(contentsOfFile: file.filePath) cellView.textField?.stringValue = String(Int(image?.size.width ?? 0)) + "x" + String(Int(image?.size.height ?? 0)) } return cellView; } else { let cellView = KMBatchTableCellView(type: .PageRange) cellView.updateInterface(file) return cellView; } } else if identifier?.rawValue == "status"{ let cellView = KMBatchTableCellView(type: .Status) if (file.currentOperateType == .CreatePDF) { cellView.updateInterface(file: file, progress: file.progress ?? 0) } else { cellView.updateInterface(file: file, progress: file.progress ?? 0) } cellView.removeFileCallBack = { [weak self] file in self?.files.removeObject(file) self?.tableView.reloadData() } return cellView; } else if identifier?.rawValue == "size"{ let cellView = KMBatchTableCellView(type: .Size) cellView.updateInterface(file) return cellView; } else if identifier?.rawValue == "fileName"{ let cellView = KMBatchTableCellView(type: .FileName) cellView.updateInterface(file) let rowView: KMBatchTableRowView = tableView.rowView(atRow: row, makeIfNecessary: true) as! KMBatchTableRowView if ((file.error) != nil) { rowView.backgroundColor = KMAppearance.Status.errBGColor(); } return cellView; } else if identifier?.rawValue == "dpi"{ let cellView = KMBatchTableCellView(type: .DPI) cellView.updateInterface(file) return cellView; } else if identifier?.rawValue == "dimensions"{ let cellView = KMBatchTableCellView(type: .Size) if (file.fileType == .Image) { let image = NSImage(contentsOfFile: file.filePath) cellView.textField?.stringValue = String(Int(image?.size.width ?? 0)) + "x" + String(Int(image?.size.height ?? 0)) } return cellView; } return nil; } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { let file = self.files[row] if self.type == .CreatePDF { if (file.error != nil) { return 64 } else { return 40 } } else { if file.fileType == .PDF { if (file.error != nil) { return 64 } else { return 40 } } else { return 0.0000001 } } } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { let rowView = KMBatchTableRowView() return rowView } func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { let indexSetData = try? NSKeyedArchiver.archivedData(withRootObject: rowIndexes, requiringSecureCoding: true) pboard.declareTypes([NSPasteboard.PasteboardType.string], owner: self) pboard.setData(indexSetData, forType: NSPasteboard.PasteboardType(rawValue: KMBatchDragType) ) return true } func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation { var isCanDrag = false var result: NSDragOperation = [] let pboard = info.draggingPasteboard if pboard.availableType(from: [.fileURL]) != nil { guard let pbItems = pboard.pasteboardItems else { return NSDragOperation(rawValue: 0) } var hasValidFile = false for item in pbItems { guard let data = item.string(forType: .fileURL), let _url = URL(string: data) else { continue } var isDirectory: ObjCBool = false let fileExists = FileManager.default.fileExists(atPath: _url.path, isDirectory: &isDirectory) if fileExists && isDirectory.boolValue { let containFile = folderContainAvailableFile(_url.path) if containFile { isCanDrag = true break } } else { if let UTType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, _url.pathExtension as CFString, nil)?.takeRetainedValue() as String? { if self.type == .CreatePDF { if UTTypeConformsTo(UTType as CFString, kUTTypeImage) { isCanDrag = true } } else { if UTTypeConformsTo(UTType as CFString, kUTTypePDF) { isCanDrag = true } } } if isCanDrag { break } } } if isCanDrag { result = .copy } return result } else { return .move } } func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool { let pboard = info.draggingPasteboard if pboard.availableType(from: [.init(KMBatchDragType)]) != nil { guard let rowData = pboard.data(forType: .init(KMBatchDragType)), let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: rowData) as? NSIndexSet else { return false } let backUpArray = self.files var referenceIndex = -1 rowIndexes.enumerate(options: .reverse, using: { (idx, stop) in let sortFile = backUpArray[idx] if referenceIndex < 0 { if idx > row { self.files.remove(at: idx) self.files.insert(sortFile, at: row) } else if idx < row { if row > self.files.count { self.files.remove(at: idx) self.files.append(sortFile) } else { self.files.remove(at: idx) self.files.insert(sortFile, at: row - 1) } } referenceIndex = self.files.firstIndex(of: sortFile) ?? -1 } else { let currentIndex = self.files.firstIndex(of: sortFile) ?? -1 if currentIndex > referenceIndex { self.files.remove(at: currentIndex) self.files.insert(sortFile, at: referenceIndex) } else { referenceIndex -= 1 self.files.remove(at: currentIndex) self.files.insert(sortFile, at: referenceIndex) } } }) self.tableView.reloadData() return true } else if pboard.availableType(from: [.fileURL]) != nil { if (pboard.pasteboardItems == nil) { return true } let allFilesArray = NSMutableArray() for item in pboard.pasteboardItems! { let fileURL = item.string(forType: .fileURL) if (fileURL == nil) { continue } let path = URL.init(string: fileURL!) if (path == nil) { continue } var isFolder = ObjCBool(false) FileManager.default.fileExists(atPath: path!.path, isDirectory: &isFolder) if isFolder.boolValue { let containFiles = fetchAvailableFilesInFolder(path!.path) allFilesArray.addObjects(from: containFiles) } else { allFilesArray.add(path!.path) } } var insertArray = NSMutableArray() lockFilePathArr?.removeAllObjects() lockFileIndex = 0 for i in 0..<allFilesArray.count { let filePath: String = allFilesArray[i] as! String if filePath.hasSuffix(".pdf") || filePath.hasSuffix(".PDF") { let document = CPDFDocument(url: URL(fileURLWithPath: filePath)) if let pdf = CPDFDocument(url: URL(fileURLWithPath: filePath)) { if !pdf.allowsPrinting || !pdf.allowsCopying { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() continue } else if document?.isLocked ?? false { lockFilePathArr?.add(filePath) } else { let file = KMBatchOperateFile(filePath: filePath, type: self.type!) if !(self.files.contains(file) ) { insertArray.add(file) } } } } else { let file = KMBatchOperateFile(filePath: filePath, type: self.type!) if !(self.files.contains(file) ) { insertArray.add(file) } } } if KMMemberInfo.shared.isMemberAllFunction == false { if self.files.count < 1 && insertArray.count > 0 { let firstObject = insertArray.firstObject insertArray.removeAllObjects() insertArray.add(firstObject as Any) } else { KMMemberInfo.shared.advancedFunctionUsage(type: .batch) return false } } for i in 0..<insertArray.count { self.files.insert(insertArray[i] as! KMBatchOperateFile, at: row + i) } self.tableView.reloadData() if lockFilePathArr!.count > 0 { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.openPasswordWindow() } } return true } return false } func switchToOperateType(_ operateType: KMBatchOperationType, files: [KMBatchOperateFile]) { switchToOperateType(operateType) self.files = files self.tableView.reloadData() } func checkNeedPasswordSwitchToOperateType(_ operateType: KMBatchOperationType, files: [KMBatchOperateFile]) { switchToOperateType(operateType) var arr: [String] = [] for i in 0..<files.count { let file = files[i] arr.append(file.filePath) } self.files = files self.files.removeAll() addFilesToList(addArray: NSMutableArray.init(array: arr)) self.tableView.reloadData() } func reloadFile(_ file: KMBatchOperateFile) { var rowIndexSet = IndexSet() for i in 0..<self.files.count { if file.filePath == self.files[i].filePath { rowIndexSet.insert(i) break } } var columnIndexSet = IndexSet() for i in 0..<self.tableView.numberOfColumns { let identifier = self.tableView.tableColumns[i].identifier if identifier.rawValue == "status" { columnIndexSet.insert(i) break } } if Thread.isMainThread { self.tableView.reloadData(forRowIndexes: rowIndexSet, columnIndexes: columnIndexSet) } else { DispatchQueue.main.async { self.tableView.reloadData(forRowIndexes: rowIndexSet, columnIndexes: columnIndexSet) } } } func refreshConvertProgress(_ progress: CGFloat, file: KMBatchOperateFile) { self.tableView.reloadData() } func reloadConvertInterface(withType type: KMConvertWithPDFType) { if type == .WordAdvance || type == .WordStandard || type == .Excel || type == .PowerPoint || type == .RTF || type == .CSV || type == .HTML || type == .Text || type == .Json { self.DPIColumn.isHidden = true } else { self.DPIColumn.isHidden = false } self.tableView.reloadData() } } extension KMBatchOperateLeftViewController: NSMenuDelegate, NSMenuItemValidation{ func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { let action = menuItem.action if action == #selector(menuItem_ShowInFinder(_:)) || action == #selector(menuItem_Delete(_:)) { if tableView.clickedRow == -1 { return false } return true } return true } }