// // KMHomeHistoryFileViewController.swift // PDF Reader Pro // // 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]) @objc optional func historyFileViewController(_ viewController: KMHomeHistoryFileViewController, refreshLayout refresh: Bool) } 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 mainBox.canDoubleClick = true documentName.maximumNumberOfLines = 1 mainBox.moveCallback = { [unowned self](mouseEntered: Bool, mouseBox: KMBox) -> Void in if !self.isSelect { if mouseEntered { self.documentName.textColor = NSColor.km_init(hex: "#252629") self.documentType.textColor = NSColor.km_init(hex: "#94989C") self.documentSize.textColor = NSColor.km_init(hex: "#94989C") self.lastModificationTime.textColor = NSColor.km_init(hex: "#94989C") self.mainBox.fillColor = NSColor.km_init(hex: "#EDEEF0") self.mainBox.borderWidth = 0 self.mainBox.cornerRadius = 4.0 } else { self.documentName.textColor = NSColor.km_init(hex: "#252629") self.documentType.textColor = NSColor.km_init(hex: "#94989C") self.documentSize.textColor = NSColor.km_init(hex: "#94989C") self.lastModificationTime.textColor = NSColor.km_init(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 self.isDateInCurrentWeek(fileDate) { // dateFormatter.dateFormat = "EEE, HH:mm" // } else { dateFormatter.dateFormat = "MMM d, yyyy" // } let fileName = url.lastPathComponent // let fileType = url.pathExtension.isEmpty ? "" : url.pathExtension let fileType = "" 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 isDateInCurrentWeek(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.km_init(hex: "#CED0D4", alpha: 0.6) mainBox.borderWidth = 1.0 mainBox.borderColor = NSColor.km_init(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.km_init(hex: "#252629") documentName.font = NSFont(name: "SFProText-Regular", size: 14) documentType.textColor = NSColor.km_init(hex: "#94989C") documentSize.textColor = NSColor.km_init(hex: "#94989C") documentName.backgroundColor = .clear lastModificationTime.textColor = NSColor.km_init(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.km_init(hex: "#CED0D4", alpha: 0.6) mainBox.borderWidth = 1.0 mainBox.borderColor = NSColor.km_init(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 isDateInCurrentWeek(_ date: Date) -> Bool { let calendar = Calendar.current // 获取当前日期的星期几 let weekday = calendar.component(.weekday, from: Date()) // 获取一周的第一天(周日)的日期 let firstDayOfWeek = calendar.date(byAdding: .day, value: -weekday, to: Date())! // 获取一周的最后一天(下周的第一天)的日期 let lastDayOfWeek = calendar.date(byAdding: .day, value: 7, to: firstDayOfWeek)! // 判断日期是否在当前周的范围内 return date > firstDayOfWeek && date < lastDayOfWeek } func getWeekOfYear(date: Date) -> Int { let components = Calendar.current.dateComponents([Calendar.Component.weekOfYear], from: date) return components.weekOfYear ?? 0 } //MARK: update // 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 menu = NSMenu() var item = menu.addItem(withTitle: NSLocalizedString("Show in Finder", comment: ""), action: #selector(buttonItemClick_ShowPath(_:)), keyEquivalent: "") item.target = self item = menu.addItem(withTitle: NSLocalizedString("Remove from Recents", comment: ""), action: #selector(buttonItemClick_ClosePath(_:)), keyEquivalent: "") item.target = self // menu.popUp(positioning: menu.item(at: 0), at: NSMakePoint(CGRectGetMaxX(sender.frame)-35, sender.frame.origin.y+10), in: self) menu.popUp(positioning: menu.item(at: 0), at: NSMakePoint(NSMaxX(sender.frame), sender.frame.origin.y), in: self) } @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: [URL] = [] 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! // 是否强制刷新 var isForceReload = false // MARK: Init override func viewWillAppear() { self.refreshMode() } 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() if (self.isForceReload) { self.isForceReload = false self.reloadData() return } for url in NSDocumentController.shared.recentDocumentURLs { if FileManager.default.fileExists(atPath: url.path) { if !self.files.contains(url) { 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.km_init(hex: "#616469") emptyTitleLabel.font = NSFont(name: "SFProText-Regular", size: 14.0) emptySubtitleLabel.textColor = NSColor.km_init(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 } self.delete?.historyFileViewController!(self, refreshLayout: true) 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) } } //考虑多个文件时如果筛选最后修改时间,那刚开启的文件可能在列表其他的位置 // if self.files.count > 0 { // var dateArray: [Int: URL] = [:] // for index in 0.. // let fileDate: Date = attrib![FileAttributeKey(rawValue: "NSFileModificationDate")] as! Date // let timeInterval = fileDate.timeIntervalSince1970 // dateArray.updateValue(url, forKey: Int(timeInterval)) // } // // let sortedKeys = dateArray.keys.sorted(by: >) // // files.removeAll() // for key in sortedKeys { // files.append(dateArray[key]!) // print("\(key): \(dateArray[key]!)") // } // } 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 } @objc func tableViewDidScroll(_ notification: Notification) { self.historyFileTableView.reloadData() } // MARK: NSTableViewDataSource func numberOfRows(in tableView: NSTableView) -> Int { return files.count } }