// // 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: NSViewController,NSCollectionViewDelegate, NSCollectionViewDataSource,NSCollectionViewDelegateFlowLayout { weak open var thumbnailBaseViewDelegate: KMNThumbnailBaseViewDelegate? @IBOutlet var backViewBox: NSBox! @IBOutlet var collectionView: NSCollectionView! 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 } } } public var pageThumbnailSize:CGSize = CGSizeMake(185.0, 260) { didSet { collectionView.reloadData() } } var dragLocalityIndexPaths: Set = [] 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() thumbnails = [] if currentDocument != nil { for i in 0 ... currentDocument!.pageCount { let thumbnail = KMNThumbnail.init(document: currentDocument!, currentPageIndex: Int(i)) thumbnails.append(thumbnail) } } collectionView.delegate = self collectionView.dataSource = self collectionView.isSelectable = true //支持拖拽需设置未True collectionView.allowsMultipleSelection = true collectionView.register(KMNThumbnailCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "thumbnailCollectionViewItem")) collectionView.registerForDraggedTypes(NSFilePromiseReceiver.readableDraggedTypes.map { NSPasteboard.PasteboardType($0) }) collectionView.registerForDraggedTypes([kmnThumLocalForDraggedTypes, .fileURL,.string,.pdf]) } public func exitCurrentView() { thumbnailBaseViewDelegate?.clickThumbnailViewControlle?(pageEditVC: self, currentIndex: clickPageIndex) } private func supportDragFileTypes()->[String] { let supportFiles = KMTools.pdfExtensions + KMConvertPDFManager.supportFileType() return supportFiles } private func fileNameWithSelectedPages(_ itemIndexes: IndexSet) -> String { var pagesName = "" if (itemIndexes.count > 1) { pagesName.append(" pages") } else { pagesName.append(" page") } let docmentName = currentDocument?.documentURL.deletingPathExtension().lastPathComponent ?? "" let tFileName = String(format: "%@ %@", pagesName,KMNTools.parseIndexSet(indexSet: itemIndexes)) return String(format: "%@%@", docmentName,tFileName) } public func insertFormPDF(insertPages: [CPDFPage],pageDex:Int) { var pageIndexDex: Int = pageDex var indexpaths = Set() for page in insertPages { currentDocument?.insertPageObject(page, at: UInt(pageIndexDex)) indexpaths.insert(IndexPath(item: pageIndexDex, section: 0)) pageIndexDex += 1 } collectionView.scrollToItems(at: indexpaths, scrollPosition: .centeredVertically) // (currentUndoManager?.prepare(withInvocationTarget: self) as KMNThumbnailBaseViewController).deletePDFPages(indexpaths: indexpaths, scroIndex: pageDex) } public func deletePDFPages(indexpaths:Set,scroIndex:Int) { collectionView.reloadData() collectionView.scrollToItems(at: [IndexPath(item: scroIndex, section: 0)], scrollPosition: .centeredVertically) } // 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, canDragItemsAt indexPaths: Set, with event: NSEvent) -> Bool { return IAPProductsManager.default().isAvailableAllFunction() } func collectionView(_ collectionView: NSCollectionView, writeItemsAt indexPaths: Set, to pasteboard: NSPasteboard) -> Bool { let data: Data = try! NSKeyedArchiver.archivedData(withRootObject: indexPaths, requiringSecureCoding: true) pasteboard.declareTypes([kmnThumLocalForDraggedTypes], owner: self) pasteboard.setData(data, forType: kmnThumLocalForDraggedTypes) dragLocalityIndexPaths.removeAll() dragLocalityIndexPaths = indexPaths return true } func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer, dropOperation proposedDropOperation: UnsafeMutablePointer) -> NSDragOperation { let pboard = draggingInfo.draggingPasteboard if (pboard.availableType(from: [kmnThumLocalForDraggedTypes]) != nil) { return .move } else if (pboard.availableType(from: [.localDraggedTypes]) != nil) { return .move } else if ((pboard.availableType(from: [.fileURL])) != nil) { guard let pbItems = pboard.pasteboardItems else { return NSDragOperation(rawValue: 0) } let allowedFileTypes = supportDragFileTypes() var hasValidFile = false for item in pbItems { guard let data = item.string(forType: .fileURL), let fileUrl = URL(string: data) else { continue } let type = fileUrl.pathExtension.lowercased() if (allowedFileTypes.contains(type)) { hasValidFile = true break } } if (!hasValidFile) { return NSDragOperation(rawValue: 0) } } return .generic } func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool { let result = false if !IAPProductsManager.default().isAvailableAllFunction() { return result } let pboard = draggingInfo.draggingPasteboard if (pboard.availableType(from: [kmnThumLocalForDraggedTypes]) != nil) { } else if (pboard.availableType(from: [.localDraggedTypes]) != nil) { } else if ((pboard.availableType(from: [.fileURL])) != nil) { guard let pbItems = pboard.pasteboardItems else { return false } //获取url var array: [URL] = [] for item in pbItems { guard let data = item.string(forType: .fileURL), let url = URL(string: data) else { continue } let allowedFileTypes = supportDragFileTypes() let type = url.pathExtension.lowercased() if (allowedFileTypes.contains(type)) { array.append(url) } } } return true } func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, endedAt screenPoint: NSPoint, dragOperation operation: NSDragOperation) { print("6") dragLocalityIndexPaths = [] } }