KMThumbnailViewController.swift 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. //
  2. // KMThumbnailViewController.swift
  3. // PDF Master
  4. //
  5. // Created by lxy on 2022/10/10.
  6. //
  7. import Cocoa
  8. @objc protocol KMThumbnailViewControllerDelegate {
  9. @objc optional func gotoPageEdit(thumbnailViewController:KMThumbnailViewController, pages: [Int])
  10. @objc optional func pageDidSelect(controller: KMThumbnailViewController, pages: [Int])
  11. @objc optional func controller(controller: KMThumbnailViewController, itemClick item: Any?, itemKey: KMItemKey, params: Any?)
  12. }
  13. class KMThumbnailViewController: NSViewController {
  14. open weak var delegate: KMThumbnailViewControllerDelegate?
  15. @IBOutlet weak var headerView: NSView!
  16. @IBOutlet weak var titleLabel: NSTextField!
  17. @IBOutlet weak var thumbnailView: KMPDFThumbnailView!
  18. @IBOutlet var doublePageBtn: NSButton!
  19. @IBOutlet weak var lineView: NSView!
  20. var doublePageMode : Bool! = false
  21. var isLocalEvent: Bool = false //是否为本视图事件
  22. var listView : CPDFListView!
  23. var copysPages : [CPDFPage] = []
  24. //注释状态
  25. var annotationShowState: KMAnnotationViewShowType = .none {
  26. didSet {
  27. if self.thumbnailView != nil {
  28. self.thumbnailView.annotationShowState = self.annotationShowState
  29. }
  30. }
  31. }
  32. func dealloc() {
  33. NotificationCenter.default.removeObserver(self)
  34. }
  35. deinit {
  36. NotificationCenter.default.removeObserver(self)
  37. print("KMThumbnailViewController 释放")
  38. }
  39. override func viewWillAppear() {
  40. super.viewWillAppear()
  41. self.thumbnailView.reloadData()
  42. }
  43. override func centerSelectionInVisibleArea(_ sender: Any?) {
  44. super.centerSelectionInVisibleArea(sender)
  45. }
  46. override func viewDidLoad() {
  47. super.viewDidLoad()
  48. self.view.wantsLayer = true
  49. self.view.layer?.backgroundColor = NSColor.clear.cgColor
  50. self.lineView.backgroundColor(NSColor(hex: "#EDEEF0"))
  51. self.headerView.wantsLayer = true
  52. self.headerView.layer?.backgroundColor = NSColor(hex: "#F7F8FA").cgColor
  53. self.titleLabel.stringValue = NSLocalizedString("Thumbnails", comment: "")
  54. self.titleLabel.font = NSFont.SFProTextSemibold(14.0)
  55. self.titleLabel.textColor = NSColor(hex: "#252629")
  56. if self.listView.document != nil {
  57. self.thumbnailView.document = self.listView.document
  58. }
  59. // self.doublePageBtn.isHidden = true
  60. self.thumbnailView.delegate = self
  61. self.thumbnailView.collectionView.isSelectable = true
  62. self.thumbnailView.collectionView.allowsMultipleSelection = true
  63. self.thumbnailView.isShowPageSize = true
  64. self.thumbnailView.isNeedMarkerLine = true
  65. // self.thumbnailView.collectionView.allowsEmptySelection = false
  66. self.doublePageBtn.toolTip = NSLocalizedString("Single/Double column display", comment: "")
  67. self.pdfCurrentPageChange()
  68. self.initNotification()
  69. }
  70. func initNotification() {
  71. NotificationCenter.default.addObserver(self, selector: #selector(KMPDFViewPageCountChangedNotification), name: NSNotification.Name.init(rawValue: "KMPDFViewRotatePage"), object: nil)
  72. NotificationCenter.default.addObserver(self, selector: #selector(KMPDFViewCurrentPageDidChangedNotification), name: NSNotification.Name.init(rawValue: "KMPDFViewCurrentPageDidChanged"), object: nil)
  73. NotificationCenter.default.addObserver(self, selector: #selector(KMPDFViewPageCountChangedNotification), name: NSNotification.Name.init(rawValue: "CPDFDocumentPageCountChangedNotification"), object: nil)
  74. NotificationCenter.default.addObserver(self, selector: #selector(AnnotationDidChangeNoti), name: NSNotification.Name.init(rawValue: "CPDFPageDidAddAnnotationNotification"), object: nil)
  75. NotificationCenter.default.addObserver(self, selector: #selector(AnnotationDidChangeNoti), name: NSNotification.Name.init(rawValue: "CPDFPageDidRemoveAnnotationNotification"), object: nil)
  76. }
  77. func removeNotification() {
  78. NotificationCenter.default.removeObserver(self)
  79. }
  80. //MARK: Public Method
  81. func reloadData () {
  82. if self.doublePageMode {
  83. self.thumbnailView.thumbnailSzie = CGSize(width: 86, height: 101)
  84. self.doublePageBtn.image = NSImage(named: "KMImageNameThumbnailPage")
  85. } else {
  86. self.thumbnailView.thumbnailSzie = CGSize(width: 156, height: 180)
  87. self.doublePageBtn.image = NSImage(named: "KMImageNameThumbnailDoublePage")
  88. }
  89. self.thumbnailView.reloadData()
  90. self.km_resignFirstResponder()
  91. }
  92. func reloadDataAtIndexs (indexs: IndexSet) {
  93. var selectPages: [Int] = []
  94. for index in indexs {
  95. selectPages.append(index+1)
  96. }
  97. DispatchQueue.main.async {
  98. var data = Set<IndexPath>()
  99. for index in selectPages {
  100. data.insert(IndexPath(item: index-1, section: 0))
  101. }
  102. self.thumbnailView.collectionView.reloadItems(at: data)
  103. self.km_resignFirstResponder()
  104. }
  105. }
  106. //MARK: Private Method
  107. @IBAction func doublePageAction(_ sender: Any) {
  108. self.doublePageMode = !self.doublePageMode
  109. self.reloadData()
  110. }
  111. private func dragPagesForDescSort(_ indexs: IndexSet, _ toIndex: Int) {
  112. if (indexs.count <= 0) {
  113. return
  114. }
  115. /// 数据降序排序
  116. let indexArray = indexs.sorted { index1, index2 in
  117. return index1 > index2
  118. }
  119. var newIndexs: IndexSet = []
  120. for index in indexArray {
  121. newIndexs.insert(index)
  122. }
  123. self.dragPages(newIndexs, toIndex)
  124. }
  125. @objc private func dragPages(_ indexs: IndexSet, _ toIndex: Int) {
  126. if (indexs.count <= 0) {
  127. return
  128. }
  129. //获取原有page的下标 和 开始添加的下标
  130. var indexTemp: Int = toIndex
  131. var pageItems: [KMThumbnailPageItem] = []
  132. for index in indexs {
  133. let newPage: CPDFPage = self.listView?.document.page(at: UInt(index)).copy() as! CPDFPage
  134. let pageItem = KMThumbnailPageItem(page: newPage, index: index, oldIndex: index)
  135. pageItems.append(pageItem)
  136. if (toIndex > index) { /// 删除了插入位置前面的页面,需要改变 toIndex
  137. indexTemp -= 1
  138. }
  139. }
  140. //建立模型
  141. var tPageItems: [KMThumbnailPageItem] = []
  142. for index in 0...pageItems.count - 1 {
  143. let pageItem: KMThumbnailPageItem = pageItems[index]
  144. let tItem = KMThumbnailPageItem(page: pageItem.page, index: indexTemp + index, oldIndex: pageItem.index)
  145. tPageItems.append(tItem)
  146. }
  147. //进行移动
  148. self.dragPageItems(pageItems: tPageItems)
  149. }
  150. private func km_resignFirstResponder() {
  151. self.view.window?.makeFirstResponder(self.listView)
  152. }
  153. //MARK: Noti
  154. @objc func KMPDFViewCurrentPageDidChangedNotification(notification: NSNotification) {
  155. if notification.object is CPDFDocument {
  156. let pdfdocument : CPDFDocument = notification.object as! CPDFDocument
  157. if pdfdocument.isEqual(self.listView.document) {
  158. if !isLocalEvent {
  159. // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { [unowned self] in
  160. self.pdfCurrentPageChange()
  161. self.delegate?.pageDidSelect?(controller: self, pages: [self.listView.currentPageIndex])
  162. // }
  163. }
  164. isLocalEvent = false
  165. }
  166. }
  167. }
  168. @objc func KMPDFViewPageCountChangedNotification(notification: NSNotification) {
  169. if notification.object is CPDFDocument {
  170. let pdfdocument : CPDFDocument = notification.object as! CPDFDocument
  171. if pdfdocument.isEqual(self.listView.document) {
  172. if !isLocalEvent {
  173. // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { [unowned self] in
  174. self.reloadData()
  175. // }
  176. }
  177. isLocalEvent = false
  178. }
  179. }
  180. }
  181. @objc func AnnotationDidChangeNoti(notification: NSNotification) {
  182. if notification.object is CPDFAnnotation {
  183. let pdfAnnotation : CPDFAnnotation = notification.object as! CPDFAnnotation
  184. if (pdfAnnotation.page != nil) {
  185. var indexs: IndexSet = IndexSet()
  186. indexs.insert(IndexSet.Element(pdfAnnotation.page.pageIndex()))
  187. self.reloadDataAtIndexs(indexs: indexs)
  188. }
  189. }
  190. }
  191. func pdfCurrentPageChange () {
  192. if self.listView.document.pageCount == 0 {
  193. return
  194. }
  195. let insertIndex: Int = self.listView.currentPageIndex;
  196. var indexs: IndexSet = IndexSet()
  197. indexs.insert(insertIndex)
  198. self.selectPages(indexs: indexs)
  199. // self.thumbnailView.collectionView.scrollToItems(at: self.thumbnailView.collectionView.selectionIndexPaths, scrollPosition: NSCollectionView.ScrollPosition.centeredVertically)
  200. }
  201. //MARK: menu Action
  202. @IBAction func insertPageItemAction(menu:NSMenuItem) {
  203. if menu.tag == 0 {
  204. self.item_insertFile(sender: menu)
  205. } else if menu.tag == 1 {
  206. self.item_insertBankPage(sender: menu)
  207. } else if menu.tag == 2 {
  208. self.item_insertPage(sender: menu)
  209. }
  210. }
  211. @objc private func item_insertFile(sender: NSMenuItem?) {
  212. let panel = NSOpenPanel()
  213. panel.allowedFileTypes = ["pdf"]
  214. panel.beginSheetModal(for: self.view.window!) { [weak self] response in
  215. if (response == .cancel) {
  216. return
  217. }
  218. /// 处理page
  219. var insertIndex: Int = self!.thumbnailView.collectionView.selectionIndexes.last!
  220. let doucument = CPDFDocument(url: panel.url)
  221. if ((doucument?.isLocked)!) {
  222. KMPasswordInputWindow.openWindow(window: self!.view.window!, url: panel.url!) { [weak self] result, password in
  223. if (result == .cancel) {
  224. return
  225. }
  226. doucument?.unlock(withPassword: password)
  227. var newInsertIndex: Int = insertIndex + 1
  228. var pages: [CPDFPage] = []
  229. var indexs: IndexSet = IndexSet()
  230. for i in 0 ..< doucument!.pageCount {
  231. let page = doucument?.page(at: i)
  232. pages.append(page!)
  233. indexs.insert(newInsertIndex)
  234. newInsertIndex += 1
  235. }
  236. self?.insertPagesForDescSort(pages: pages, indexs: indexs)
  237. }
  238. } else {
  239. var newInsertIndex: Int = insertIndex + 1
  240. var pages: [CPDFPage] = []
  241. var indexs: IndexSet = IndexSet()
  242. for i in 0 ..< doucument!.pageCount {
  243. let page = doucument?.page(at: i)
  244. pages.append(page!)
  245. indexs.insert(newInsertIndex)
  246. newInsertIndex += 1
  247. }
  248. self?.insertPagesForDescSort(pages: pages, indexs: indexs)
  249. }
  250. }
  251. }
  252. @objc private func item_insertBankPage(sender: NSMenuItem?) {
  253. let insertIndex: Int = self.thumbnailView.collectionView.selectionIndexes.last!
  254. let page = self.listView?.document.page(at: UInt(insertIndex))
  255. let document = CPDFDocument()
  256. document?.insertPage((page?.bounds.size)!, at: 0)
  257. let newPage: CPDFPage = (document?.page(at: 0))!
  258. self.insertPagesForDescSort(pages: [newPage], indexs: IndexSet(integer: insertIndex+1))
  259. }
  260. @objc private func item_insertPage(sender: NSMenuItem?) {
  261. let windowController = KMPageEditInsertCustomPageWindowController(windowNibName: "KMPageEditInsertCustomPageWindowController")
  262. let insertIndex: Int = self.thumbnailView.collectionView.selectionIndexes.last!
  263. let page = self.listView?.document.page(at: UInt(insertIndex))
  264. if (self.thumbnailView.collectionView.selectionIndexes.count > 0) {
  265. windowController.selectedPageSize = page!.bounds.size
  266. }
  267. self.view.window?.beginSheet(windowController.window!, completionHandler: { response in})
  268. windowController.itemClick = {
  269. [weak self] (index: Int) in
  270. if (index == 1) { /// 取消
  271. self?.view.window?.endSheet((windowController.window)!)
  272. return
  273. }
  274. /// 插入
  275. /// 样式
  276. let windowController_Insert: KMPageEditInsertCustomPageWindowController = windowController
  277. let type = windowController_Insert.typeIndex
  278. /// 页面大小
  279. let pageSize = windowController_Insert.pageSize
  280. /// 方向
  281. let direction = windowController_Insert.direction
  282. /// 插入位置
  283. let insertIndex: Int = insertIndex
  284. if (type == 1) { /// 空白页
  285. let document = CPDFDocument()
  286. document?.insertPage(pageSize, at: 0)
  287. let page: CPDFPage = (document?.page(at: 0))!
  288. if (direction == 0) { /// 纵向
  289. page.rotation = 90
  290. }
  291. self?.insertPagesForDescSort(pages: [page], indexs: IndexSet(integer: insertIndex+1))
  292. } else {
  293. let document = CPDFDocument()
  294. var imageName = "plaid"
  295. if (type == 2) {
  296. imageName = "horizontal_line"
  297. } else if (type == 3) {
  298. imageName = "five_line_score"
  299. }
  300. let imagePath = Bundle.main.pathForImageResource(imageName)
  301. document?.insertPage(pageSize, withImage: imagePath, at: 0)
  302. let page: CPDFPage = (document?.page(at: 0))!
  303. if (direction == 0) { /// 纵向
  304. page.rotation = 90
  305. }
  306. self?.insertPagesForDescSort(pages: [page], indexs: IndexSet(integer: insertIndex+1))
  307. }
  308. self?.view.window?.endSheet((windowController.window)!)
  309. }
  310. }
  311. @objc private func insertPagesForDescSort(pages: Array<CPDFPage>, indexs: IndexSet) {
  312. self.insertPages(pages: pages, indexs: indexs)
  313. /// 选中插入的页面
  314. self.selectPages(indexs: indexs)
  315. }
  316. private func selectPages(indexs: IndexSet, needScroll: Bool = true) {
  317. var selectPages: [Int] = []
  318. for index in indexs {
  319. selectPages.append(index+1)
  320. }
  321. DispatchQueue.main.async {
  322. var data = Set<IndexPath>()
  323. for index in selectPages {
  324. data.insert(IndexPath(item: index-1, section: 0))
  325. }
  326. self.thumbnailView.collectionView.deselectAll(nil)
  327. if needScroll {
  328. self.thumbnailView.collectionView.selectItems(at: data, scrollPosition: .centeredVertically)
  329. } else {
  330. self.thumbnailView.collectionView.selectItems(at: data, scrollPosition: NSCollectionView.ScrollPosition())
  331. }
  332. }
  333. }
  334. /// MARK: indexs 需要降序排序后
  335. @objc private func insertPages(pages: Array<CPDFPage>, indexs: IndexSet) {
  336. var count: Int = 0
  337. for index in indexs {
  338. if (count >= pages.count) {
  339. break
  340. }
  341. let newPage = pages[count].copy() as? CPDFPage
  342. if (newPage == nil) {
  343. continue
  344. }
  345. self.listView?.document.insertPageObject(newPage!, at: UInt(index))
  346. count += 1
  347. }
  348. self.listView.undoManager?.registerUndo(withTarget: self, selector: #selector(deletePages), object: indexs)
  349. self.listView?.layoutDocumentView()
  350. self.thumbnailView.reloadData()
  351. }
  352. /// MARK: indexs 需要降序排序后
  353. @objc private func deletePages(indexs: IndexSet) {
  354. let newIndexs = indexs.sorted()
  355. var array: Array<CPDFPage> = []
  356. for i in indexs {
  357. array.append((self.listView?.document.page(at: UInt(i)))!)
  358. }
  359. self.listView?.document.removePage(at: indexs)
  360. self.listView.undoManager?.registerUndo(withTarget: self) { target in
  361. target.insertPages(pages: array, indexs: indexs)
  362. }
  363. self.listView?.layoutDocumentView()
  364. self.thumbnailView.reloadData()
  365. }
  366. @IBAction func rotatePageItemAction(menu:NSMenuItem) {
  367. Task { @MainActor in
  368. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  369. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  370. return
  371. }
  372. let indexs = self.thumbnailView.collectionView.selectionIndexes
  373. let indexPaths = self.thumbnailView.collectionView.selectionIndexPaths
  374. if indexs.count >= 0 {
  375. var pageItems: [KMThumbnailPageItem] = []
  376. let newDocument = self.thumbnailView.document
  377. for index in indexs {
  378. let page : CPDFPage = newDocument.page(at: UInt(index))
  379. var rotation = page.rotation
  380. if rotation == 0 {
  381. rotation = 90
  382. } else if rotation == 90 {
  383. rotation = 180
  384. } else if rotation == 180 {
  385. rotation = 270
  386. } else if rotation == 270 {
  387. rotation = 0
  388. }
  389. let pageItem = KMThumbnailPageItem(page: page, rotate: rotation, oldRotate: page.rotation)
  390. pageItems.append(pageItem)
  391. }
  392. self.rotatePageItems(pageItems: pageItems, indexPaths: indexPaths)
  393. // 事件外面传递
  394. self.delegate?.controller?(controller: self, itemClick: menu, itemKey: .rightRotate, params: nil)
  395. }
  396. }
  397. }
  398. @IBAction func leftRotatePageItemAction(menu:NSMenuItem) {
  399. Task { @MainActor in
  400. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  401. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  402. return
  403. }
  404. let indexs = self.thumbnailView.collectionView.selectionIndexes
  405. let indexPaths = self.thumbnailView.collectionView.selectionIndexPaths
  406. if indexs.count >= 0 {
  407. var pageItems: [KMThumbnailPageItem] = []
  408. let newDocument = self.thumbnailView.document
  409. for index in indexs {
  410. let page : CPDFPage = newDocument.page(at: UInt(index))
  411. var rotation = page.rotation
  412. if rotation == 0 {
  413. rotation = 270
  414. } else if rotation == 90 {
  415. rotation = 0
  416. } else if rotation == 180 {
  417. rotation = 90
  418. } else if rotation == 270 {
  419. rotation = 180
  420. }
  421. let pageItem = KMThumbnailPageItem(page: page, rotate: rotation, oldRotate: page.rotation)
  422. pageItems.append(pageItem)
  423. }
  424. self.rotatePageItems(pageItems: pageItems, indexPaths: indexPaths)
  425. // 事件外面传递
  426. self.delegate?.controller?(controller: self, itemClick: menu, itemKey: .leftRotate, params: nil)
  427. }
  428. }
  429. }
  430. @IBAction func extractPageItemAction(menu:NSMenuItem) {
  431. let index = (self.thumbnailView.collectionView.selectionIndexes).first ?? -1
  432. if Int(index) >= 0 {
  433. let newDocument = self.thumbnailView.document
  434. var page : CPDFPage = newDocument.page(at: UInt(index))
  435. let filename : String = newDocument.documentURL.lastPathComponent
  436. let pageIndex = newDocument.index(for: page) + 1
  437. var newfileName : String = "\(NSString(string: filename).deletingPathExtension) page \(pageIndex)"
  438. newfileName = "\(newfileName)\(filename.extension)"
  439. let panel = NSSavePanel()
  440. panel.nameFieldStringValue = newfileName
  441. panel.canCreateDirectories = true
  442. panel.allowedFileTypes = ["pdf"]
  443. panel.isExtensionHidden = true
  444. panel.beginSheetModal(for: self.view.window!) { result in
  445. if result == .OK {
  446. let pdfdocument = CPDFDocument()
  447. let ret = pdfdocument!.importPages((self.thumbnailView.collectionView.selectionIndexes), from: self.thumbnailView.document, at: 0)
  448. if ret {
  449. let success = pdfdocument!.write(to:panel.url)
  450. if success {
  451. let workspace = NSWorkspace.shared
  452. workspace.activateFileViewerSelecting([panel.url!])
  453. }
  454. }
  455. }
  456. }
  457. }
  458. }
  459. @IBAction func pageEditItemAction(menu:NSMenuItem) {
  460. var indexs: [Int] = []
  461. for index in self.thumbnailView.collectionView.selectionIndexes {
  462. indexs.append(index)
  463. }
  464. self.delegate?.gotoPageEdit?(thumbnailViewController: self, pages: indexs)
  465. }
  466. @IBAction func deletePageItemAction(menu:NSMenuItem) {
  467. Task { @MainActor in
  468. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  469. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  470. return
  471. }
  472. let indexs = self.thumbnailView.collectionView.selectionIndexes
  473. if indexs.count > 0 {
  474. self.deletePageItemWithIndexs(indexs: indexs)
  475. // 事件外面传递
  476. self.delegate?.controller?(controller: self, itemClick: menu, itemKey: .delete, params: nil)
  477. }
  478. }
  479. }
  480. @IBAction func sharePageItemAction(menu:NSMenuItem) {
  481. let item = menu.parent!
  482. let index = (self.thumbnailView.collectionView.selectionIndexes).first ?? -1
  483. if Int(index) >= 0 {
  484. let doucument = self.thumbnailView.document
  485. let page = doucument.page(at: UInt(index))
  486. let filename : String = doucument.documentURL.lastPathComponent
  487. let folderPath = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(filename))!
  488. try? FileManager.default.removeItem(atPath: folderPath)
  489. let pdfdocument = CPDFDocument()
  490. let ret = pdfdocument!.importPages((self.thumbnailView.collectionView.selectionIndexes), from: self.thumbnailView.document, at: 0)
  491. let url = URL(fileURLWithPath: folderPath)
  492. if ret {
  493. let success = pdfdocument!.write(to:url)
  494. if success {
  495. let workspace = NSWorkspace.shared
  496. workspace.activateFileViewerSelecting([url])
  497. }
  498. }
  499. let represent : NSSharingService = menu.representedObject as! NSSharingService
  500. represent.perform(withItems: [url])
  501. }
  502. }
  503. @IBAction func copyItemAction(menu:NSMenuItem) {
  504. Task { @MainActor in
  505. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  506. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  507. return
  508. }
  509. }
  510. let indexs = self.thumbnailView.collectionView.selectionIndexes
  511. if indexs.count >= 0 {
  512. self.copysPages = []
  513. for i in indexs {
  514. let page = self.thumbnailView.document.page(at: UInt(i)).copy() as? CPDFPage
  515. self.copysPages.append(page ?? CPDFPage())
  516. }
  517. }
  518. }
  519. @IBAction func cutItemAction(menu:NSMenuItem) {
  520. Task { @MainActor in
  521. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  522. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  523. return
  524. }
  525. let indexs = self.thumbnailView.collectionView.selectionIndexes
  526. if indexs.count >= 0 {
  527. self.copysPages = []
  528. for i in indexs {
  529. let page = self.thumbnailView.document.page(at: UInt(i)).copy() as? CPDFPage
  530. self.copysPages.append(page ?? CPDFPage())
  531. }
  532. self.deletePageItemWithIndexs(indexs: indexs)
  533. // 事件传递到外面
  534. self.delegate?.controller?(controller: self, itemClick: menu, itemKey: .cut, params: nil)
  535. }
  536. }
  537. }
  538. @IBAction func pastePageItemAction(menu:NSMenuItem) {
  539. Task { @MainActor in
  540. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  541. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  542. return
  543. }
  544. var index = (self.thumbnailView.collectionView.selectionIndexes).last ?? -1
  545. if Int(index) >= 0 && self.copysPages.count > 0 {
  546. var pageItems: [KMThumbnailPageItem] = []
  547. for page in self.copysPages {
  548. index = index + 1
  549. let pageItem = KMThumbnailPageItem(page: page, index: index, oldIndex: index)
  550. pageItems.append(pageItem)
  551. }
  552. self.addPageItems(pageItems: pageItems)
  553. self.selectPages(indexs: IndexSet(integer: index))
  554. self.listView.go(toPageIndex: index, animated: true)
  555. // 事件传递到外面
  556. self.delegate?.controller?(controller: self, itemClick: menu, itemKey: .paste, params: nil)
  557. }
  558. }
  559. }
  560. @IBAction func printItemAction(menu:NSMenuItem) {
  561. var indexs:[Int] = []
  562. for index in self.thumbnailView.collectionView.selectionIndexes {
  563. indexs.append(index)
  564. }
  565. if indexs.count > 0 {
  566. self.delegate?.controller?(controller: self, itemClick: menu, itemKey: .print, params: indexs)
  567. }
  568. }
  569. }
  570. protocol KMThumbnailViewControllerAction {}
  571. extension KMThumbnailViewController: KMThumbnailViewControllerAction {
  572. @IBAction func cut(_ sender: Any) {
  573. self.cutItemAction(menu: NSMenuItem())
  574. }
  575. @IBAction func copy(_ sender: Any) {
  576. self.copyItemAction(menu: NSMenuItem())
  577. }
  578. @IBAction func paste(_ sender: Any) {
  579. self.pastePageItemAction(menu: NSMenuItem())
  580. }
  581. @IBAction func delete(_ sender: Any) {
  582. self.deletePageItemAction(menu: NSMenuItem())
  583. }
  584. @IBAction func escButtonAction(_ sender: NSButton) {
  585. self.cancelSelect()
  586. }
  587. func cancelSelect() {
  588. self.selectPages(indexs: [])
  589. self.km_resignFirstResponder()
  590. }
  591. }
  592. //MARK: KMPDFThumbnailViewDelegate
  593. extension KMThumbnailViewController : KMPDFThumbnailViewDelegate {
  594. func thumbnailView(thumbanView: KMPDFThumbnailView, didSelectPageAtIndex index: UInt, event: NSEvent) {
  595. NSApp.mainWindow?.makeFirstResponder(self)
  596. //是本地触发事件
  597. self.isLocalEvent = true
  598. if thumbanView.collectionView.selectionIndexes.count == 1 || (!event.modifierFlags.contains(NSEvent.ModifierFlags.command) &&
  599. !event.modifierFlags.contains(NSEvent.ModifierFlags.shift)) {
  600. let page : CPDFPage = self.listView.document.page(at: index)
  601. self.listView.go(toPageIndex: Int(page.pageIndex()), animated: true)
  602. self.thumbnailView.collectionView.deselectAll(nil)
  603. self.thumbnailView.collectionView.selectionIndexes = IndexSet(integer: IndexSet.Element(index))
  604. }
  605. var indexs: [Int] = []
  606. for index in self.thumbnailView.collectionView.selectionIndexes {
  607. indexs.append(index)
  608. }
  609. self.delegate?.pageDidSelect?(controller: self, pages: indexs)
  610. }
  611. func thumbnailView(thumbanView: KMPDFThumbnailView, item: KMPDFThumbnailItem, rightMouseDidSelect index: UInt, event: NSEvent) {
  612. self.addRightMenuItem(view: item, event: event)
  613. }
  614. func thumbnailView(thumbanView: KMPDFThumbnailView, sizeForItemAt indexpath: IndexPath) -> NSSize {
  615. if self.doublePageMode {
  616. return NSMakeSize(86, 147)
  617. } else {
  618. return NSMakeSize(156, 226)
  619. }
  620. }
  621. func thumbnailView(thumbanView: KMPDFThumbnailView, didDragPages pages: [Int], indexpath: IndexPath) {
  622. let toIndex = max(0, indexpath.item)
  623. var indexs = IndexSet()
  624. for page in pages {
  625. indexs.insert(page)
  626. }
  627. self.dragPagesForDescSort(indexs, toIndex)
  628. }
  629. func thumbnailView(thumbanView: KMPDFThumbnailView, insetForSectionAt section: Int) -> NSEdgeInsets {
  630. if self.doublePageMode {
  631. return NSEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
  632. } else {
  633. return NSEdgeInsets(top: 8, left: 24, bottom: 8, right: 24)
  634. }
  635. }
  636. }
  637. //MARK: NSMenuDelegate
  638. extension KMThumbnailViewController : NSMenuDelegate,NSMenuItemValidation {
  639. func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
  640. let action = menuItem.action
  641. if action == #selector(insertPageItemAction) ||
  642. action == #selector(insertPageItemAction) ||
  643. action == #selector(deletePageItemAction) ||
  644. action == #selector(rotatePageItemAction) ||
  645. action == #selector(leftRotatePageItemAction) ||
  646. action == #selector(copyItemAction) ||
  647. action == #selector(cutItemAction) ||
  648. action == #selector(printItemAction) ||
  649. action == #selector(sharePageItemAction) ||
  650. action == #selector(extractPageItemAction) {
  651. if self.thumbnailView.collectionView.selectionIndexes.count > 0 {
  652. return true
  653. } else {
  654. return false
  655. }
  656. }
  657. if action == #selector(pastePageItemAction) {
  658. if self.copysPages.count != 0 {
  659. return true
  660. } else {
  661. return false
  662. }
  663. }
  664. if (action == #selector(undo)) {
  665. return self.listView.undoManager?.canUndo ?? false
  666. }
  667. if (action == #selector(redo)) {
  668. return self.listView.undoManager?.canRedo ?? false
  669. }
  670. return true
  671. }
  672. func addRightMenuItem(view: KMPDFThumbnailItem, event: NSEvent) {
  673. let index = view.page.pageIndex()
  674. if !self.thumbnailView.collectionView.selectionIndexes.contains(IndexSet.Element(index)) {
  675. var indexs: IndexSet = IndexSet()
  676. indexs.insert(IndexSet.Element(index))
  677. self.selectPages(indexs: indexs, needScroll: false)
  678. //
  679. // //PDFView跳转
  680. self.isLocalEvent = true
  681. self.listView.go(toPageIndex: Int(view.page.pageIndex()), animated: true)
  682. }
  683. DispatchQueue.main.async { [unowned self] in
  684. let menu = NSMenu()
  685. var item = NSMenuItem()
  686. // item = menu.addItem(withTitle: NSLocalizedString("Insert", comment: ""), action: nil, target: self)
  687. // item.representedObject = row
  688. //
  689. // var subMenu = NSMenu()
  690. // var subitem = NSMenuItem()
  691. // subitem = subMenu.addItem(withTitle: NSLocalizedString("Insert File", comment: ""), action: #selector(insertPageItemAction), target: self, tag:0)
  692. // subitem.representedObject = row
  693. // subitem = subMenu.addItem(withTitle: NSLocalizedString("Insert blank page", comment: ""), action: #selector(insertPageItemAction), target: self, tag:1)
  694. // subitem.representedObject = row
  695. // subitem = subMenu.addItem(withTitle: NSLocalizedString("Insert page", comment: ""), action: #selector(insertPageItemAction), target: self, tag:2)
  696. // subitem.representedObject = row
  697. // item.submenu = subMenu
  698. // item = menu.addItem(withTitle: NSLocalizedString("Extract", comment: ""), action: #selector(extractPageItemAction), target: self)
  699. item = menu.addItem(withTitle: NSLocalizedString("Delete Page", comment: ""), action: #selector(deletePageItemAction), target: self)
  700. item.keyEquivalent = String(Unicode.Scalar(NSBackspaceCharacter)!)
  701. item.keyEquivalentModifierMask = []
  702. item = menu.addItem(withTitle: NSLocalizedString("Page Edit", comment: ""), action: #selector(pageEditItemAction), target: self)
  703. menu.addItem(NSMenuItem.separator())
  704. item = menu.addItem(withTitle: NSLocalizedString("Rotate Clockwise", comment: ""), action: #selector(rotatePageItemAction), target: self)
  705. item = menu.addItem(withTitle: NSLocalizedString("Rotate Counterclockwise", comment: ""), action: #selector(leftRotatePageItemAction), target: self)
  706. menu.addItem(NSMenuItem.separator())
  707. item = menu.addItem(withTitle: NSLocalizedString("Copy", comment: ""), action: #selector(copyItemAction), target: self)
  708. item.keyEquivalent = "c"
  709. item = menu.addItem(withTitle: NSLocalizedString("Cut", comment: ""), action: #selector(cutItemAction), target: self)
  710. item.keyEquivalent = "x"
  711. item = menu.addItem(withTitle: NSLocalizedString("Paste", comment: ""), action: #selector(pastePageItemAction), target: self)
  712. item.keyEquivalent = "v"
  713. menu.addItem(NSMenuItem.separator())
  714. item = menu.addItem(withTitle: NSLocalizedString("Print", comment: ""), action: #selector(printItemAction), target: self)
  715. let point = view.contentBox?.convert(event.locationInWindow, from: nil)
  716. menu.popUp(positioning: nil, at: point!, in: view.contentBox)
  717. // item = menu.addItem(withTitle: NSLocalizedString("Share", comment: ""), action: nil, target: self)
  718. // item.representedObject = row
  719. // item.submenu = NSSharingServicePicker.menu(forSharingItems: [self.listView.document.documentURL ?? ""], subjectContext: "", withTarget: self, selector: #selector(sharePageItemAction), serviceDelegate: nil)
  720. }
  721. }
  722. }
  723. //MARK: undoRedo
  724. extension KMThumbnailViewController {
  725. func rotatePageItems(pageItems: [KMThumbnailPageItem], indexPaths: Set<IndexPath>) {
  726. let tempPageItems = pageItems
  727. for pageItem in tempPageItems {
  728. pageItem.page.rotation = pageItem.rotate
  729. }
  730. self.listView.layoutDocumentView()
  731. self.thumbnailView.reloadData()
  732. self.thumbnailView.collectionView.selectItems(at: indexPaths, scrollPosition: .centeredVertically)
  733. self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
  734. self.isLocalEvent = true
  735. //替换下标顺序
  736. var tempPageItems: [KMThumbnailPageItem] = []
  737. for pageItem in pageItems {
  738. let item = KMThumbnailPageItem(page: pageItem.page, rotate: pageItem.oldRotate, oldRotate: pageItem.rotate)
  739. tempPageItems.append(item)
  740. }
  741. self.rotatePageItems(pageItems: tempPageItems, indexPaths: indexPaths)
  742. }
  743. }
  744. func deletePageItemWithIndexs(indexs: IndexSet) {
  745. if (indexs.count == (self.listView?.document.pageCount)!) {
  746. let _ = CustomAlertView(message: NSLocalizedString("Unable to delete all pages", comment: ""), from: self.thumbnailView, with: .blue)
  747. return
  748. }
  749. var pageItems: [KMThumbnailPageItem] = []
  750. for index in indexs {
  751. let page = self.listView.document.page(at: UInt(index))?.copy() as? CPDFPage
  752. if (page == nil) {
  753. continue
  754. }
  755. let pageItem = KMThumbnailPageItem(page: page!, index: index, oldIndex: index, bookMark: self.listView.document.bookmark(forPageIndex: UInt(index)))
  756. pageItems.append(pageItem)
  757. }
  758. self.deletePageItems(pageItems: pageItems)
  759. }
  760. func deletePageItems(pageItems: [KMThumbnailPageItem]) {
  761. //移除现有
  762. var tempPageItems = pageItems
  763. tempPageItems.sort(){$0.oldIndex > $1.oldIndex}
  764. for pageItem in tempPageItems {
  765. self.listView?.document.removePage(at: UInt(pageItem.oldIndex))
  766. }
  767. self.listView.layoutDocumentView()
  768. self.thumbnailView.reloadData()
  769. self.pdfCurrentPageChange()
  770. self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
  771. self.isLocalEvent = true
  772. self.addPageItems(pageItems: tempPageItems)
  773. }
  774. }
  775. func addPageItems(pageItems: [KMThumbnailPageItem]) {
  776. var tempPageItems = pageItems
  777. tempPageItems.sort(){$0.oldIndex < $1.oldIndex}
  778. for pageItem in tempPageItems {
  779. let newPage = pageItem.page
  780. self.listView?.document.insertPageObject(newPage, at: UInt(pageItem.oldIndex))
  781. }
  782. for pageItem in tempPageItems {
  783. if pageItem.bookMark != nil && pageItem.oldIndex < self.listView.document.pageCount {
  784. self.listView?.document.addBookmark(pageItem.bookMark!.label, forPageIndex: UInt(pageItem.oldIndex))
  785. }
  786. }
  787. self.listView.layoutDocumentView()
  788. self.thumbnailView.reloadData()
  789. self.pdfCurrentPageChange()
  790. self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
  791. self.isLocalEvent = true
  792. self.deletePageItems(pageItems: tempPageItems)
  793. }
  794. }
  795. func dragPageItems(pageItems: [KMThumbnailPageItem]) {
  796. var tempPageItems = pageItems
  797. //按照原下标顺序
  798. tempPageItems.sort(){$0.oldIndex > $1.oldIndex}
  799. //移除现有
  800. for pageItem in tempPageItems {
  801. self.listView?.document.removePage(at: UInt(pageItem.oldIndex))
  802. }
  803. //在原位置添加
  804. tempPageItems.sort(){$0.index < $1.index}
  805. for pageItem in tempPageItems {
  806. let newPage = pageItem.page
  807. self.listView?.document.insertPageObject(newPage, at: UInt(pageItem.index))
  808. }
  809. // 刷新UI
  810. self.listView?.layoutDocumentView()
  811. self.thumbnailView.reloadData()
  812. self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
  813. //替换下标顺序
  814. var tempPageItems: [KMThumbnailPageItem] = []
  815. for pageItem in pageItems {
  816. let item = KMThumbnailPageItem(page: pageItem.page, index: pageItem.oldIndex, oldIndex: pageItem.index)
  817. tempPageItems.append(item)
  818. }
  819. self.dragPageItems(pageItems: tempPageItems)
  820. }
  821. }
  822. @IBAction func undo(_ sender: Any) {
  823. if (self.listView.undoManager?.canUndo ?? false) {
  824. self.listView.undoManager?.undo()
  825. }
  826. }
  827. @IBAction func redo(_ sender: Any) {
  828. if (self.listView.undoManager?.canRedo ?? false) {
  829. self.listView.undoManager?.redo()
  830. }
  831. }
  832. }
  833. struct KMThumbnailPageItem {
  834. var page: CPDFPage
  835. var index: Int = 0
  836. var oldIndex: Int = 0
  837. var rotate: Int = 0
  838. var oldRotate: Int = 0
  839. var bookMark: CPDFBookmark?
  840. }