// // KMBatchOperateLeftViewController.swift // PDF Reader Pro // // Created by kdanmobile on 2023/10/26. // import Cocoa import KMComponentLibrary let KMBatchDragType = "KMBatchDragType" class KMBatchOperateLeftViewController: KMNBaseViewController { @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 private var addFileButton_: ComponentDropdown? private var deleteButton_: ComponentButton? private var groupView_: ComponentGroup? private var emptyViewTopLine: NSView = { let view = NSView() view.wantsLayer = true return view }() private var emptyView_: ComponentEmpty = { let view = ComponentEmpty() view.properties = ComponentEmptyProperty(emptyType: .add_File, state: .normal, image: NSImage(named: "KMEmptyIcon"), text: KMLocalizedString("Select Files"), subText: KMLocalizedString("Drop files here or Click Add Files at upper left corner. You can drag files to reorder as you need.")) return view }() private var dividerColor_: NSColor? private var isSizeAsc_ = false private var dimensionsAsc_ = false private var fileNameAsc_ = false deinit { DistributedNotificationCenter.default().removeObserver(self) } override func viewDidLoad() { super.viewDidLoad() for i in 0..= 1 { let winC = KMPurchaseCompareWindowController.sharedInstance() if type == .CreatePDF { winC?.kEventName = "Onbrd_ImagetoPDF_BuyNow" } winC?.showWindow(nil) return } } #endif self.progressInt = 0 let panel = NSOpenPanel() if type == .CreatePDF { panel.allowedFileTypes = KMImageToPDFMethod.supportedImageTypes() } else { panel.allowedFileTypes = ["pdf", "PDF"] } if IAPProductsManager.default().isAvailableAllFunction() { panel.allowsMultipleSelection = true panel.canChooseDirectories = true } panel.canChooseFiles = true #if VERSION_FREE #else panel.message = KMLocalizedString("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.. 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() } // MARK: - Actions 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 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 { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("Clear All Recents", comment: "")+"?" alert.addButton(withTitle: KMLocalizedString("Delete", comment: "")) alert.addButton(withTitle: KMLocalizedString("Cancel", comment: "")) alert.beginSheetModal(for: self.view.window!) {[weak self] response in if response == NSApplication.ModalResponse.alertFirstButtonReturn { self?.files.removeAll() self?.tableView.reloadData() } } } } func fetchAvailableFilesInFolder(_ folderPath: String) -> [String] { var array: [String] = [] let subFileArray = FileManager().subpaths(atPath: folderPath) for i in 0.. Bool { var containFile = false guard let subFileArray = FileManager.default.subpaths(atPath: folderPath) else { return containFile } for i in 0..?) -> CPDFDocument? { var document: CPDFDocument? = nil var data: Data? = nil if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) { data = pboard.data(forType: NSPasteboard.PasteboardType.pdf) } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.postScript.rawValue]) { data = pboard.data(forType: NSPasteboard.PasteboardType.postScript) } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) { data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff) ?? Data()) } else { let images = pboard.readObjects(forClasses: [NSImage.self], options: [:]) let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:]) if images?.count ?? 0 > 0 { data = convertTIFFDataToPDF((images![0] as AnyObject).tiffRepresentation!) } else if strings?.count ?? 0 > 0 { data = KMOCTool.convertStringsToPDF(withString: strings ?? [""]) // convertStringsToPDF(strings!) } } if let data = data { document = CPDFDocument(data: data) } else if let outError = outError { outError.pointee = NSError(domain: "SKDocumentErrorDomain", code: 3, userInfo: [NSLocalizedDescriptionKey: KMLocalizedString("Unable to load data from clipboard", comment: "Error description")]) } return document } func convertTIFFDataToPDF(_ tiffData: Data) -> Data? { guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil } let pdfData = NSMutableData(capacity: tiffData.count) let consumer = CGDataConsumer(data: pdfData! as CFMutableData)! var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height)) let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil) ctxt!.beginPDFPage(nil) ctxt!.draw(cgImage, in: rect) ctxt!.endPDFPage() ctxt!.closePDF() return pdfData as? Data } // MARK: - Private Methods private func _saveImagePath() -> String { let rootPath = KMDataManager.fetchAppSupportOfBundleIdentifierDirectory() let path = rootPath.appendingPathComponent("ImageToPDF").path if FileManager.default.fileExists(atPath: path) == false { try?FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false) } return path } private func _clearImageData() { let path = self._saveImagePath() if FileManager.default.fileExists(atPath: path) { try?FileManager.default.removeItem(atPath: path) } } private func _initHeaderCellView(cellView: KMNTableHeaderCellView) { var dividerColor = self.dividerColor_ if dividerColor == nil { dividerColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider") } cellView.leftLine.wantsLayer = true cellView.leftLine.layer?.backgroundColor = dividerColor?.cgColor ?? .black cellView.rightLine.wantsLayer = true cellView.rightLine.layer?.backgroundColor = dividerColor?.cgColor ?? .black cellView.bottomLine.wantsLayer = true cellView.bottomLine.layer?.backgroundColor = dividerColor?.cgColor ?? .black } private func _addFolderAction() { let openPanel = NSOpenPanel() // openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "") openPanel.canChooseDirectories = true openPanel.canChooseFiles = false openPanel.allowsMultipleSelection = true openPanel.beginSheetModal(for: view.window!, completionHandler: { [self] result in if result != .OK { } else { var result: [URL] = [] for folderURL in openPanel.urls { _findAllFiles(folder: folderURL, result: &result) } var paths: [String] = [] for url in result { paths.append(url.path) } self.addFilesToList(addArray: NSMutableArray(array: paths)) } }) } private func _findAllFiles(folder: URL, result: inout [URL]) { let fileManager = FileManager.default var isDirectory: ObjCBool = ObjCBool(false) fileManager.fileExists(atPath: folder.path, isDirectory: &isDirectory) if (!isDirectory.boolValue) { return } let contents = try?fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil) if contents?.count == 0 { return } let array = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif","ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic"] for documentURL in contents! { var isDirectory: ObjCBool = ObjCBool(false) fileManager.fileExists(atPath: documentURL.path, isDirectory: &isDirectory) if (isDirectory.boolValue) { _findAllFiles(folder: documentURL, result: &result) } else { if !array.contains(documentURL.pathExtension.lowercased()) { continue } result.append(documentURL) } } } 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.. Int { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMBatchFilesCountNotification"), object: self.files, userInfo: [kObjectKey : self]) self.deleteFileButton.isEnabled = self.files.count > 0 deleteButton_?.properties.isDisabled = self.files.count <= 0 self.blankView.isHidden = self.files.count > 0 if self.files.count == 0 { return 0 } return self.files.count + 1; } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let identifier = tableColumn?.identifier let rowIdx = max(0, row-1) let file = self.files[rowIdx] let cellColor = ComponentLibrary.shared.getComponentColorFromKey("olorFill/4") let titleFont = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") let titleColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/1") if identifier?.rawValue == "index" { if row == 0 { let cellView = KMNTableHeaderCellView() cellView.wantsLayer = true cellView.layer?.backgroundColor = cellColor.cgColor // cellView.layer?.backgroundColor = NSColor(hex: "#F6F6F8").cgColor cellView.titleLabel.stringValue = KMLocalizedString("") _initHeaderCellView(cellView: cellView) return cellView } let cellView = KMBatchTableCellView(type: .Size) _ = row + 1 cellView.textField?.stringValue = String(format: "%d", row); return cellView; } else if identifier?.rawValue == "pageRange"{ if (file.currentOperateType == .CreatePDF) { if row == 0 { let cellView = KMNTableHeaderCellView() cellView.wantsLayer = true cellView.layer?.backgroundColor = cellColor.cgColor cellView.titleLabel.stringValue = KMLocalizedString("Dimensions") cellView.titleLabel.font = titleFont cellView.titleLabel.textColor = titleColor _initHeaderCellView(cellView: cellView) cellView.itemClick = { [weak self] idx, _ in if idx == 1 { // 排序 let asc = self?.dimensionsAsc_ ?? false if asc { self?.files.sort(){$0.dimensions > $1.dimensions} } else { self?.files.sort(){$0.dimensions <= $1.dimensions} } self?.dimensionsAsc_ = !asc self?.reloadData() } } return cellView } 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)) file.dimensions = Float((image?.size.width ?? 0) * (image?.size.height ?? 0)) } return cellView; } else { let cellView = KMBatchTableCellView(type: .PageRange) cellView.updateInterface(file) return cellView; } } else if identifier?.rawValue == "status"{ if row == 0 { let cellView = KMNTableHeaderCellView() cellView.wantsLayer = true cellView.layer?.backgroundColor = cellColor.cgColor cellView.titleLabel.stringValue = KMLocalizedString("State") cellView.titleLabel.font = titleFont cellView.titleLabel.textColor = titleColor _initHeaderCellView(cellView: cellView) return cellView } 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"{ if row == 0 { let cellView = KMNTableHeaderCellView() cellView.wantsLayer = true cellView.layer?.backgroundColor = cellColor.cgColor cellView.titleLabel.stringValue = KMLocalizedString("Size") cellView.titleLabel.font = titleFont cellView.titleLabel.textColor = titleColor _initHeaderCellView(cellView: cellView) cellView.itemClick = { [weak self] idx, _ in if idx == 1 { // 排序 let asc = self?.isSizeAsc_ ?? false if asc { self?.files.sort(){$0.fileSize > $1.fileSize} } else { self?.files.sort(){$0.fileSize <= $1.fileSize} } self?.isSizeAsc_ = !asc self?.reloadData() } } return cellView } let cellView = KMBatchTableCellView(type: .Size) cellView.updateInterface(file) return cellView; } else if identifier?.rawValue == "fileName"{ if row == 0 { let cellView = KMNTableHeaderCellView() cellView.wantsLayer = true cellView.layer?.backgroundColor = cellColor.cgColor cellView.titleLabel.stringValue = KMLocalizedString("File Name") cellView.titleLabel.font = titleFont cellView.titleLabel.textColor = titleColor _initHeaderCellView(cellView: cellView) cellView.itemClick = { [weak self] idx, _ in if idx == 1 { // 排序 let asc = self?.fileNameAsc_ ?? false if asc { self?.files.sort(){$0.filePath.lastPathComponent > $1.filePath.lastPathComponent} } else { self?.files.sort(){$0.filePath.lastPathComponent <= $1.filePath.lastPathComponent} } self?.fileNameAsc_ = !asc self?.reloadData() } } return cellView } let cellView = KMBatchTableCellView(type: .FileName) cellView.updateInterface(file) cellView.fileIv?.wantsLayer = true cellView.fileIv?.layer?.borderWidth = 1 cellView.fileIv?.layer?.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/3-default").cgColor 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"{ if row == 0 { let cellView = KMNTableHeaderCellView() cellView.wantsLayer = true cellView.layer?.backgroundColor = cellColor.cgColor cellView.titleLabel.stringValue = KMLocalizedString("Dimensions") cellView.titleLabel.font = titleFont cellView.titleLabel.textColor = titleColor _initHeaderCellView(cellView: cellView) return cellView } 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 rowIdx = max(0, row-1) let file = self.files[rowIdx] if self.type == .CreatePDF { if row == 0 { return 32 } if (file.error != nil) { return 104 } else { return 80 } } 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? { if row == 0 { let rowView = KMBatchTableRowView() rowView.selectionBackgroundColorBlock = { return .clear } rowView.selectionHighlightStyle = .none rowView.isSelected = false return rowView } let rowView = KMBatchTableRowView() return rowView } func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { if rowIndexes.first == 0 { return false } var theIndex = IndexSet() for idx in rowIndexes { theIndex.insert(idx-1) } let indexSetData = try? NSKeyedArchiver.archivedData(withRootObject: theIndex, 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 { if row == 0 { return NSDragOperation(rawValue: 0) } 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 theIdx = max(0, idx) let sortFile = backUpArray[theIdx] let theRow = row-1 if referenceIndex < 0 { if idx > theRow { self.files.remove(at: idx) self.files.insert(sortFile, at: theRow) } else if idx < theRow { if theRow > self.files.count { self.files.remove(at: idx) self.files.append(sortFile) } else { self.files.remove(at: idx) self.files.insert(sortFile, at: theRow - 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.. 0 { let firstObject = insertArray.firstObject insertArray.removeAllObjects() insertArray.add(firstObject as Any) } else { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) return false } } for i in 0.. 0 { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.openPasswordWindow() } } return true } return false } } // MARK: - NSMenuDelegate, NSMenuItemValidation 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 } } //MARK: - ComponentDropdownDelegate extension KMBatchOperateLeftViewController: ComponentDropdownDelegate { func componentDropdownDidShowMenuItem(dropdown: ComponentDropdown) { showGroupView() } } //MARK: - ComponentGroupDelegate extension KMBatchOperateLeftViewController: ComponentGroupDelegate { func componentGroupDidDismiss(group: ComponentGroup?) { removeGroupView() } func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) { if let selItem = menuItemProperty { let index = group?.menuItemArr.firstIndex(of: selItem) if index == 0 { chooseFile() } else if index == 1 { _addFolderAction() } else if index == 2 { let pboard = NSPasteboard.general if let document = self.openDocumentWithImageFromPasteboard(pboard, error: nil) { // Document opened successfully if let page = document.page(at: 0) { let data = page.PDFListViewTIFFData(for: page.bounds) var path = self._saveImagePath() + "/Untitled.png" path = KMTools.getUniqueFilePath(filePath: path) try?data?.write(to: URL(fileURLWithPath: path), options: .atomic) self.addFilesToList(addArray: [path]) } } } else if index == 3 { chooseFileFromCamera() } } } }