// // KMNThumbnailBaseViewController.swift // PDF Reader Pro // // Created by 丁林圭 on 2024/10/21. // import Cocoa @objc protocol KMNThumbnailBaseViewDelegate: AnyObject { @objc optional func clickThumbnailViewControlle(pageEditVC:KMNThumbnailBaseViewController?,currentIndex:Int) @objc optional func insertPDFThumbnailViewControlle(pageEditVC:KMNThumbnailBaseViewController?,pdfDocment:CPDFDocument?) } internal let kmnThumLocalForDraggedTypes = NSPasteboard.PasteboardType(rawValue: "kmnThumLocalForDraggedTypes") class KMNThumbnailBaseViewController: KMNBaseViewController,NSCollectionViewDelegate, NSCollectionViewDataSource,NSCollectionViewDelegateFlowLayout { weak open var thumbnailBaseViewDelegate: KMNThumbnailBaseViewDelegate? @IBOutlet var backViewBox: NSBox! @IBOutlet var collectionView: KMNThumbnailCollectionView! let subTitleHeight: CGFloat = 20.0 let maxCellHeight: CGFloat = 280.0 private var currentDocument:CPDFDocument? public var currentUndoManager:UndoManager? public var showDocument: CPDFDocument? { return currentDocument } private var thumbnails:[KMNThumbnail] = [] var selectionIndexPaths: Set = [] { didSet { var indexpaths: Set = [] for indexpath in selectionIndexPaths { if (indexpath.section >= collectionView.numberOfSections) { continue } if indexpath.section < 0 { continue } if (indexpath.item >= collectionView.numberOfItems(inSection: indexpath.section)) { continue } if indexpath.item < 0 { continue } indexpaths.insert(indexpath) } collectionView.selectionIndexPaths = indexpaths collectionView.scrollToItems(at: indexpaths, scrollPosition: .top) } } public var clickPageIndex: Int{ let minIndexPath = selectionIndexPaths.min(by: { $0.item < $1.item }) return minIndexPath?.item ?? 0 } public var isAdjustWidth:Bool = false public var isShowPageSize:Bool = false { didSet { if oldValue != isShowPageSize { var pageSize = pageThumbnailSize if(isShowPageSize) { pageSize.height += subTitleHeight } else { pageSize.height -= subTitleHeight } pageThumbnailSize = pageSize collectionView.reloadData() } } } public var pageThumbnailSize:CGSize = CGSizeMake(185.0, 260) { didSet { collectionView.reloadData() } } public let defaultItemSize = NSMakeSize(185.0, 260) var dragLocalityPages: [CPDFPage] = [] deinit { thumbnailBaseViewDelegate = nil KMPrint("KMNThumbnailBaseViewController deinit.") } init(_ document: CPDFDocument?) { super.init(nibName: "KMNThumbnailBaseViewController", bundle: nil) currentDocument = document } init(_ filePath: String,password:String?) { super.init(nibName: "KMNThumbnailBaseViewController", bundle: nil) let document = CPDFDocument.init(url: URL(fileURLWithPath: filePath)) if password != nil { document?.unlock(withPassword: password as String?) } if document?.allowsCopying == false || document?.allowsPrinting == false { self.exitCurrentView() } else { currentDocument = document } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() collectionView.delegate = self collectionView.dataSource = self collectionView.isSelectable = true //支持拖拽需设置未True collectionView.allowsMultipleSelection = true collectionView.register(KMNThumbnailCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "thumbnailCollectionViewItem")) collectionView.registerForDraggedTypes([.fileURL]) collectionView.setDraggingSourceOperationMask(.every, forLocal: false) collectionView.setDraggingSourceOperationMask(.every, forLocal: true) refreshDatas() } public func exitCurrentView() { thumbnailBaseViewDelegate?.clickThumbnailViewControlle?(pageEditVC: self, currentIndex: clickPageIndex) } public func supportDragFileTypes()->[String] { let supportFiles = KMNConvertTool.pdfExtensions + KMConvertPDFManager.supportFileType() return supportFiles } public func refreshDatas() { thumbnails = [] if currentDocument != nil { for i in 0 ... currentDocument!.pageCount { let thumbnail = KMNThumbnail.init(document: currentDocument!, currentPageIndex: Int(i)) thumbnails.append(thumbnail) } } } // MARK: - NSCollectionViewDataSource func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { return thumbnails.count } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { let item: KMNThumbnailCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "thumbnailCollectionViewItem"), for: indexPath) as! KMNThumbnailCollectionViewItem item.isShowFileSize = isShowPageSize item.doubleClickBack = { [weak self] in self?.thumbnailBaseViewDelegate?.clickThumbnailViewControlle?(pageEditVC: self, currentIndex: indexPath.item) } item.thumbnailMode = thumbnails[indexPath.item] return item } // MARK: - NSCollectionViewDelegateFlowLayout func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { if isAdjustWidth == false { return pageThumbnailSize } else { let thumbnailMode: KMNThumbnail = thumbnails[indexPath.item] let pageSize = thumbnailMode.pageSize var cellHeight = pageSize.width / ((pageThumbnailSize.width - 32) * pageThumbnailSize.height) var cellWidth = pageThumbnailSize.width if cellHeight > maxCellHeight { cellHeight = 280.0 cellWidth = cellHeight/pageSize.height * pageSize.width } return CGSize(width: cellWidth, height: cellHeight) } } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 16.0 } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 24.0 } public func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, insetForSectionAt section: Int) -> NSEdgeInsets { return NSEdgeInsetsMake(24.0, 24.0, 24.0, 24.0) } //MARK: - NSCollectionViewDelegate func collectionView(_ collectionView: NSCollectionView, writeItemsAt indexPaths: Set, to pasteboard: NSPasteboard) -> Bool { if IAPProductsManager.default().isAvailableAllFunction() == false { return false } var docmentName = currentDocument?.documentURL.lastPathComponent.deletingPathExtension ?? "" let pagesName = indexPaths.count > 1 ? " pages" : " page" var tFileName = pagesName + KMNTools.parseIndexPathsSet(indexSets: collectionView.selectionIndexPaths) if tFileName.count > 50 { tFileName = String(tFileName.prefix(50)) } pasteboard.declareTypes([.fileURL], owner: self) let writePDFDocument = CPDFDocument() for indexPath in indexPaths { let row = indexPath.item if let copyPage = currentDocument?.page(at: UInt(row)) as? CPDFPage { writePDFDocument?.insertPageObject(copyPage, at: writePDFDocument?.pageCount ?? 0) } } var cachesDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! cachesDir = cachesDir.appendingPathComponent("PageEdit_Pasteboard") let fileManager = FileManager.default if !fileManager.fileExists(atPath: cachesDir.path) { try? FileManager.default.createDirectory(atPath: cachesDir.path, withIntermediateDirectories: true, attributes: nil) } docmentName = "\(docmentName)\(tFileName)" if docmentName.count > 50 { docmentName = String(docmentName.prefix(50)) } let filePathURL = cachesDir.appendingPathComponent(docmentName).appendingPathExtension("pdf") let success = writePDFDocument?.write(to: filePathURL, isSaveFontSubset:false) if success == true { pasteboard.setPropertyList([filePathURL.path], forType: .fileURL) return true } else { return false } } func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItemsAt indexPaths: Set) { let sortedIndexPaths = indexPaths.sorted { (ip1, ip2) -> Bool in if ip1.section == ip2.section { return ip1.item < ip2.item } return ip1.section < ip2.section } dragLocalityPages = [] for fromIndexPath in sortedIndexPaths { let page = thumbnails[fromIndexPath.item].thumbnaiPage if(page != nil) { dragLocalityPages.append(page!) } } } func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer, dropOperation proposedDropOperation: UnsafeMutablePointer) -> NSDragOperation { let pboard = draggingInfo.draggingPasteboard if dragLocalityPages.count != 0 { if proposedDropOperation.pointee == .on { proposedDropOperation.pointee = .before } return .move } else if let availableType = pboard.availableType(from: [.fileURL]), availableType == .fileURL { if let fileNames = pboard.propertyList(forType: .fileURL) as? [String], fileNames.count >= 1 { let path = fileNames.first! let pathExtension = URL(fileURLWithPath: path).pathExtension.lowercased() if pathExtension == "pdf" || supportDragFileTypes().contains(pathExtension) { return .copy } } } return [] } func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool { let pboard = draggingInfo.draggingPasteboard if dragLocalityPages.count != 0 { movePages(pages: dragLocalityPages, destinationDex: indexPath.item) return true } else if let availableType = pboard.availableType(from: [.fileURL]), availableType == .fileURL { let index = indexPath.item if let fileNames = pboard.propertyList(forType: .fileURL) as? [String] { insertFromFilePath(fileNames: fileNames, formDex: 0, indexDex: UInt(index), selectIndexs: []) { zSelectIndexs in self.refreshDatas() self.selectPages(with: zSelectIndexs) } return true } } return false } func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, endedAt screenPoint: NSPoint, dragOperation operation: NSDragOperation) { dragLocalityPages = [] } }