KMNThumbnailBaseViewController.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. //
  2. // KMNThumbnailBaseViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by 丁林圭 on 2024/10/21.
  6. //
  7. import Cocoa
  8. @objc protocol KMNThumbnailBaseViewDelegate: AnyObject {
  9. @objc optional func clickThumbnailViewControlle(pageEditVC:KMNThumbnailBaseViewController?,currentIndex:Int)
  10. @objc optional func insertPDFThumbnailViewControlle(pageEditVC:KMNThumbnailBaseViewController?,pdfDocment:CPDFDocument?)
  11. }
  12. internal let kmnThumLocalForDraggedTypes = NSPasteboard.PasteboardType(rawValue: "kmnThumLocalForDraggedTypes")
  13. class KMNThumbnailBaseViewController: KMNBaseViewController,NSCollectionViewDelegate, NSCollectionViewDataSource,NSCollectionViewDelegateFlowLayout {
  14. weak open var thumbnailBaseViewDelegate: KMNThumbnailBaseViewDelegate?
  15. @IBOutlet var backViewBox: NSBox!
  16. @IBOutlet var collectionView: KMNThumbnailCollectionView!
  17. let subTitleHeight: CGFloat = 20.0
  18. let maxCellHeight: CGFloat = 280.0
  19. private var currentDocument:CPDFDocument?
  20. public var currentUndoManager:UndoManager?
  21. public var showDocument: CPDFDocument? {
  22. return currentDocument
  23. }
  24. private var thumbnails:[KMNThumbnail] = []
  25. var selectionIndexPaths: Set<IndexPath> = [] {
  26. didSet {
  27. var indexpaths: Set<IndexPath> = []
  28. for indexpath in selectionIndexPaths {
  29. if (indexpath.section >= collectionView.numberOfSections) {
  30. continue
  31. }
  32. if indexpath.section < 0 {
  33. continue
  34. }
  35. if (indexpath.item >= collectionView.numberOfItems(inSection: indexpath.section)) {
  36. continue
  37. }
  38. if indexpath.item < 0 {
  39. continue
  40. }
  41. indexpaths.insert(indexpath)
  42. }
  43. collectionView.selectionIndexPaths = indexpaths
  44. collectionView.scrollToItems(at: indexpaths, scrollPosition: .top)
  45. }
  46. }
  47. public var clickPageIndex: Int{
  48. let minIndexPath = selectionIndexPaths.min(by: { $0.item < $1.item })
  49. return minIndexPath?.item ?? 0
  50. }
  51. public var isAdjustWidth:Bool = false
  52. public var isShowPageSize:Bool = false {
  53. didSet {
  54. if oldValue != isShowPageSize {
  55. var pageSize = pageThumbnailSize
  56. if(isShowPageSize) {
  57. pageSize.height += subTitleHeight
  58. } else {
  59. pageSize.height -= subTitleHeight
  60. }
  61. pageThumbnailSize = pageSize
  62. collectionView.reloadData()
  63. }
  64. }
  65. }
  66. public var pageThumbnailSize:CGSize = CGSizeMake(185.0, 260) {
  67. didSet {
  68. collectionView.reloadData()
  69. }
  70. }
  71. public let defaultItemSize = NSMakeSize(185.0, 260)
  72. var dragLocalityPages: [CPDFPage] = []
  73. deinit {
  74. thumbnailBaseViewDelegate = nil
  75. KMPrint("KMNThumbnailBaseViewController deinit.")
  76. }
  77. init(_ document: CPDFDocument?) {
  78. super.init(nibName: "KMNThumbnailBaseViewController", bundle: nil)
  79. currentDocument = document
  80. }
  81. init(_ filePath: String,password:String?) {
  82. super.init(nibName: "KMNThumbnailBaseViewController", bundle: nil)
  83. let document = CPDFDocument.init(url: URL(fileURLWithPath: filePath))
  84. if password != nil {
  85. document?.unlock(withPassword: password as String?)
  86. }
  87. if document?.allowsCopying == false || document?.allowsPrinting == false {
  88. self.exitCurrentView()
  89. } else {
  90. currentDocument = document
  91. }
  92. }
  93. required init?(coder: NSCoder) {
  94. fatalError("init(coder:) has not been implemented")
  95. }
  96. override func viewDidLoad() {
  97. super.viewDidLoad()
  98. collectionView.delegate = self
  99. collectionView.dataSource = self
  100. collectionView.isSelectable = true //支持拖拽需设置未True
  101. collectionView.allowsMultipleSelection = true
  102. collectionView.register(KMNThumbnailCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "thumbnailCollectionViewItem"))
  103. collectionView.registerForDraggedTypes([.fileURL])
  104. collectionView.setDraggingSourceOperationMask(.every, forLocal: false)
  105. collectionView.setDraggingSourceOperationMask(.every, forLocal: true)
  106. refreshDatas()
  107. }
  108. public func exitCurrentView() {
  109. thumbnailBaseViewDelegate?.clickThumbnailViewControlle?(pageEditVC: self, currentIndex: clickPageIndex)
  110. }
  111. public func supportDragFileTypes()->[String] {
  112. let supportFiles = KMNConvertTool.pdfExtensions + KMConvertPDFManager.supportFileType()
  113. return supportFiles
  114. }
  115. public func refreshDatas() {
  116. thumbnails = []
  117. if currentDocument != nil {
  118. for i in 0 ... currentDocument!.pageCount {
  119. let thumbnail = KMNThumbnail.init(document: currentDocument!, currentPageIndex: Int(i))
  120. thumbnails.append(thumbnail)
  121. }
  122. }
  123. }
  124. // MARK: - NSCollectionViewDataSource
  125. func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
  126. return thumbnails.count
  127. }
  128. func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
  129. let item: KMNThumbnailCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "thumbnailCollectionViewItem"), for: indexPath) as! KMNThumbnailCollectionViewItem
  130. item.isShowFileSize = isShowPageSize
  131. item.doubleClickBack = { [weak self] in
  132. self?.thumbnailBaseViewDelegate?.clickThumbnailViewControlle?(pageEditVC: self, currentIndex: indexPath.item)
  133. }
  134. item.thumbnailMode = thumbnails[indexPath.item]
  135. return item
  136. }
  137. // MARK: - NSCollectionViewDelegateFlowLayout
  138. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
  139. if isAdjustWidth == false {
  140. return pageThumbnailSize
  141. } else {
  142. let thumbnailMode: KMNThumbnail = thumbnails[indexPath.item]
  143. let pageSize = thumbnailMode.pageSize
  144. var cellHeight = pageSize.width / ((pageThumbnailSize.width - 32) * pageThumbnailSize.height)
  145. var cellWidth = pageThumbnailSize.width
  146. if cellHeight > maxCellHeight {
  147. cellHeight = 280.0
  148. cellWidth = cellHeight/pageSize.height * pageSize.width
  149. }
  150. return CGSize(width: cellWidth, height: cellHeight)
  151. }
  152. }
  153. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  154. return 16.0
  155. }
  156. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  157. return 24.0
  158. }
  159. public func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, insetForSectionAt section: Int) -> NSEdgeInsets {
  160. return NSEdgeInsetsMake(24.0, 24.0, 24.0, 24.0)
  161. }
  162. //MARK: - NSCollectionViewDelegate
  163. func collectionView(_ collectionView: NSCollectionView,
  164. writeItemsAt indexPaths: Set<IndexPath>,
  165. to pasteboard: NSPasteboard) -> Bool {
  166. if IAPProductsManager.default().isAvailableAllFunction() == false {
  167. return false
  168. }
  169. var docmentName = currentDocument?.documentURL.lastPathComponent.deletingPathExtension ?? ""
  170. let pagesName = indexPaths.count > 1 ? " pages" : " page"
  171. var tFileName = pagesName + KMNTools.parseIndexPathsSet(indexSets: collectionView.selectionIndexPaths)
  172. if tFileName.count > 50 {
  173. tFileName = String(tFileName.prefix(50))
  174. }
  175. pasteboard.declareTypes([.fileURL], owner: self)
  176. let writePDFDocument = CPDFDocument()
  177. for indexPath in indexPaths {
  178. let row = indexPath.item
  179. if let copyPage = currentDocument?.page(at: UInt(row)) as? CPDFPage {
  180. writePDFDocument?.insertPageObject(copyPage, at: writePDFDocument?.pageCount ?? 0)
  181. }
  182. }
  183. var cachesDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
  184. cachesDir = cachesDir.appendingPathComponent("PageEdit_Pasteboard")
  185. let fileManager = FileManager.default
  186. if !fileManager.fileExists(atPath: cachesDir.path) {
  187. try? FileManager.default.createDirectory(atPath: cachesDir.path, withIntermediateDirectories: true, attributes: nil)
  188. }
  189. docmentName = "\(docmentName)\(tFileName)"
  190. if docmentName.count > 50 {
  191. docmentName = String(docmentName.prefix(50))
  192. }
  193. let filePathURL = cachesDir.appendingPathComponent(docmentName).appendingPathExtension("pdf")
  194. let success = writePDFDocument?.write(to: filePathURL, isSaveFontSubset:false)
  195. if success == true {
  196. pasteboard.setPropertyList([filePathURL.path], forType: .fileURL)
  197. return true
  198. } else {
  199. return false
  200. }
  201. }
  202. func collectionView(_ collectionView: NSCollectionView,
  203. draggingSession session: NSDraggingSession,
  204. willBeginAt screenPoint: NSPoint,
  205. forItemsAt indexPaths: Set<IndexPath>) {
  206. let sortedIndexPaths = indexPaths.sorted { (ip1, ip2) -> Bool in
  207. if ip1.section == ip2.section {
  208. return ip1.item < ip2.item
  209. }
  210. return ip1.section < ip2.section
  211. }
  212. dragLocalityPages = []
  213. for fromIndexPath in sortedIndexPaths {
  214. let page = thumbnails[fromIndexPath.item].thumbnaiPage
  215. if(page != nil) {
  216. dragLocalityPages.append(page!)
  217. }
  218. }
  219. }
  220. func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
  221. let pboard = draggingInfo.draggingPasteboard
  222. if dragLocalityPages.count != 0 {
  223. if proposedDropOperation.pointee == .on {
  224. proposedDropOperation.pointee = .before
  225. }
  226. return .move
  227. } else if let availableType = pboard.availableType(from: [.fileURL]), availableType == .fileURL {
  228. if let fileNames = pboard.propertyList(forType: .fileURL) as? [String], fileNames.count >= 1 {
  229. let path = fileNames.first!
  230. let pathExtension = URL(fileURLWithPath: path).pathExtension.lowercased()
  231. if pathExtension == "pdf" || supportDragFileTypes().contains(pathExtension) {
  232. return .copy
  233. }
  234. }
  235. }
  236. return []
  237. }
  238. func collectionView(_ collectionView: NSCollectionView,
  239. acceptDrop draggingInfo: NSDraggingInfo,
  240. indexPath: IndexPath,
  241. dropOperation: NSCollectionView.DropOperation) -> Bool {
  242. let pboard = draggingInfo.draggingPasteboard
  243. if dragLocalityPages.count != 0 {
  244. movePages(pages: dragLocalityPages, destinationDex: indexPath.item)
  245. return true
  246. } else if let availableType = pboard.availableType(from: [.fileURL]), availableType == .fileURL {
  247. let index = indexPath.item
  248. if let fileNames = pboard.propertyList(forType: .fileURL) as? [String] {
  249. insertFromFilePath(fileNames: fileNames, formDex: 0, indexDex: UInt(index), selectIndexs: []) { zSelectIndexs in
  250. self.refreshDatas()
  251. self.selectPages(with: zSelectIndexs)
  252. }
  253. return true
  254. }
  255. }
  256. return false
  257. }
  258. func collectionView(_ collectionView: NSCollectionView,
  259. draggingSession session: NSDraggingSession,
  260. endedAt screenPoint: NSPoint,
  261. dragOperation operation: NSDragOperation) {
  262. dragLocalityPages = []
  263. }
  264. }