// // KMHomeHistoryFileViewController.swift // PDF Master // // Created by wanjun on 2022/10/28. // import Cocoa public enum HistoryFileShowMode : Int { case Thumbnail = 0 case List } @objc protocol KMHomeHistoryFileViewControllerDelegate { @objc optional func historyFileViewController(_ viewController: KMHomeHistoryFileViewController, deleteDocuments indexPaths: [URL]) @objc optional func historyFileViewController(_ viewController: KMHomeHistoryFileViewController, didSelectItemsAt indexPaths: [URL]) } class KMHomeHistoryFileTableviewCell: NSTableCellView { @IBOutlet weak var fileImageView: NSImageView! @IBOutlet weak var documentName: NSTextField! @IBOutlet weak var documentType: NSTextField! @IBOutlet weak var documentSize: NSTextField! @IBOutlet weak var moreButton: NSButton! @IBOutlet weak var lastModificationTime: NSTextField! @IBOutlet weak var mainBox: KMBox! var file: URL? var selectUrls: [URL] = [] var isSelect: Bool = false var currentWindowController: NSWindowController? // MARK: Init override func awakeFromNib() { super.awakeFromNib() mainBox.menu = tableCellMenu documentName.maximumNumberOfLines = 1 mainBox.moveCallback = { [unowned self](mouseEntered: Bool, mouseBox: KMBox) -> Void in if !self.isSelect { if mouseEntered { self.documentName.textColor = NSColor(hex: "#252629") self.documentType.textColor = NSColor(hex: "#94989C") self.documentSize.textColor = NSColor(hex: "#94989C") self.lastModificationTime.textColor = NSColor(hex: "#94989C") self.mainBox.fillColor = NSColor(hex: "#EDEEF0") self.mainBox.borderWidth = 0 self.mainBox.cornerRadius = 4.0 } else { self.documentName.textColor = NSColor(hex: "#252629") self.documentType.textColor = NSColor(hex: "#94989C") self.documentSize.textColor = NSColor(hex: "#94989C") self.lastModificationTime.textColor = NSColor(hex: "#94989C") self.mainBox.fillColor = .clear self.mainBox.borderWidth = 0 self.mainBox.cornerRadius = 0.0 } } } } // MARK: Private Methods func initializeUI(_ url: URL) -> Void { file = url let attrib = try? FileManager.default.attributesOfItem(atPath: url.path) as? Dictionary if attrib != nil { let dateFormatter: DateFormatter = DateFormatter.init() let fileDate: Date = attrib![FileAttributeKey(rawValue: "NSFileModificationDate")] as! Date var fileTime: String = "" if fileDate.isToday() { dateFormatter.dateFormat = "HH:mm" } else if isSameWeek(withDate: fileDate) { dateFormatter.dateFormat = "EEE, HH:mm" } else { dateFormatter.dateFormat = "MMM d, yyyy" } let fileName = url.lastPathComponent let fileType = url.pathExtension.isEmpty ? "" : url.pathExtension let sizeFloat: Float = attrib![FileAttributeKey(rawValue: "NSFileSize")] as? Float ?? 0.0 let fileSize = fileSizeString(sizeFloat).isEmpty ? "" : fileSizeString(sizeFloat) let lastTime = dateFormatter.string(from: fileDate) if fileDate.isToday() { fileTime = String(format: "%@, %@", NSLocalizedString("Today", comment: ""), lastTime) } else if isSameWeek(withDate: fileDate) { fileTime = lastTime } else { fileTime = lastTime } let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = 22.0 documentName.stringValue = fileName // documentName.attributedStringValue = NSAttributedString(string: fileName, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) documentType.attributedStringValue = NSAttributedString(string: fileType, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) documentSize.attributedStringValue = NSAttributedString(string: fileSize, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) lastModificationTime.attributedStringValue = NSAttributedString(string: fileTime, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) mainBox.toolTip = fileName if selectUrls.contains(url) { isSelect = true mainBox.fillColor = NSColor(hex: "#CED0D4", alpha: 0.6) mainBox.borderWidth = 1.0 mainBox.borderColor = NSColor(hex: "#CED0D4") mainBox.cornerRadius = 4.0 } else { isSelect = false mainBox.fillColor = .clear mainBox.borderWidth = 0.0 mainBox.cornerRadius = 0.0 } documentName.backgroundColor = .clear documentName.textColor = NSColor(hex: "#252629") documentName.font = NSFont(name: "SFProText-Regular", size: 14) documentType.textColor = NSColor(hex: "#94989C") documentSize.textColor = NSColor(hex: "#94989C") documentName.backgroundColor = .clear lastModificationTime.textColor = NSColor(hex: "#94989C") lastModificationTime.backgroundColor = .clear moreButton.image = NSImage(named: "KMHomeMoreTools") let image: NSImage = NSImage.previewForFile(path: url, ofSize: fileImageView.frame.size, asIcon: true) ?? NSImage() fileImageView.image = image } } func highlightCell(_ rows: Array, _ row: Int) -> Void { for i in rows { if i == row { mainBox.fillColor = NSColor(hex: "#CED0D4", alpha: 0.6) mainBox.borderWidth = 1.0 mainBox.borderColor = NSColor(hex: "#CED0D4") } } } func fileSizeString(_ fSize: Float) -> String { let fileSize = fSize / 1024 let size = fileSize >= 1024 ? (fileSize < 1048576 ? fileSize/1024 : fileSize/1048576.0) : fileSize let unit = fileSize >= 1024 ? (fileSize < 1048576 ? "M" : "G") : "K" return String(format: "%0.1f %@", size, unit) } func isSameWeek (withDate date: Date) -> Bool { let currentWeekOfYear = getWeekOfYear(date: Date.init()) let targetWeekOfYear = getWeekOfYear(date: date) if targetWeekOfYear == currentWeekOfYear { return false } else { return true } } func getWeekOfYear(date: Date) -> Int { let components = Calendar.current.dateComponents([Calendar.Component.weekOfYear], from: date) return components.weekOfYear ?? 0 } // MARK: Menu lazy var tableCellMenu: NSMenu = { let tableCellMenu = NSMenu() var item = NSMenuItem() item.title = NSLocalizedString("Show in Finder", comment: "") item.action = #selector(buttonItemClick_ShowPath) tableCellMenu.addItem(item) item = NSMenuItem() item.title = NSLocalizedString("Remove from Recents", comment: "") item.action = #selector(buttonItemClick_ClosePath) tableCellMenu.addItem(item) return tableCellMenu }() // MARK: Action @IBAction func moreButtonAction(_ sender: NSButton) { let popViewDataArr = [NSLocalizedString("Show in Finder", comment: ""), NSLocalizedString("Remove from Recents", comment: "")] let vc: KMHomePopViewController = KMHomePopViewController().initWithPopViewDataArr(popViewDataArr) let createFilePopover: NSPopover = NSPopover.init() createFilePopover.contentViewController = vc createFilePopover.animates = true createFilePopover.behavior = .semitransient createFilePopover.setValue(true, forKey: "shouldHideAnchor") createFilePopover.show(relativeTo: CGRect(x: moreButton.bounds.origin.x, y: 10, width: moreButton.bounds.size.width, height: moreButton.bounds.size.height), of: moreButton, preferredEdge: .minY) vc.customBox.fillColor = NSColor(hex: "#F6F6F6", alpha: 0.6) vc.downCallback = { [weak self](downEntered: Bool, count: String) -> Void in if self != nil { if downEntered { if count == NSLocalizedString("Show in Finder", comment: "") { self!.buttonItemClick_ShowPath(self!.moreButton as Any) } else if count == NSLocalizedString("Remove from Recents", comment: "") { self!.buttonItemClick_ClosePath(self!.moreButton as Any) } } } } } @IBAction func buttonItemClick_ShowPath(_ sender: Any) { if FileManager.default.fileExists(atPath: file!.path) { NSWorkspace.shared.activateFileViewerSelecting([file!]) } } @IBAction func buttonItemClick_ClosePath(_ sender: Any) { var selects: [URL] = [] if selectUrls.count > 0 { for selecturl in self.selectUrls { selects.append(selecturl) } } else { selects.append(file!) } if UserDefaults.standard.bool(forKey: "kHistoryDeleteNOReminderKey") { historyFileDeleteAction(selects) } else { let historyFileDeleteVC: KMHistoryFileDeleteWindowController = KMHistoryFileDeleteWindowController.init(windowNibName: NSNib.Name("KMHistoryFileDeleteWindowController")) historyFileDeleteVC.indexPaths = selects self.currentWindowController = historyFileDeleteVC historyFileDeleteVC.deleteCallback = { [weak self](indexPaths: [URL], windowController: KMHistoryFileDeleteWindowController) -> Void in if self != nil { self?.currentWindowController = nil self!.historyFileDeleteAction(indexPaths) } } self.window?.beginSheet(historyFileDeleteVC.window!) } } func historyFileDeleteAction(_ indexPaths: [URL]) -> Void { let urls: Array = NSDocumentController.shared.recentDocumentURLs NSDocumentController.shared.clearRecentDocuments(nil) DispatchQueue.main.asyncAfter(deadline: .now()) { [self] in for (_, url) in urls.enumerated() { if !indexPaths.contains(url) { NSDocumentController.shared.noteNewRecentDocumentURL(url) } } NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "KMHomeFileRectChange"), object: self.window) } } } class KMHomeHistoryFileViewController: NSViewController, NSCollectionViewDelegate, NSCollectionViewDataSource, NSCollectionViewDelegateFlowLayout, NSTableViewDelegate, NSTableViewDataSource { @IBOutlet weak var historyFileLabel: NSTextField! @IBOutlet weak var modeBox: NSBox! @IBOutlet weak var modeBoxHeight: NSLayoutConstraint! @IBOutlet weak var thumbnailBox: KMBox! @IBOutlet weak var thumbnailImageView: NSImageView! @IBOutlet weak var listBox: KMBox! @IBOutlet weak var listImageView: NSImageView! @IBOutlet weak var deleteBox: KMBox! @IBOutlet weak var deleteBoxHeight: NSLayoutConstraint! @IBOutlet weak var deleteImageView: NSImageView! @IBOutlet weak var thumbnailSCrollView: NSScrollView! @IBOutlet weak var historyFileCollectionView: KMHistoryFileCollectionView! @IBOutlet weak var listScrollView: NSScrollView! @IBOutlet weak var historyFileTableView: KMHistoryFileTableView! @IBOutlet weak var emptyMainBox: NSBox! @IBOutlet weak var emptyBox: NSBox! @IBOutlet weak var emptyImageView: NSImageView! @IBOutlet weak var emptyTitleLabel: NSTextField! @IBOutlet weak var emptySubtitleLabel: NSTextField! @IBOutlet weak var emptyHovBox: KMMoveBox! var files: [Any] = [] var selectFiles: [URL] = [] var selectFiles_shift: [Int] = [] var showMode: HistoryFileShowMode! open weak var delete: KMHomeHistoryFileViewControllerDelegate? var allowMultipleChoices_cmd: Bool! var allowMultipleChoices_shift: Bool! var multipleChoices: [KMBox] = [] var multipleChoicesInts: [Int] = [] var deleteButtonVC: KMDesignButton! // MARK: Init override func viewDidLoad() { super.viewDidLoad() // Do view setup here. deleteButtonVC = KMDesignButton.init(withType: .Image) historyFileCollectionView.register(KMHistoryFileCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMHistoryFileCollectionViewItem")) initializeUI() initLocalization() allowMultipleChoices_cmd = false allowMultipleChoices_shift = false NotificationCenter.default.addObserver(self, selector: #selector(willBecomeActive), name: NSNotification.Name(rawValue: "KMApplicationWillBecomeActive"), object: nil) if UserDefaults.standard.bool(forKey: "kFileListViewListModeKey") { showMode = .List } else { showMode = .Thumbnail } refreshMode() self.listBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in if self != nil { if downEntered { if (self!.showMode == .Thumbnail) { self!.showMode = .List self!.refreshMode() } } } } self.thumbnailBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in if self != nil { if downEntered { if (self!.showMode == .List) { self!.showMode = .Thumbnail self!.refreshMode() } } } } self.deleteBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in if self != nil { if self!.deleteButtonVC.enabled { if downEntered { self!.deleteButtonVC.state = .Sel } else { self!.deleteButtonVC.state = .Norm } self!.deleteButtonVC.updateUI() } } } self.emptyHovBox.move = { [unowned self](mouseEntered: Bool) -> Void in if mouseEntered { emptyImageView.image = NSImage(named: "icon_empty_add_hov") } else { emptyImageView.image = NSImage(named: "icon_empty_add_norm") } } } override func viewDidAppear() { super.viewDidAppear() reloadData() } func initializeUI() { deleteBox.fillColor = .clear deleteBox.contentView = deleteButtonVC.view deleteButtonVC.target = self deleteButtonVC.action = #selector(deleteAction(_:)) deleteButtonVC.image = NSImage(named: "icon_btn_clear_false_norm")! deleteButtonVC.button(type: .Sec, size: .m, height: deleteBoxHeight) historyFileLabel.font = NSFont(name: "SFProText-Semibold", size: 20) historyFileLabel.textColor = NSColor(red: 37/255.0, green: 38/255.0, blue: 41/255.0, alpha: 1.0) modeBox.fillColor = KMDesignToken.shared.fill(withToken: "segmented.bg") modeBox.cornerRadius = KMDesignToken.shared.borderRadius(withToken: "segmented.bg").stringToCGFloat() emptyImageView.image = NSImage(named: "icon_empty_add_norm") emptyTitleLabel.textColor = NSColor(hex: "#616469") emptyTitleLabel.font = NSFont(name: "SFProText-Regular", size: 14.0) emptySubtitleLabel.textColor = NSColor(hex: "#94989C") emptySubtitleLabel.font = NSFont(name: "SFProText-Regular", size: 12.0) } func initLocalization() { let fastToolParagraphStyle = NSMutableParagraphStyle() fastToolParagraphStyle.lineSpacing = 28.0 historyFileLabel.attributedStringValue = NSAttributedString(string: NSLocalizedString("Recent", comment: ""), attributes: [NSAttributedString.Key.paragraphStyle: fastToolParagraphStyle]) emptyTitleLabel.stringValue = NSLocalizedString("No recently opened files", comment: "") emptySubtitleLabel.stringValue = NSLocalizedString("Click to open the file or drag the file directly here to open the file.", comment: "") } // MARK: Get && Set // MARK: Private Methods func refreshMode() { switch showMode { case .Thumbnail: listBox.fillColor = KMDesignToken.shared.fill(withToken: "segmented.bg-item.unsel") listBox.cornerRadius = KMDesignToken.shared.borderRadius(withToken: "segmented.bg").stringToCGFloat() thumbnailBox.fillColor = KMDesignToken.shared.fill(withToken: "segmented.bg-item.sel") thumbnailBox.cornerRadius = KMDesignToken.shared.borderRadius(withToken: "segmented.bg").stringToCGFloat() listScrollView.isHidden = true thumbnailSCrollView.isHidden = false UserDefaults.standard.setValue(false, forKey: "kFileListViewListModeKey") break case .List: listBox.fillColor = KMDesignToken.shared.fill(withToken: "segmented.bg-item.sel") listBox.cornerRadius = KMDesignToken.shared.borderRadius(withToken: "segmented.bg").stringToCGFloat() thumbnailBox.fillColor = KMDesignToken.shared.fill(withToken: "segmented.bg-item.unsel") thumbnailBox.cornerRadius = KMDesignToken.shared.borderRadius(withToken: "segmented.bg").stringToCGFloat() listScrollView.isHidden = false thumbnailSCrollView.isHidden = true UserDefaults.standard.setValue(true, forKey: "kFileListViewListModeKey") break default: break } UserDefaults.standard.synchronize() reloadData() } func reloadData() -> Void { files.removeAll() for url in NSDocumentController.shared.recentDocumentURLs { if FileManager.default.fileExists(atPath: url.path) { self.files.append(url) } } let fileNumber = KMPreferenceManager.shared.getData(forKey: KMPreference.documentMaximunDisplayNumberKey) as? Int ?? 10 if fileNumber <= files.count { let arr1 = files.prefix(fileNumber) self.files = Array(arr1) } thumbnailSCrollView.isHidden = true listScrollView.isHidden = true emptyMainBox.isHidden = true if files.count > 0 { deleteButtonVC.enabled = true deleteButtonVC.state = .Norm if showMode == .Thumbnail { thumbnailSCrollView.isHidden = false historyFileCollectionView.reloadData() } else { listScrollView.isHidden = false historyFileTableView.reloadData() } } else { deleteButtonVC.enabled = false deleteButtonVC.state = .Disabled emptyMainBox.isHidden = false historyFileCollectionView.reloadData() historyFileTableView.reloadData() } deleteButtonVC.updateUI() } func multipleChoicesAction(choiceBox box: KMBox, choiceRow row: Int) -> Void { if allowMultipleChoices_cmd { if multipleChoices.contains(box) { box.fillColor = .clear multipleChoices.removeObject(box) } else { multipleChoices.append(box) } for box in multipleChoices { box.fillColor = NSColor(red: 37/255.0, green: 139/255.0, blue: 251/255.0, alpha: 1.0) } } else if allowMultipleChoices_shift { for box in multipleChoices { box.fillColor = NSColor(red: 37/255.0, green: 139/255.0, blue: 251/255.0, alpha: 1.0) } } else { for iBox in multipleChoices { iBox.fillColor = .clear } multipleChoices.removeAll() multipleChoices.append(box) box.fillColor = NSColor(red: 37/255.0, green: 139/255.0, blue: 251/255.0, alpha: 1.0) } multipleChoicesIntsAction(choiceRow: row) } func multipleChoicesIntsAction(choiceRow row: Int) -> Void { if allowMultipleChoices_cmd { if multipleChoicesInts.contains(row) { multipleChoicesInts.removeObject(row) } else { multipleChoicesInts.append(row) } } else if allowMultipleChoices_shift { } else { multipleChoicesInts.removeAll() multipleChoicesInts.append(row) } } override func flagsChanged(with event: NSEvent) { super.flagsChanged(with: event) if event.type == .flagsChanged { if event.keyCode == 55 { // cmd if allowMultipleChoices_cmd { selectFiles_shift.removeAll() selectFiles.removeAll() allowMultipleChoices_cmd = false } else { allowMultipleChoices_cmd = true allowMultipleChoices_shift = false } } else if event.keyCode == 56 { // shift if allowMultipleChoices_shift { selectFiles_shift.removeAll() selectFiles.removeAll() allowMultipleChoices_shift = false } else { allowMultipleChoices_shift = true allowMultipleChoices_cmd = false } } } } @objc func willBecomeActive() { self.reloadData() } // MARK: Action @IBAction func deleteAction(_ sender: NSButton) -> Void { if selectFiles.count == 0 { for url in NSDocumentController.shared.recentDocumentURLs { if FileManager.default.fileExists(atPath: url.path) { selectFiles.append(url) } } self.delete?.historyFileViewController!(self, deleteDocuments: selectFiles) } else if selectFiles.count > 0 { // let urls: Array = NSDocumentController.shared.recentDocumentURLs // NSDocumentController.shared.clearRecentDocuments(nil) // DispatchQueue.main.asyncAfter(deadline: .now()) { [self] in // for (_, url) in urls.enumerated() { // if !selectFiles.contains(url) { // NSDocumentController.shared.noteNewRecentDocumentURL(url) // } // } // NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "KMHomeFileRectChange"), object: NSApp.mainWindow) // } self.delete?.historyFileViewController!(self, deleteDocuments: selectFiles) } } @IBAction func openFileAction(_ sender: NSButton) { let openPanel = NSOpenPanel() openPanel.allowedFileTypes = ["pdf", "PDF"] openPanel.allowsMultipleSelection = true openPanel.beginSheetModal(for: self.view.window!) { result in if result == .OK { for url in openPanel.urls { if !url.path.isPDFValid() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() return } NSDocumentController.shared.openDocument(withContentsOf: url, display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) } else { } } } } } } // MARK: NSCollectionViewDataSource func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { return files.count } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { if collectionView.isEqual(to: historyFileCollectionView) { let item: KMHistoryFileCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMHistoryFileCollectionViewItem"), for: indexPath) as! KMHistoryFileCollectionViewItem if (indexPath.item > files.count) { return item } let i: Int = indexPath.item let url: URL = files[i] as! URL item.selectUrls = selectFiles item.refreshUI(url) item.mainBox.downCallback = { [unowned self](downEntered: Bool, mouseBox: KMBox, event) -> Void in if self != nil { if downEntered { if self.allowMultipleChoices_shift { if self.selectFiles_shift.count == 0 { self.selectFiles.append(url) self.selectFiles_shift.append(i) } else if self.selectFiles_shift.count == 1 { let first = self.selectFiles_shift[0] as Int self.selectFiles.removeAll() if first > i { for path in self.files[i...first] { self.selectFiles.append(path as! URL) } } else { for path in self.files[first...i] { self.selectFiles.append(path as! URL) } } self.selectFiles_shift.append(i) } else if self.selectFiles_shift.count == 2 { let first = self.selectFiles_shift[0] as Int self.selectFiles.removeAll() if first > i { for path in self.files[i...first] { self.selectFiles.append(path as! URL) } } else { for path in self.files[first...i] { self.selectFiles.append(path as! URL) } } self.selectFiles_shift[1] = i } } else if self.allowMultipleChoices_cmd { if self.selectFiles.contains(url) { self.selectFiles.removeObject(url) } else { self.selectFiles.append(url) } if self.selectFiles_shift.contains(i) { self.selectFiles_shift.removeObject(i) } else { self.selectFiles_shift.append(i) } } else { self.selectFiles.removeAll() self.selectFiles_shift.removeAll() self.selectFiles.append(url) self.selectFiles_shift.append(i) } collectionView.reloadData() } } } item.mainBox.doubleCallback = { [unowned self](downEntered: Bool, mouseBox: KMBox) -> Void in if self != nil { if downEntered { self.selectFiles.removeAll() var indexs: [URL] = [] let index: URL = self.files[i] as! URL indexs.append(index) self.delete?.historyFileViewController!(self, didSelectItemsAt: indexs) } } } return item } return NSCollectionViewItem.init() } // MARK: NSCollectionViewDelegate func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set) { } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { if collectionView.isEqual(to: historyFileCollectionView) { return CGSize(width: 226, height: 248) } return CGSize(width: 226, height: 248) } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 16 } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 16 } // MARK: NSTableViewDelegate func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { return 72.0; } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let url: URL = files[row] as! URL let identifier = tableColumn?.identifier let cellView: KMHomeHistoryFileTableviewCell = tableView.makeView(withIdentifier:identifier!, owner: self) as! KMHomeHistoryFileTableviewCell cellView.selectUrls = selectFiles cellView.initializeUI(url) cellView.highlightCell(multipleChoicesInts, row) cellView.mainBox.downCallback = { [unowned self](downEntered: Bool, mouseBox: KMBox, event) -> Void in if self != nil { if downEntered { if self.allowMultipleChoices_shift { if self.selectFiles_shift.count == 0 { self.selectFiles.append(url) self.selectFiles_shift.append(row) } else if self.selectFiles_shift.count == 1 { let first = self.selectFiles_shift[0] as Int self.selectFiles.removeAll() if first > row { for path in self.files[row...first] { self.selectFiles.append(path as! URL) } } else { for path in self.files[first...row] { self.selectFiles.append(path as! URL) } } self.selectFiles_shift.append(row) } else if self.selectFiles_shift.count == 2 { let first = self.selectFiles_shift[0] as Int self.selectFiles.removeAll() if first > row { for path in self.files[row...first] { self.selectFiles.append(path as! URL) } } else { for path in self.files[first...row] { self.selectFiles.append(path as! URL) } } self.selectFiles_shift[1] = row } } else if self.allowMultipleChoices_cmd { if self.selectFiles.contains(url) { self.selectFiles.removeObject(url) } else { self.selectFiles.append(url) } if self.selectFiles_shift.contains(row) { self.selectFiles_shift.removeObject(row) } else { self.selectFiles_shift.append(row) } } else { self.selectFiles.removeAll() self.selectFiles_shift.removeAll() self.selectFiles.append(url) self.selectFiles_shift.append(row) } tableView.reloadData() } } } cellView.mainBox.doubleCallback = { [unowned self](downEntered: Bool, mouseBox: KMBox) -> Void in if self != nil { if downEntered { self.selectFiles.removeAll() var indexs: [URL] = [] let index: URL = self.files[row] as! URL indexs.append(index) self.delete?.historyFileViewController!(self, didSelectItemsAt: indexs) } } } return cellView } // MARK: NSTableViewDataSource func numberOfRows(in tableView: NSTableView) -> Int { return files.count } }