KMPDFEditViewController.swift 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. //
  2. // KMPDFEditViewController.swift
  3. // PDF Master
  4. //
  5. // Created by tangchao on 2023/1/6.
  6. //
  7. import Cocoa
  8. enum KMPageEditType: Int {
  9. case pageRange = 1
  10. case leftRotate = 2
  11. case rightRotate = 3
  12. case insert = 4
  13. case extract = 5
  14. case replace = 6
  15. case split = 7
  16. case reverse = 8
  17. case delete = 9
  18. }
  19. class KMPDFEditViewController: NSViewController {
  20. @IBOutlet weak var topBarBox: NSBox!
  21. @IBOutlet weak var contentBox: NSBox!
  22. var pageRangeView: KMDesignSelect?
  23. var pageRangeViewItems = [NSLocalizedString("All Pages", comment: ""),
  24. NSLocalizedString("Odd Pages", comment: ""),
  25. NSLocalizedString("Even Pages", comment: ""),
  26. NSLocalizedString("Horizontal Pages", comment: ""),
  27. NSLocalizedString("Vertical Pages", comment: ""),
  28. NSLocalizedString("Customized", comment: "")]
  29. var toolBar = KMToolbar()
  30. private var zoomOutButton: NSButton?
  31. private var zoomInButton: NSButton?
  32. lazy var rightItemView: NSView = {
  33. let view = NSView()
  34. let size: CGFloat = 28
  35. let y: CGFloat = 6
  36. let zoomOutButton = NSButton()
  37. view.addSubview(zoomOutButton)
  38. zoomOutButton.frame = NSMakeRect(0, y, size, size)
  39. zoomOutButton.isBordered = false
  40. zoomOutButton.image = NSImage(named: "KMImageNamePageEditZoomOut")
  41. zoomOutButton.target = self
  42. zoomOutButton.action = #selector(zoomOutButtonAction)
  43. self.zoomOutButton = zoomOutButton
  44. let zoomInButton = NSButton()
  45. view.addSubview(zoomInButton)
  46. zoomInButton.frame = NSMakeRect(size+7, y, size, size)
  47. zoomInButton.isBordered = false
  48. zoomInButton.image = NSImage(named: "KMImageNamePageEditZoomIn")
  49. zoomInButton.target = self
  50. zoomInButton.action = #selector(zoomInButtonAction)
  51. self.zoomInButton = zoomInButton
  52. return view
  53. }()
  54. var thumbnailView = KMPageEditThumbnailView()
  55. private var pdfDocument: CPDFDocument?
  56. var listView: CPDFView?
  57. var windowController: NSWindowController?
  58. var pageIsUpdate: Bool = true
  59. /// 临时存储 document
  60. private var documentCaches: [CPDFDocument] = []
  61. var selectedPages: [Int] = []
  62. var copysPages: Array<CPDFPage> = []
  63. private let defaultItemSize = NSMakeSize(218 + 12 * 2, 292 + 24)
  64. var itemSize: NSSize = NSMakeSize(218 + 12 * 2, 292 + 24)
  65. private var lockedFiles: Array<URL> = []
  66. private var undoRedoManager: UndoManager = UndoManager()
  67. // index=1 双击退出;index=2 打印
  68. var itemClick: KMCommonClickBlock?
  69. var documentEditedCallback: KMCommonBlock?
  70. required init?(coder: NSCoder) {
  71. super.init(coder: coder)
  72. }
  73. init(_ document: CPDFDocument) {
  74. super.init(nibName: "KMPDFEditViewController", bundle: nil)
  75. self.pdfDocument = document
  76. }
  77. override func viewDidAppear() {
  78. super.viewDidAppear()
  79. if (self.pdfDocument?.isLocked == false) {
  80. self.thumbnailView.document = self.pdfDocument!
  81. self.thumbnailView.reloadData()
  82. }
  83. if (self.selectedPages.isEmpty) {
  84. var index: Int = 0
  85. if (self.listView != nil) {
  86. index = self.listView!.currentPageIndex
  87. }
  88. self.selectPages(indexs: IndexSet(integer: index))
  89. self.pageRangeView?.stringValue = "\(index+1)"
  90. self.pageRangeView?.editable = true
  91. } else {
  92. var indexs: IndexSet = []
  93. for pageIndex in self.selectedPages {
  94. if (pageIndex < 0 || pageIndex >= (self.listView?.document.pageCount)!) {
  95. continue
  96. }
  97. indexs.insert(pageIndex)
  98. }
  99. self.selectPages(indexs: indexs)
  100. self.pageRangeView?.editable = true
  101. self.pageRangeView?.stringValue = KMPageRangeTools.newParseSelectedIndexs(selectedIndex: indexs.sorted())
  102. }
  103. self.view.window?.makeFirstResponder(self)
  104. }
  105. override func viewDidLoad() {
  106. super.viewDidLoad()
  107. self.thumbnailView.collectionView.backgroundColor(NSColor(hex: "#CED0D4"))
  108. let toolBar = self.toolBar
  109. self.topBarBox.contentView?.addSubview(toolBar)
  110. toolBar.frame = self.topBarBox.contentView!.bounds
  111. toolBar.autoresizingMask = [.width, .height]
  112. toolBar.delegate = self
  113. self.topBarBox.fillColor = NSColor(hex: "#F7F8FA")
  114. let rightItemView = self.rightItemView
  115. self.topBarBox.contentView?.addSubview(rightItemView)
  116. rightItemView.frame = NSMakeRect(NSWidth(self.topBarBox.contentView!.frame)-80, 0, 80, NSHeight(self.topBarBox.contentView!.frame))
  117. rightItemView.autoresizingMask = [.minXMargin]
  118. let view = self.thumbnailView
  119. self.contentBox.contentView?.addSubview(view)
  120. view.frame = self.contentBox.contentView!.bounds
  121. view.autoresizingMask = [.width, .height]
  122. self.thumbnailView.delegate = self
  123. self.thumbnailView.selectionDidChange = { [weak self] selectedIndexs in
  124. self?.view.window?.makeFirstResponder(self)
  125. var replaceEnable: Bool = false
  126. if (selectedIndexs.count == 1) { /// 替换item 置灰
  127. replaceEnable = true
  128. }
  129. var enabled: Bool = false
  130. if (selectedIndexs.count > 0) {
  131. enabled = true
  132. }
  133. if (self?.toolBar.items == nil) {
  134. return
  135. }
  136. var replaceItem: KMToolBoxItem?
  137. for i in 0 ..< (self?.toolBar.items.count)! {
  138. let item: KMToolBoxItem = (self?.toolBar.items[i])!
  139. if (item.itemIdentifier == KMToolbarPageEditReplaceItemIdentifier) {
  140. replaceItem = item
  141. }
  142. if (item.itemIdentifier == KMToolbarPageEditExtractItemIdentifier ||
  143. item.itemIdentifier == KMToolbarPageEditReverseItemIdentifier ||
  144. item.itemIdentifier == KMToolbarPageEditDeleteItemIdentifier ||
  145. item.itemIdentifier == KMToolbarPageEditLeftRotateItemIdentifier ||
  146. item.itemIdentifier == KMToolbarPageEditRightRotateItemIdentifier) {
  147. item.unEnabled = !enabled
  148. }
  149. }
  150. if (replaceItem != nil) {
  151. replaceItem?.unEnabled = !replaceEnable
  152. }
  153. if (self!.pageIsUpdate == false) {
  154. self?.pageIsUpdate = true
  155. return
  156. }
  157. var indexs: Array<Int> = []
  158. for indexPath in selectedIndexs {
  159. indexs.append(indexPath.item)
  160. }
  161. indexs.sort(){$0 < $1}
  162. self?.pageRangeView?.editable = true;
  163. self?.pageRangeView?.stringValue = KMPageRangeTools.newParseSelectedIndexs(selectedIndex: indexs)
  164. }
  165. let menu = NSMenu()
  166. menu.delegate = self
  167. self.view.menu = menu
  168. }
  169. // MARK: Private Methods
  170. private func copyPages(with indexs: IndexSet) {
  171. Task { @MainActor in
  172. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  173. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  174. return
  175. }
  176. if indexs.count > 0 {
  177. self.copysPages = []
  178. for i in indexs {
  179. let page = self.thumbnailView.document.page(at: UInt(i)).copy() as? CPDFPage
  180. if (page == nil) {
  181. continue
  182. }
  183. self.copysPages.append(page!)
  184. }
  185. }
  186. }
  187. }
  188. private func cutPages(with indexs: IndexSet) {
  189. if indexs.count > 0 {
  190. if (indexs.count == (self.listView?.document.pageCount)!) {
  191. let _ = CustomAlertView(message: NSLocalizedString("Unable to delete all pages", comment: ""), from: self.thumbnailView, with: .blue)
  192. return
  193. }
  194. self.copysPages = []
  195. for i in indexs {
  196. let page = self.thumbnailView.document.page(at: UInt(i)).copy() as? CPDFPage
  197. if (page == nil) {
  198. continue
  199. }
  200. self.copysPages.append(page!)
  201. }
  202. self.clearSelectPages()
  203. self.deletePages(indexs: indexs)
  204. // 提醒外面文档已编辑
  205. if (self.documentEditedCallback != nil) {
  206. self.documentEditedCallback!()
  207. }
  208. }
  209. }
  210. private func pastePages(at index: Int) {
  211. Task { @MainActor in
  212. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  213. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  214. return
  215. }
  216. if (index >= 0 && self.copysPages.count > 0) {
  217. var indexs: IndexSet = IndexSet()
  218. for (i, _) in self.copysPages.enumerated() {
  219. indexs.insert(index+i+1)
  220. }
  221. self.insertPagesForDescSort(pages: self.copysPages, indexs: indexs)
  222. // 提醒外面文档已编辑
  223. if (self.documentEditedCallback != nil) {
  224. self.documentEditedCallback!()
  225. }
  226. var indexpaths: Set<IndexPath> = []
  227. indexpaths.insert(IndexPath(item: index, section: 0))
  228. self.thumbnailView.collectionView.animator().scrollToItems(at: indexpaths, scrollPosition: .top)
  229. }
  230. }
  231. }
  232. private func getSelecteIndex() -> Int {
  233. var index: Int = 0
  234. for indexpath in self.thumbnailView.selectionIndexPaths {
  235. index = indexpath.item
  236. }
  237. return index
  238. }
  239. private func getSelectedPage() -> CPDFPage {
  240. return (self.pdfDocument!.page(at: UInt(getSelecteIndex())))!
  241. }
  242. private func showPasswordWindow(_ insertIndex: Int) {
  243. if (self.lockedFiles.count > 0) {
  244. let fileURL = self.lockedFiles.first
  245. KMPasswordInputWindow.openWindow(window: self.view.window!, type: .open, url: fileURL!) { result, password in
  246. if (result == .cancel) { /// 取消
  247. self.lockedFiles.removeFirst()
  248. if (self.lockedFiles.count > 0) {
  249. self.showPasswordWindow(insertIndex)
  250. }
  251. return
  252. }
  253. /// 解密成功
  254. let document = CPDFDocument(url: fileURL)
  255. document?.unlock(withPassword: password)
  256. var newInsertIndex: Int = insertIndex
  257. var pages: [CPDFPage] = []
  258. var indexs: IndexSet = IndexSet()
  259. for i in 0 ..< document!.pageCount {
  260. let page = document?.page(at: i)
  261. pages.append(page!)
  262. indexs.insert(newInsertIndex)
  263. newInsertIndex += 1
  264. }
  265. self.insertPagesForDescSort(pages: pages, indexs: indexs)
  266. self.lockedFiles.removeFirst()
  267. if (self.lockedFiles.count > 0) {
  268. self.showPasswordWindow(newInsertIndex)
  269. }
  270. }
  271. }
  272. }
  273. @objc private func insertPagesForDescSort(pages: Array<CPDFPage>, indexs: IndexSet) {
  274. self.insertPages(pages: pages, indexs: indexs)
  275. /// 选中插入的页面
  276. self.selectPages(indexs: indexs)
  277. }
  278. private func selectPages(indexs: IndexSet) {
  279. var indexpaths: Set<IndexPath> = []
  280. for index in indexs {
  281. indexpaths.insert(IndexPath(item: index, section: 0))
  282. }
  283. self.thumbnailView.selectPages(at: indexpaths)
  284. }
  285. // MARK: -
  286. // MARK: - 清空选择
  287. private func clearSelectPages() {
  288. self.selectPages(indexs: IndexSet())
  289. }
  290. private func refreshUI(indexs: IndexSet = []) {
  291. if (Thread.isMainThread) {
  292. self.listView?.layoutDocumentView()
  293. var indexpaths: Set<IndexPath> = []
  294. for index in indexs {
  295. indexpaths.insert(IndexPath(item: index, section: 0))
  296. }
  297. self.thumbnailView.refreshUI(indexs: indexpaths)
  298. } else {
  299. DispatchQueue.main.async {
  300. self.listView?.layoutDocumentView()
  301. var indexpaths: Set<IndexPath> = []
  302. for index in indexs {
  303. indexpaths.insert(IndexPath(item: index, section: 0))
  304. }
  305. self.thumbnailView.refreshUI(indexs: indexpaths)
  306. }
  307. }
  308. }
  309. private func refreshUIForKeepSelecteds(indexs: IndexSet = []) {
  310. let indexpaths = self.thumbnailView.selectionIndexPaths
  311. self.refreshUI(indexs: indexs)
  312. self.thumbnailView.selectPages(at: indexpaths)
  313. }
  314. // MARK: Undo / Redo
  315. @objc private func leftRotate(indexs: IndexSet) {
  316. Task { @MainActor in
  317. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  318. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  319. return
  320. }
  321. if (indexs.count <= 0) {
  322. return
  323. }
  324. // 提醒外面文档已编辑
  325. if (self.documentEditedCallback != nil) {
  326. self.documentEditedCallback!()
  327. }
  328. for i in 0 ..< (self.listView?.document.pageCount)! {
  329. if (indexs.contains(IndexSet.Element(i))) {
  330. let page = self.listView?.document.page(at: i)
  331. if (page == nil) {
  332. continue
  333. }
  334. page!.rotation = (page!.rotation-90)%360
  335. }
  336. }
  337. self.undoRedoManager.registerUndo(withTarget: self, selector: #selector(rightRotate), object: indexs)
  338. self.refreshUIForKeepSelecteds(indexs: indexs)
  339. }
  340. }
  341. @objc private func rightRotate(indexs: IndexSet) {
  342. Task { @MainActor in
  343. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  344. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  345. return
  346. }
  347. if (indexs.count <= 0) {
  348. return
  349. }
  350. // 提醒外面文档已编辑
  351. if (self.documentEditedCallback != nil) {
  352. self.documentEditedCallback!()
  353. }
  354. for i in 0 ..< (self.listView?.document.pageCount)! {
  355. if (indexs.contains(IndexSet.Element(i))) {
  356. let page = self.listView?.document.page(at: i)
  357. if (page == nil) {
  358. continue
  359. }
  360. page!.rotation = (page!.rotation+90)%360
  361. }
  362. }
  363. self.undoRedoManager.registerUndo(withTarget: self, selector: #selector(leftRotate), object: indexs)
  364. self.refreshUIForKeepSelecteds(indexs: indexs)
  365. }
  366. }
  367. @objc private func insertPages(pages: Array<CPDFPage>, indexs: IndexSet) {
  368. var count: Int = 0
  369. for index in indexs {
  370. if (count >= pages.count) {
  371. break
  372. }
  373. if (index > (self.listView?.document.pageCount)!) {
  374. break
  375. }
  376. let newPage = pages[count]
  377. self.listView?.document.insertPageObject(newPage, at: UInt(index))
  378. count += 1
  379. }
  380. self.undoRedoManager.registerUndo(withTarget: self, selector: #selector(deletePages), object: indexs)
  381. self.refreshUI()
  382. }
  383. @objc private func deletePages(indexs: IndexSet) {
  384. if (indexs.count <= 0) {
  385. return
  386. }
  387. if (indexs.count == (self.listView?.document.pageCount)!) {
  388. let _ = CustomAlertView(message: NSLocalizedString("Unable to delete all pages", comment: ""), from: self.thumbnailView, with: .blue)
  389. return
  390. }
  391. // 提醒外面文档已编辑
  392. if (self.documentEditedCallback != nil) {
  393. self.documentEditedCallback!()
  394. }
  395. var array: Array<CPDFPage> = []
  396. for i in indexs {
  397. let page = self.listView?.document.page(at: UInt(i)).copy() as? CPDFPage
  398. if (page != nil) {
  399. array.append(page!)
  400. }
  401. }
  402. self.listView?.document.removePage(at: indexs)
  403. self.undoRedoManager.registerUndo(withTarget: self) { target in
  404. target.insertPages(pages: array, indexs: indexs)
  405. }
  406. self.refreshUI()
  407. }
  408. @objc private func reversePages(indexs: IndexSet) {
  409. KMPageEditTools.reverse((self.listView?.document)!, indexs
  410. ) { result, error in
  411. if (result) {
  412. self.refreshUI()
  413. self.undoRedoManager.registerUndo(withTarget: self, selector: #selector(self.reversePages), object: indexs)
  414. }
  415. }
  416. }
  417. @objc private func dragPages(_ indexs: IndexSet, _ toIndex: Int, reversed: Bool = false) {
  418. if (indexs.count <= 0) {
  419. return
  420. }
  421. // 插入位置偏移量
  422. var toIndexOffset: Int = 0
  423. // 需要移动的页面index数组
  424. var newPages: [CPDFPage] = []
  425. // 从后面往前删除
  426. for index in indexs.reversed() {
  427. let newPage = (self.listView?.document.page(at: UInt(index)))?.copy() as? CPDFPage
  428. if (newPage == nil) {
  429. continue
  430. }
  431. newPages.insert(newPage!, at: 0)
  432. self.listView?.document.removePage(at: UInt(index))
  433. if (index < toIndex) { /// 删除了插入位置前面的页面,需要改变 toIndex
  434. toIndexOffset += 1
  435. }
  436. }
  437. if (indexs.last! < toIndex) { // 往后拖拽
  438. toIndexOffset -= 1
  439. }
  440. let insertIndex = max(0, toIndex-toIndexOffset)
  441. var selectIndexs: IndexSet = []
  442. for (index, page) in newPages.enumerated() {
  443. self.listView?.document.insertPageObject(page, at: UInt(insertIndex+index))
  444. selectIndexs.insert(insertIndex+index)
  445. }
  446. // 新增 undo
  447. self.undoRedoManager.registerUndo(withTarget: self) { target in
  448. target.clearSelectPages()
  449. target.dragPages_reversed(indexs, toIndex, newPages)
  450. }
  451. // 刷新UI
  452. self.refreshUI()
  453. if (reversed == false) {
  454. self.selectPages(indexs: selectIndexs)
  455. }
  456. }
  457. @objc private func dragPages_reversed(_ indexs: IndexSet, _ toIndex: Int, _ pages: [CPDFPage]) {
  458. if (indexs.count <= 0) {
  459. return
  460. }
  461. // 插入位置偏移量
  462. var toIndexOffset: Int = 0
  463. for index in indexs {
  464. if (index < toIndex) { /// 删除了插入位置前面的页面,需要改变 toIndex
  465. toIndexOffset += 1
  466. }
  467. }
  468. if (indexs.last! < toIndex) { // 往后拖拽
  469. toIndexOffset -= 1
  470. }
  471. let insertIndex = max(0, toIndex-toIndexOffset)
  472. // 需要移动的页面index数组
  473. var datas: [Int] = []
  474. for index in insertIndex ..< (insertIndex + indexs.count) {
  475. datas.append(index)
  476. }
  477. // 从后面开始删除
  478. for index in datas.reversed() {
  479. self.listView?.document.removePage(at: UInt(index))
  480. }
  481. // 再插入到对应的位置
  482. for (index,value) in indexs.enumerated() {
  483. var page: CPDFPage?
  484. if (index < pages.count) {
  485. page = pages[index]
  486. }
  487. if (page != nil) {
  488. self.listView?.document.insertPageObject(page!, at: UInt(value))
  489. }
  490. }
  491. // 新增 undo
  492. self.undoRedoManager.registerUndo(withTarget: self) { target in
  493. target.dragPages(indexs, toIndex, reversed: true)
  494. }
  495. // 刷新UI
  496. self.refreshUI()
  497. }
  498. // MARK: topBar 事件
  499. @objc func zoomOutButtonAction(sender: NSButton) {
  500. if (self.itemSize.width > self.defaultItemSize.width) {
  501. return
  502. }
  503. if (self.itemSize.width < self.defaultItemSize.width) {
  504. self.itemSize = self.defaultItemSize
  505. } else if (self.itemSize.width == self.defaultItemSize.width) {
  506. self.itemSize = NSSize(width: self.defaultItemSize.width*1.5, height: self.defaultItemSize.height*1.5)
  507. }
  508. self.zoomInButton?.isEnabled = true
  509. if (self.itemSize.width > self.defaultItemSize.width) {
  510. sender.isEnabled = false
  511. }
  512. self.thumbnailView.zoomOut()
  513. }
  514. @objc func zoomInButtonAction(sender: NSButton) {
  515. if (self.itemSize.width < self.defaultItemSize.width) {
  516. return
  517. }
  518. if (self.itemSize.width > self.defaultItemSize.width) {
  519. self.itemSize = self.defaultItemSize
  520. } else if (self.itemSize.width == self.defaultItemSize.width) {
  521. self.itemSize = NSSize(width: self.defaultItemSize.width*0.5, height: self.defaultItemSize.height*0.5)
  522. }
  523. self.zoomOutButton?.isEnabled = true
  524. if (self.itemSize.width < self.defaultItemSize.width) {
  525. sender.isEnabled = false
  526. }
  527. self.thumbnailView.zoomIn()
  528. }
  529. // MARK: menu 菜单事件
  530. @objc func item_insertFile(sender: NSMenuItem?) {
  531. let panel = NSOpenPanel()
  532. panel.allowedFileTypes = ["pdf"]
  533. panel.allowsMultipleSelection = true
  534. panel.beginSheetModal(for: self.view.window!) { [weak self] response in
  535. if (response == .cancel) {
  536. return
  537. }
  538. /// 处理page
  539. var insertIndex: Int = (self?.getSelecteIndex())!
  540. self!.lockedFiles.removeAll()
  541. var pages: Array<CPDFPage> = []
  542. self?.documentCaches.removeAll()
  543. var indexs = IndexSet()
  544. for fileURL in panel.urls {
  545. let document = CPDFDocument(url: fileURL)
  546. if ((document?.isLocked)!) {
  547. self?.lockedFiles.append(fileURL)
  548. continue
  549. }
  550. self?.documentCaches.append(document!)
  551. for i in 0 ..< document!.pageCount {
  552. let page = document?.page(at: i)
  553. pages.append(page!)
  554. insertIndex += 1
  555. indexs.insert(insertIndex)
  556. }
  557. }
  558. self?.insertPagesForDescSort(pages: pages, indexs: indexs)
  559. if ((self?.lockedFiles.count)! <= 0) {
  560. self?.refreshUI()
  561. return
  562. }
  563. self?.refreshUI()
  564. self!.showPasswordWindow(insertIndex)
  565. }
  566. }
  567. @objc func item_insertBlankPage(sender: NSMenuItem?) {
  568. let index = self.getSelecteIndex()
  569. let page = self.listView?.document.page(at: UInt(index))
  570. self.documentCaches.removeAll()
  571. let document = CPDFDocument()
  572. document?.insertPage((page?.bounds.size)!, at: 0)
  573. self.documentCaches.append(document!)
  574. let newPage: CPDFPage = (document?.page(at: 0))!
  575. self.insertPagesForDescSort(pages: [newPage], indexs: IndexSet(integer: index+1))
  576. }
  577. @objc func item_insertCustomPage(sender: NSMenuItem?) {
  578. let windowController = KMPageEditInsertCustomPageWindowController(windowNibName: "KMPageEditInsertCustomPageWindowController")
  579. if (self.thumbnailView.selectionIndexPaths.count > 0) {
  580. windowController.selectedPageSize = self.getSelectedPage().bounds.size
  581. }
  582. self.windowController = windowController
  583. self.view.window?.beginSheet(windowController.window!, completionHandler: { response in})
  584. windowController.itemClick = {
  585. [weak self] (index: Int) in
  586. if (index == 1) { /// 取消
  587. self?.view.window?.endSheet((self!.windowController?.window)!)
  588. self?.windowController = nil
  589. return
  590. }
  591. /// 插入
  592. /// 样式
  593. let windowController_Insert: KMPageEditInsertCustomPageWindowController = self?.windowController as! KMPageEditInsertCustomPageWindowController
  594. let type = windowController_Insert.typeIndex
  595. /// 页面大小
  596. let pageSize = windowController_Insert.pageSize
  597. /// 方向
  598. let direction = windowController_Insert.direction
  599. /// 插入位置
  600. let insertIndex: Int = (self?.getSelecteIndex())!
  601. if (type == 1) { /// 空白页
  602. let document = CPDFDocument()
  603. document?.insertPage(pageSize, at: 0)
  604. let page: CPDFPage = (document?.page(at: 0))!
  605. if (direction == 0) { /// 纵向
  606. page.rotation = 90
  607. }
  608. self?.insertPagesForDescSort(pages: [page], indexs: IndexSet(integer: insertIndex+1))
  609. } else {
  610. let document = CPDFDocument()
  611. var imageName = "plaid"
  612. if (type == 2) {
  613. imageName = "horizontal_line"
  614. } else if (type == 3) {
  615. imageName = "five_line_score"
  616. }
  617. let imagePath = Bundle.main.pathForImageResource(imageName)
  618. document?.insertPage(pageSize, withImage: imagePath, at: 0)
  619. let page: CPDFPage = (document?.page(at: 0))!
  620. if (direction == 0) { /// 纵向
  621. page.rotation = 90
  622. }
  623. self?.insertPagesForDescSort(pages: [page], indexs: IndexSet(integer: insertIndex+1))
  624. }
  625. self?.view.window?.endSheet((self?.windowController?.window)!)
  626. self?.windowController = nil
  627. }
  628. }
  629. // MARK: toolBar 菜单事件
  630. @objc func pageRangeMenuAction(sender: KMToolbarClickButton) {
  631. }
  632. @objc func leftRotateMenuAction(sender: KMToolbarClickButton?) {
  633. let selectedIndexs = self.thumbnailView.selectionIndexPaths
  634. var indexs: IndexSet = []
  635. for indexpath in selectedIndexs {
  636. indexs.insert(indexpath.item)
  637. }
  638. self.leftRotate(indexs: indexs)
  639. }
  640. @objc func rightRotateMenuAction(sender: KMToolbarClickButton?) {
  641. let selectedIndexs = self.thumbnailView.selectionIndexPaths
  642. var indexs: IndexSet = []
  643. for indexpath in selectedIndexs {
  644. indexs.insert(indexpath.item)
  645. }
  646. self.rightRotate(indexs: indexs)
  647. }
  648. @objc func insertMenuAction(sender: KMToolbarClickButton) {
  649. let menu = NSMenu()
  650. let insertFileItem = NSMenuItem(title: "Insert File", action: #selector(item_insertFile), target: self)
  651. menu.addItem(insertFileItem!)
  652. let insertBlankPageItem = NSMenuItem(title: "Insert a blank page", action: #selector(item_insertBlankPage), target: self)
  653. menu.addItem(insertBlankPageItem!)
  654. let insertCustomPageItem = NSMenuItem(title: "Insert custom page", action: #selector(item_insertCustomPage), target: self)
  655. menu.addItem(insertCustomPageItem!)
  656. menu.popUp(positioning: nil, at: NSPoint(x: 0, y: 40), in: sender)
  657. }
  658. @objc func extractMenuAction(sender: KMToolbarClickButton?) {
  659. if (self.thumbnailView.selectionIndexPaths.count == 0) {
  660. let alert = NSAlert()
  661. alert.messageText = "请选择需要提取的页面"
  662. alert.runModal()
  663. return
  664. }
  665. let windowController = KMPageEditExtractWindowController(windowNibName: "KMPageEditSettingBaseWindowController")
  666. self.view.window?.beginSheet(windowController.window!)
  667. self.windowController = windowController
  668. windowController.itemClick = { [weak self] index, value in
  669. if (index == 1) { /// 取消
  670. self?.view.window?.endSheet((self?.windowController?.window)!)
  671. self?.windowController = nil
  672. return
  673. }
  674. let windowController_extract: KMPageEditExtractWindowController = self?.windowController as! KMPageEditExtractWindowController
  675. /// 提取设置项
  676. let settingView: KMPageEditExtractSettingView = windowController_extract.settingView! as! KMPageEditExtractSettingView
  677. let oneDocumentPerPage: Bool = settingView.independentPerPageCheck.state != .on
  678. let extractAfterDelete: Bool = settingView.extractAfterDeletePageCheck.state == .on
  679. self?.view.window?.endSheet((self?.windowController!.window)!)
  680. self?.windowController = nil
  681. // /// 提取的页面
  682. let indexpaths = self?.thumbnailView.selectionIndexPaths
  683. var indexs: IndexSet = []
  684. var extractPages: Array<CPDFPage> = []
  685. for indexpath in indexpaths! {
  686. let page = self?.listView?.document.page(at: UInt(indexpath.item))
  687. if (page != nil) {
  688. extractPages.append(page!)
  689. }
  690. indexs.insert(indexpath.item)
  691. }
  692. KMPageEditTools.extract((self?.listView?.document)!, indexs, oneDocumentPerPage, (self?.view.window)!) { result, urls, error in
  693. if (result == false) {
  694. return
  695. }
  696. if (extractAfterDelete) {
  697. var indexs: IndexSet = IndexSet()
  698. for page in extractPages {
  699. let indexPage: Int = Int((self?.listView?.document.index(for: page))!)
  700. indexs.insert(indexPage)
  701. }
  702. self?.deletePages(indexs: indexs)
  703. }
  704. }
  705. }
  706. }
  707. @objc func replaceMenuAction(sender: KMToolbarClickButton?) {
  708. let panel = NSOpenPanel()
  709. panel.allowedFileTypes = ["pdf"]
  710. panel.allowsMultipleSelection = true
  711. panel.beginSheetModal(for: self.view.window!) { [weak self] response in
  712. if (response == .cancel) {
  713. return
  714. }
  715. /// 处理page
  716. var pages: Array<CPDFPage> = []
  717. let selectedIndex: Int = (self?.getSelecteIndex())!
  718. self?.listView?.document.removePage(at: UInt(selectedIndex))
  719. var insertIndex: Int = selectedIndex
  720. self?.lockedFiles.removeAll()
  721. for fileURL in panel.urls {
  722. let document = CPDFDocument(url: fileURL)
  723. if ((document?.isLocked)!) {
  724. self?.lockedFiles.append(fileURL)
  725. continue
  726. }
  727. for i in 0 ..< document!.pageCount {
  728. let page = document?.page(at: i)
  729. pages.append(page!)
  730. self!.listView?.document.insertPageObject(page, at:UInt(insertIndex))
  731. insertIndex += 1
  732. }
  733. }
  734. if ((self?.lockedFiles.count)! <= 0) {
  735. self?.refreshUI()
  736. return
  737. }
  738. self?.refreshUI()
  739. self!.showPasswordWindow(insertIndex)
  740. }
  741. }
  742. @objc func splitMenuAction(sender: KMToolbarClickButton) {
  743. let model = KMPageEditSplitSettingModel()
  744. model.documentURL = self.listView?.document.documentURL
  745. model.fileName = model.documentURL.lastPathComponent
  746. model.pathExtension = model.fileName.components(separatedBy: ".").last
  747. if (self.thumbnailView.selectionIndexPaths.count > 0) {
  748. model.type = 2
  749. model.pageRangeType = 2
  750. var selectedIndexs: Array<Int> = []
  751. for indexpath in self.thumbnailView.selectionIndexPaths {
  752. selectedIndexs.append(indexpath.item)
  753. }
  754. model.pageRangeString = KMPageRangeTools.newParseSelectedIndexs(selectedIndex: selectedIndexs)
  755. } else {
  756. model.type = 0
  757. }
  758. let windowController = KMPageEditSplitWindowController(model)
  759. self.view.window?.beginSheet(windowController.window!)
  760. self.windowController = windowController
  761. windowController.itemClick = { [weak self] index, value in
  762. if (index == 1) { /// 取消
  763. self?.view.window?.endSheet((self?.windowController!.window)!)
  764. self?.windowController = nil
  765. return
  766. }
  767. /// 拆分
  768. let windowController_split: KMPageEditSplitWindowController = self?.windowController as! KMPageEditSplitWindowController
  769. let outputModel: KMPageEditSplitSettingModel = windowController_split.model! as! KMPageEditSplitSettingModel
  770. self?.view.window?.endSheet((self?.windowController!.window)!)
  771. self?.windowController = nil
  772. let panel = NSOpenPanel()
  773. panel.canChooseFiles = false
  774. panel.canChooseDirectories = true
  775. panel.canCreateDirectories = true
  776. let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
  777. button.state = .off
  778. panel.accessoryView = button
  779. panel.beginSheetModal(for: (self?.view.window)!) { response in
  780. if (response == .cancel) {
  781. return
  782. }
  783. KMPageEditTools.split((self?.listView?.document)!, outputModel, panel.url!.path, outputModel.outputFileNameDeletePathExtension) { result, outputFilepaths, error in
  784. if (result) {
  785. if (button.state == .on) {
  786. for filepath in outputFilepaths! {
  787. if !filepath.isPDFValid() {
  788. let alert = NSAlert()
  789. alert.alertStyle = .critical
  790. alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  791. alert.runModal()
  792. } else {
  793. NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: filepath), display: true) { document, alreadyOpen, error in
  794. }
  795. }
  796. }
  797. } else {
  798. var urls: [URL] = []
  799. for filepath in outputFilepaths! {
  800. urls.append(URL(fileURLWithPath: filepath))
  801. }
  802. NSWorkspace.shared.activateFileViewerSelecting(urls)
  803. }
  804. }
  805. }
  806. }
  807. }
  808. }
  809. @objc func reverseMenuAction(sender: KMToolbarClickButton) {
  810. let selectedIndexs = self.thumbnailView.selectionIndexPaths
  811. if (selectedIndexs.count < 2 ) {
  812. let _ = CustomAlertView(message: "请先选择至少两个页面进行编辑操作", from: self.thumbnailView, with: .blue)
  813. return
  814. }
  815. var indexs: IndexSet = []
  816. for indexpath in selectedIndexs {
  817. indexs.insert(indexpath.item)
  818. }
  819. self.reversePages(indexs: indexs)
  820. }
  821. @objc func deleteMenuAction(sender: KMToolbarClickButton) {
  822. Task { @MainActor in
  823. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  824. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  825. return
  826. }
  827. var indexs: IndexSet = IndexSet()
  828. for indexPath in self.thumbnailView.selectionIndexPaths {
  829. indexs.insert(indexPath.item)
  830. }
  831. self.clearSelectPages()
  832. self.deletePages(indexs: indexs)
  833. }
  834. }
  835. }
  836. // MARK: -
  837. // MARK: KMNewToolbarDelegate
  838. extension KMPDFEditViewController: KMNewToolbarDelegate {
  839. func toolbarDefaultItemIdentifiers(_ toolbar: KMToolbar!) -> [String]! {
  840. return [KMToolbarPageEditPageRangeItemIdentifier,
  841. KMToolbarPageEditLeftRotateItemIdentifier,
  842. KMToolbarPageEditRightRotateItemIdentifier,
  843. // KMToolbarDividerItemIdentifier,
  844. // KMToolbarPageEditInsetItemIdentifier,
  845. // KMToolbarPageEditExtractItemIdentifier,
  846. // KMToolbarPageEditReplaceItemIdentifier,
  847. // KMToolbarPageEditSplitItemIdentifier,
  848. // KMToolbarPageEditReverseItemIdentifier,
  849. KMToolbarDividerItemIdentifier,
  850. KMToolbarPageEditDeleteItemIdentifier]
  851. }
  852. func toolbar(_ toolbar: KMToolbar!, itemForItemIdentifier identifier: String!) -> KMToolBoxItem! {
  853. let item = KMToolBoxItem(itemIdentifier: identifier)
  854. if (identifier == KMToolbarPageEditPageRangeItemIdentifier) {
  855. // item?.image = NSImage(named: "KMImageNameMainToolbarrRight")
  856. item?.alternateImage = NSImage(named: "KMImageNameMainToolbarrRight")
  857. item?.target = self
  858. item?.btnTag = KMPageEditType.pageRange.rawValue
  859. item?.toolTip = NSLocalizedString("pageRange", comment: "")
  860. item?.titleName = NSLocalizedString("pageRange ", comment: "")
  861. item?.boxImagePosition = KMToolBoxImagePosition.left
  862. item?.btnAction = #selector(pageRangeMenuAction)
  863. let view = NSView()
  864. item?.addSubview(view)
  865. view.frame = item!.bounds
  866. view.autoresizingMask = [.width,.height]
  867. view.wantsLayer = true
  868. view.layer?.backgroundColor = NSColor(hex: "#F7F8FA").cgColor
  869. let comBoxView = KMDesignSelect(withType: .Combox)
  870. view.addSubview(comBoxView.view)
  871. comBoxView.view.frame = NSMakeRect(0, 8, NSWidth(view.frame), 24)
  872. comBoxView.view.autoresizingMask = [.width]
  873. comBoxView.removeAllItems()
  874. comBoxView.addItems(withObjectValues: self.pageRangeViewItems)
  875. comBoxView.selectItem(at: 0)
  876. comBoxView.placeholderString = NSLocalizedString("eg .1,3-5,10", comment: "")
  877. comBoxView.editable = false
  878. comBoxView.delete = self
  879. pageRangeView = comBoxView
  880. let menuItem = NSMenuItem.init(title: "pageRange", action: #selector(pageRangeMenuAction), target: self)
  881. item?.menuFormRepresentation = menuItem
  882. } else if (identifier == KMToolbarPageEditLeftRotateItemIdentifier) {
  883. item?.image = NSImage(named: "KMImageNameMainToolPageLeftRotate")
  884. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageLeftRotate")
  885. item?.target = self
  886. item?.btnTag = KMPageEditType.leftRotate.rawValue
  887. item?.toolTip = NSLocalizedString("Rotate Left", comment: "")
  888. item?.titleName = NSLocalizedString("", comment: "")
  889. item?.boxImagePosition = KMToolBoxImagePosition.left
  890. item?.btnAction = #selector(leftRotateMenuAction)
  891. let menuItem = NSMenuItem.init(title: "", action: #selector(leftRotateMenuAction), target: self)
  892. item?.menuFormRepresentation = menuItem
  893. } else if (identifier == KMToolbarPageEditRightRotateItemIdentifier) {
  894. item?.image = NSImage(named: "KMImageNameMainToolPageRightRotate")
  895. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageRightRotate")
  896. item?.target = self
  897. item?.btnTag = KMPageEditType.rightRotate.rawValue
  898. item?.toolTip = NSLocalizedString("Rotate Right", comment: "")
  899. item?.titleName = NSLocalizedString("", comment: "")
  900. item?.boxImagePosition = KMToolBoxImagePosition.left
  901. item?.btnAction = #selector(rightRotateMenuAction)
  902. let menuItem = NSMenuItem.init(title: "", action: #selector(rightRotateMenuAction), target: self)
  903. item?.menuFormRepresentation = menuItem
  904. } else if (identifier == KMToolbarPageEditInsetItemIdentifier) {
  905. item?.image = NSImage(named: "KMImageNameMainToolPageInsert")
  906. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageInsert")
  907. item?.target = self
  908. item?.btnTag = KMPageEditType.insert.rawValue
  909. item?.toolTip = NSLocalizedString("Insert", comment: "")
  910. item?.titleName = NSLocalizedString("Insert", comment: "")
  911. item?.boxImagePosition = KMToolBoxImagePosition.left
  912. item?.btnAction = #selector(insertMenuAction)
  913. let menuItem = NSMenuItem.init(title: "Insert", action: #selector(insertMenuAction), target: self)
  914. item?.menuFormRepresentation = menuItem
  915. } else if (identifier == KMToolbarPageEditExtractItemIdentifier) {
  916. item?.image = NSImage(named: "KMImageNameMainToolPageExtract")
  917. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageExtract")
  918. item?.target = self
  919. item?.btnTag = KMPageEditType.extract.rawValue
  920. item?.toolTip = NSLocalizedString("Extract", comment: "")
  921. item?.titleName = NSLocalizedString("Extract", comment: "")
  922. item?.boxImagePosition = KMToolBoxImagePosition.left
  923. item?.btnAction = #selector(extractMenuAction)
  924. let menuItem = NSMenuItem.init(title: "Extract", action: #selector(extractMenuAction), target: self)
  925. item?.menuFormRepresentation = menuItem
  926. } else if (identifier == KMToolbarPageEditReplaceItemIdentifier) {
  927. item?.image = NSImage(named: "KMImageNameMainToolPageReplace")
  928. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageReplace")
  929. item?.target = self
  930. item?.btnTag = KMPageEditType.replace.rawValue
  931. item?.toolTip = NSLocalizedString("Replace", comment: "")
  932. item?.titleName = NSLocalizedString("Replace", comment: "")
  933. item?.boxImagePosition = KMToolBoxImagePosition.left
  934. item?.btnAction = #selector(replaceMenuAction)
  935. let menuItem = NSMenuItem.init(title: "Replace", action: #selector(replaceMenuAction), target: self)
  936. item?.menuFormRepresentation = menuItem
  937. } else if (identifier == KMToolbarPageEditSplitItemIdentifier) {
  938. item?.image = NSImage(named: "KMImageNameMainToolPageSplit")
  939. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageSplit")
  940. item?.target = self
  941. item?.btnTag = KMPageEditType.split.rawValue
  942. item?.toolTip = NSLocalizedString("Split the PDF into multiple files", comment: "")
  943. item?.titleName = NSLocalizedString("Split", comment: "")
  944. item?.boxImagePosition = KMToolBoxImagePosition.left
  945. item?.btnAction = #selector(splitMenuAction)
  946. let menuItem = NSMenuItem.init(title: "Split", action: #selector(splitMenuAction), target: self)
  947. item?.menuFormRepresentation = menuItem
  948. } else if (identifier == KMToolbarPageEditReverseItemIdentifier) {
  949. item?.image = NSImage(named: "KMImageNameMainToolPageReverse")
  950. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageReverse")
  951. item?.target = self
  952. item?.btnTag = KMPageEditType.reverse.rawValue
  953. item?.toolTip = NSLocalizedString("Reverse", comment: "")
  954. item?.titleName = NSLocalizedString("Reverse", comment: "")
  955. item?.boxImagePosition = KMToolBoxImagePosition.left
  956. item?.btnAction = #selector(reverseMenuAction)
  957. let menuItem = NSMenuItem.init(title: "Reverse", action: #selector(reverseMenuAction), target: self)
  958. item?.menuFormRepresentation = menuItem
  959. } else if (identifier == KMToolbarPageEditDeleteItemIdentifier) {
  960. item?.image = NSImage(named: "KMImageNameMainToolPageDelete")
  961. item?.alternateImage = NSImage(named: "KMImageNameMainToolPageDelete")
  962. item?.target = self
  963. item?.btnTag = KMPageEditType.delete.rawValue
  964. item?.toolTip = NSLocalizedString("Delete", comment: "")
  965. item?.titleName = NSLocalizedString("", comment: "")
  966. item?.boxImagePosition = KMToolBoxImagePosition.left
  967. item?.btnAction = #selector(deleteMenuAction)
  968. let menuItem = NSMenuItem.init(title: "Delete", action: #selector(deleteMenuAction), target: self)
  969. item?.menuFormRepresentation = menuItem
  970. }
  971. return item
  972. }
  973. //MARK: menu Action
  974. @objc func insertPageItemAction(menu:NSMenuItem) {
  975. if (menu.tag == 0) {
  976. self.item_insertFile(sender: nil)
  977. } else if (menu.tag == 1) {
  978. self.item_insertBlankPage(sender: nil)
  979. } else if (menu.tag == 2) {
  980. self.item_insertCustomPage(sender: nil)
  981. }
  982. }
  983. @objc func rotatePageItemAction(menu:NSMenuItem) {
  984. rightRotateMenuAction(sender: nil)
  985. }
  986. @objc func leftRotatePageItemAction(menu:NSMenuItem) {
  987. leftRotateMenuAction(sender: nil)
  988. }
  989. @objc func extractPageItemAction(menu:NSMenuItem) {
  990. extractMenuAction(sender: nil)
  991. }
  992. @objc func replacePageItemAction(menu:NSMenuItem) {
  993. replaceMenuAction(sender: nil)
  994. }
  995. @objc func deletePageItemAction(menu:NSMenuItem) {
  996. Task { @MainActor in
  997. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  998. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  999. return
  1000. }
  1001. let indexs = menu.representedObject as! IndexSet
  1002. if indexs.count > 0 {
  1003. self.clearSelectPages()
  1004. self.deletePages(indexs: indexs)
  1005. }
  1006. }
  1007. }
  1008. @objc func sharePageItemAction(menu:NSMenuItem) {
  1009. let item = menu.parent!
  1010. let index = (item.representedObject as! IndexSet).first ?? -1
  1011. if Int(index) >= 0 {
  1012. let doucument = self.thumbnailView.document
  1013. let page = doucument.page(at: UInt(index))
  1014. let filename : String = doucument.documentURL.lastPathComponent
  1015. let folderPath = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(filename))!
  1016. try? FileManager.default.removeItem(atPath: folderPath)
  1017. let pdfdocument = CPDFDocument()
  1018. let ret = pdfdocument!.importPages((item.representedObject as! IndexSet), from: self.thumbnailView.document, at: 0)
  1019. let url = URL(fileURLWithPath: folderPath)
  1020. if ret {
  1021. let success = pdfdocument!.write(to:url)
  1022. if success {
  1023. let workspace = NSWorkspace.shared
  1024. workspace.activateFileViewerSelecting([url])
  1025. }
  1026. }
  1027. let represent : NSSharingService = menu.representedObject as! NSSharingService
  1028. represent.perform(withItems: [url])
  1029. }
  1030. }
  1031. @objc func copyItemAction(menu:NSMenuItem) {
  1032. let indexs = menu.representedObject as! IndexSet
  1033. self.copyPages(with: indexs)
  1034. }
  1035. @objc func cutItemAction(menu:NSMenuItem) {
  1036. let indexs = menu.representedObject as! IndexSet
  1037. self.cutPages(with: indexs)
  1038. }
  1039. @objc func pastePageItemAction(menu:NSMenuItem) {
  1040. var index = (menu.representedObject as! IndexSet).last ?? -1
  1041. self.pastePages(at: index)
  1042. }
  1043. @objc func showPageSizeItemAction(menu: NSMenuItem) {
  1044. self.thumbnailView.isShowPageSize = !self.thumbnailView.isShowPageSize
  1045. self.refreshUIForKeepSelecteds()
  1046. }
  1047. @objc func printItemAction(menu:NSMenuItem) {
  1048. var datas: [Int] = []
  1049. for indexpath in self.thumbnailView.selectionIndexPaths {
  1050. datas.append(indexpath.item)
  1051. }
  1052. guard let callback = self.itemClick else {
  1053. return
  1054. }
  1055. callback(2, datas.sorted())
  1056. }
  1057. }
  1058. // MARK: -
  1059. // MARK: NSMenuDelegate,NSMenuItemValidation
  1060. extension KMPDFEditViewController : NSMenuDelegate,NSMenuItemValidation {
  1061. func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
  1062. let action = menuItem.action
  1063. if action == #selector(insertPageItemAction) ||
  1064. action == #selector(insertPageItemAction) ||
  1065. action == #selector(deletePageItemAction) ||
  1066. action == #selector(replacePageItemAction) ||
  1067. action == #selector(rotatePageItemAction) ||
  1068. action == #selector(leftRotatePageItemAction) ||
  1069. action == #selector(copyItemAction) ||
  1070. action == #selector(cutItemAction) ||
  1071. action == #selector(pastePageItemAction) ||
  1072. action == #selector(printItemAction) ||
  1073. action == #selector(sharePageItemAction) ||
  1074. action == #selector(extractPageItemAction) ||
  1075. action == #selector(showPageSizeItemAction) {
  1076. let row = self.thumbnailView.collectionView.selectionIndexes
  1077. if row.count > 0 {
  1078. if (row.count > 1 && action == #selector(replacePageItemAction)) {
  1079. return false
  1080. }
  1081. return true
  1082. }
  1083. return false
  1084. }
  1085. if (action == #selector(cut)) {
  1086. return self.thumbnailView.collectionView.selectionIndexes.count > 0
  1087. }
  1088. if (action == NSSelectorFromString("copy:")) {
  1089. return self.thumbnailView.collectionView.selectionIndexes.count > 0
  1090. }
  1091. if (action == #selector(paste)) {
  1092. return self.copysPages.count > 0
  1093. }
  1094. if (action == #selector(undo)) {
  1095. return self.undoRedoManager.canUndo
  1096. }
  1097. if (action == #selector(redo)) {
  1098. return self.undoRedoManager.canRedo
  1099. }
  1100. if (action == #selector(delete)) {
  1101. return self.thumbnailView.collectionView.selectionIndexes.count > 0
  1102. }
  1103. return true
  1104. }
  1105. func menuNeedsUpdate(_ menu: NSMenu) {
  1106. menu.removeAllItems()
  1107. let row = self.thumbnailView.collectionView.selectionIndexes
  1108. // let point = self.thumbnailView.collectionView.convert(NSEvent.mouseLocation, to: nil)
  1109. // let indexpaths = self.thumbnailView.collectionView.indexPathForItem(at: point)
  1110. if (row.isEmpty) {
  1111. return
  1112. }
  1113. var item = NSMenuItem()
  1114. // if (row.count == 1) {
  1115. // item = menu.addItem(withTitle: NSLocalizedString("Insert", comment: ""), action: nil, target: self)
  1116. // item.representedObject = row
  1117. //
  1118. // var subMenu = NSMenu()
  1119. // var subitem = NSMenuItem()
  1120. // subitem = subMenu.addItem(withTitle: NSLocalizedString("Insert File", comment: ""), action: #selector(insertPageItemAction), target: self, tag:0)
  1121. // subitem.representedObject = row
  1122. // subitem = subMenu.addItem(withTitle: NSLocalizedString("Insert blank page", comment: ""), action: #selector(insertPageItemAction), target: self, tag:1)
  1123. // subitem.representedObject = row
  1124. // subitem = subMenu.addItem(withTitle: NSLocalizedString("Insert page", comment: ""), action: #selector(insertPageItemAction), target: self, tag:2)
  1125. // subitem.representedObject = row
  1126. // item.submenu = subMenu
  1127. // }
  1128. // item = menu.addItem(withTitle: NSLocalizedString("Extract", comment: ""), action: #selector(extractPageItemAction), target: self)
  1129. // item.representedObject = row
  1130. // if (row.count == 1) {
  1131. // item = menu.addItem(withTitle: NSLocalizedString("Replace Page", comment: ""), action: #selector(replacePageItemAction), target: self)
  1132. // item.representedObject = row
  1133. // }
  1134. item = menu.addItem(withTitle: NSLocalizedString("Delete Page", comment: ""), action: #selector(deletePageItemAction), target: self)
  1135. item.keyEquivalent = String(Unicode.Scalar(NSBackspaceCharacter)!)
  1136. item.keyEquivalentModifierMask = []
  1137. item.representedObject = row
  1138. menu.addItem(NSMenuItem.separator())
  1139. item = menu.addItem(withTitle: NSLocalizedString("Rotate Clockwise", comment: ""), action: #selector(rotatePageItemAction), target: self)
  1140. item.representedObject = row
  1141. item = menu.addItem(withTitle: NSLocalizedString("Rotate Counterclockwise", comment: ""), action: #selector(leftRotatePageItemAction), target: self)
  1142. item.representedObject = row
  1143. menu.addItem(NSMenuItem.separator())
  1144. item = menu.addItem(withTitle: NSLocalizedString("Copy", comment: ""), action: #selector(copyItemAction), target: self)
  1145. item.representedObject = row
  1146. item.keyEquivalent = "c"
  1147. item.keyEquivalentModifierMask = [.command]
  1148. item = menu.addItem(withTitle: NSLocalizedString("Cut", comment: ""), action: #selector(cutItemAction), target: self)
  1149. item.representedObject = row
  1150. item.keyEquivalent = "x"
  1151. item = menu.addItem(withTitle: NSLocalizedString("Paste", comment: ""), action: #selector(pastePageItemAction), target: self)
  1152. item.representedObject = row
  1153. item.keyEquivalent = "v"
  1154. menu.addItem(NSMenuItem.separator())
  1155. if (!self.thumbnailView.isShowPageSize) {
  1156. item = menu.addItem(withTitle: NSLocalizedString("Hide Page Size", comment: ""), action: #selector(showPageSizeItemAction), target: self)
  1157. item.representedObject = row
  1158. } else {
  1159. item = menu.addItem(withTitle: NSLocalizedString("Display Page Size", comment: ""), action: #selector(showPageSizeItemAction), target: self)
  1160. item.representedObject = row
  1161. }
  1162. menu.addItem(NSMenuItem.separator())
  1163. item = menu.addItem(withTitle: NSLocalizedString("Print", comment: ""), action: #selector(printItemAction), target: self)
  1164. item.representedObject = row
  1165. // if (row.count <= 1) {
  1166. // item = menu.addItem(withTitle: NSLocalizedString("Share", comment: ""), action: nil, target: self)
  1167. // item.representedObject = row
  1168. // item.submenu = NSSharingServicePicker.menu(forSharingItems: [self.listView!.document.documentURL ?? ""], subjectContext: "", withTarget: self, selector: #selector(sharePageItemAction), serviceDelegate: nil)
  1169. // }
  1170. }
  1171. }
  1172. // MARK: -
  1173. // MARK: KMSelectPopButtonDelegate
  1174. extension KMPDFEditViewController: KMSelectPopButtonDelegate {
  1175. func km_comboBoxSelectionDidChange(_ obj: KMDesignSelect) {
  1176. let index: Int = self.pageRangeView!.indexOfSelectedItem
  1177. var indexpaths: Set<IndexPath> = []
  1178. if (index <= 0) { /// 全部页面
  1179. self.pageRangeView?.editable = false
  1180. for i in 0 ..< (self.listView?.document.pageCount)! {
  1181. indexpaths.insert(IndexPath(item: Int(i), section: 0))
  1182. }
  1183. self.pageIsUpdate = false
  1184. self.thumbnailView.selectPages(at: indexpaths)
  1185. } else if (index == 1) { /// 奇数页
  1186. self.pageRangeView?.editable = false
  1187. for i in 0 ..< (self.listView?.document.pageCount)! {
  1188. if (i % 2 == 1) {
  1189. continue
  1190. }
  1191. indexpaths.insert(IndexPath(item: Int(i), section: 0))
  1192. }
  1193. self.pageIsUpdate = false
  1194. self.thumbnailView.selectPages(at: indexpaths)
  1195. } else if (index == 2) { /// 偶数页
  1196. self.pageRangeView?.editable = false
  1197. for i in 0 ..< (self.listView?.document.pageCount)! {
  1198. if (i % 2 == 0) {
  1199. continue
  1200. }
  1201. indexpaths.insert(IndexPath(item: Int(i), section: 0))
  1202. }
  1203. self.pageIsUpdate = false
  1204. self.thumbnailView.selectPages(at: indexpaths)
  1205. } else if (index == 3) { /// 横向页
  1206. self.pageRangeView?.editable = false
  1207. for i in 0 ..< (self.listView?.document.pageCount)! {
  1208. let page = self.listView?.document.page(at: i)
  1209. if (page?.rotation == 0 || page?.rotation == 180 || page?.rotation == -180) {
  1210. continue
  1211. }
  1212. indexpaths.insert(IndexPath(item: Int(i), section: 0))
  1213. }
  1214. self.pageIsUpdate = false
  1215. self.thumbnailView.selectPages(at: indexpaths)
  1216. } else if (index == 4) { /// 纵向页
  1217. self.pageRangeView?.editable = false
  1218. for i in 0 ..< (self.listView?.document.pageCount)! {
  1219. let page = self.listView?.document.page(at: i)
  1220. if (page?.rotation == 90 || page?.rotation == 270 || page?.rotation == -90 || page?.rotation == -270) {
  1221. continue
  1222. }
  1223. indexpaths.insert(IndexPath(item: Int(i), section: 0))
  1224. }
  1225. self.pageIsUpdate = false
  1226. self.thumbnailView.selectPages(at: indexpaths)
  1227. } else { /// 自定义
  1228. self.pageIsUpdate = false
  1229. self.pageRangeView?.editable = true
  1230. self.clearSelectPages()
  1231. DispatchQueue.main.async {
  1232. self.pageRangeView?.stringValue = ""
  1233. }
  1234. }
  1235. }
  1236. func km_controlTextDidChange(_ obj: KMDesignSelect) {
  1237. }
  1238. func km_controlTextDidEndEditing(_ obj: KMDesignSelect) {
  1239. self.view.window?.makeFirstResponder(self)
  1240. for index in 0 ..< self.pageRangeView!.numberOfItems {
  1241. if (self.pageRangeViewItems[index] == self.pageRangeView!.stringValue) {
  1242. return
  1243. }
  1244. }
  1245. let pages = KMPageRangeTools.findSelectPage(pageRangeString: self.pageRangeView!.stringValue, pageCount: Int((self.listView?.document.pageCount)!))
  1246. if (pages.isEmpty) {
  1247. let alert = NSAlert()
  1248. alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
  1249. alert.runModal()
  1250. return
  1251. }
  1252. var indexpaths: Set<IndexPath> = []
  1253. for page in pages {
  1254. if (page >= 1) {
  1255. indexpaths.insert(IndexPath(item: page-1, section: 0))
  1256. }
  1257. }
  1258. self.pageIsUpdate = false
  1259. self.thumbnailView.selectPages(at: indexpaths)
  1260. }
  1261. }
  1262. // MARK: -
  1263. // MARK: KMPDFThumbnailViewDelegate
  1264. extension KMPDFEditViewController: KMPDFThumbnailViewDelegate {
  1265. func thumbnailView(thumbanView: KMPDFThumbnailView, didDragAddFiles files: [URL], indexpath: IndexPath) {
  1266. /// 处理page
  1267. // var insertIndex: Int = indexpath.item
  1268. // self.lockedFiles.removeAll()
  1269. // var pages: Array<CPDFPage> = []
  1270. // self.documentCaches.removeAll()
  1271. // var indexs = IndexSet()
  1272. // for fileURL in files {
  1273. // let document = CPDFDocument(url: fileURL)
  1274. // if ((document?.isLocked)!) {
  1275. // self.lockedFiles.append(fileURL)
  1276. // continue
  1277. // }
  1278. //
  1279. // self.documentCaches.append(document!)
  1280. // for i in 0 ..< document!.pageCount {
  1281. // let page = document?.page(at: i)
  1282. // pages.append(page!)
  1283. // indexs.insert(insertIndex)
  1284. // insertIndex += 1
  1285. // }
  1286. // }
  1287. // self.insertPagesForDescSort(pages: pages, indexs: indexs)
  1288. //
  1289. // if (self.lockedFiles.count <= 0) {
  1290. // self.refreshUI()
  1291. // return
  1292. // }
  1293. //
  1294. // self.refreshUI()
  1295. // self.showPasswordWindow(insertIndex)
  1296. }
  1297. func thumbnailView(thumbanView: KMPDFThumbnailView, didDragPages pages: [Int], indexpath: IndexPath) {
  1298. let toIndex = max(0, indexpath.item)
  1299. var indexs = IndexSet()
  1300. for page in pages {
  1301. indexs.insert(page)
  1302. }
  1303. self.dragPages(indexs, toIndex)
  1304. if (pages.count > 0) {
  1305. // 提醒外面文档已编辑
  1306. if (self.documentEditedCallback != nil) {
  1307. self.documentEditedCallback!()
  1308. }
  1309. }
  1310. }
  1311. // MARK: thumbanView layout
  1312. func thumbnailView(thumbanView: KMPDFThumbnailView, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  1313. return 0.01
  1314. }
  1315. func thumbnailView(thumbanView: KMPDFThumbnailView, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  1316. return 0.01
  1317. }
  1318. func thumbnailView(thumbanView: KMPDFThumbnailView, insetForSectionAt section: Int) -> NSEdgeInsets {
  1319. return NSEdgeInsets(top: 16, left: 16, bottom: 0, right: 32)
  1320. }
  1321. func thumbnailView(thumbanView: KMPDFThumbnailView, sizeForItemAt indexpath: IndexPath) -> NSSize {
  1322. self.thumbnailView.thumbnailSzie = CGSize(width: 120, height: 155)
  1323. if (!self.thumbnailView.isShowPageSize) {
  1324. return NSMakeSize(self.itemSize.width, self.itemSize.height+26)
  1325. }
  1326. return self.itemSize
  1327. }
  1328. func thumbnailView(thumbanView: KMPDFThumbnailView, itemForRepresentedObjectAt indexpath: IndexPath) -> NSCollectionViewItem {
  1329. let cellView: KMPageEditThumbnailItem = thumbanView.collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMPageEditThumbnailItem"), for: indexpath) as! KMPageEditThumbnailItem
  1330. cellView.isShowPageSize = self.thumbnailView.isShowPageSize
  1331. cellView.page = self.thumbnailView.document.page(at: UInt(indexpath.item))
  1332. cellView.setPage(page: self.thumbnailView.document.page(at: UInt(indexpath.item)))
  1333. cellView.doubleClickAction = { [unowned self] _ in
  1334. guard let callback = self.itemClick else {
  1335. return
  1336. }
  1337. callback(1, indexpath.item)
  1338. }
  1339. cellView.mouseDownAction = { [unowned self] _ in
  1340. let selectionIndexPaths = self.thumbnailView.selectionIndexPaths
  1341. if (selectionIndexPaths.count == 1 && selectionIndexPaths.first?.item == indexpath.item) {
  1342. return
  1343. }
  1344. self.selectPages(indexs: IndexSet.init(integer: indexpath.item))
  1345. }
  1346. cellView.rightMouseDownAction = { [unowned self] _ in
  1347. self.selectPages(indexs: IndexSet.init(integer: indexpath.item))
  1348. }
  1349. return cellView
  1350. }
  1351. }
  1352. // MARK: -
  1353. // MARK: 系统菜单栏
  1354. extension KMPDFEditViewController: KMEditMenuProtocol {
  1355. @IBAction func cut(_ sender: Any) {
  1356. self.cutPages(with: self.thumbnailView.collectionView.selectionIndexes)
  1357. }
  1358. @IBAction func copy(_ sender: Any) {
  1359. self.copyPages(with: self.thumbnailView.collectionView.selectionIndexes)
  1360. }
  1361. @IBAction func paste(_ sender: Any) {
  1362. var index: Int = Int(self.thumbnailView.document.pageCount-1)
  1363. let indexSet = self.thumbnailView.collectionView.selectionIndexes
  1364. if (indexSet.isEmpty == false) {
  1365. index = indexSet.last!
  1366. }
  1367. self.pastePages(at: index)
  1368. }
  1369. @IBAction func delete(_ sender: Any) {
  1370. Task { @MainActor in
  1371. if await (KMLightMemberManager.manager.canUseAdvanced() == false) {
  1372. let _ = KMComparativeTableViewController.show(window: self.view.window!)
  1373. return
  1374. }
  1375. let selectedIndexs = self.thumbnailView.collectionView.selectionIndexPaths
  1376. var indexs: IndexSet = IndexSet()
  1377. for indexPath in selectedIndexs {
  1378. indexs.insert(indexPath.item)
  1379. }
  1380. self.clearSelectPages()
  1381. self.deletePages(indexs: indexs)
  1382. }
  1383. }
  1384. @IBAction func undo(_ sender: Any) {
  1385. if (self.undoRedoManager.canUndo) {
  1386. self.undoRedoManager.undo()
  1387. }
  1388. }
  1389. @IBAction func redo(_ sender: Any) {
  1390. if (self.undoRedoManager.canRedo) {
  1391. self.undoRedoManager.redo()
  1392. }
  1393. }
  1394. }