KMMergeViewController.swift 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347
  1. //
  2. // KMMergeViewController.swift
  3. // PDF Master
  4. //
  5. // Created by tangchao on 2022/11/23.
  6. //
  7. import Cocoa
  8. import PDFKit
  9. import CoreGraphics
  10. class KMMergePage: CPDFPage {
  11. var drawingPage: CPDFPage!
  12. // override func draw(with box: PDFDisplayBox) {
  13. // super.draw(with: box)
  14. //
  15. // let context: CGContext = NSGraphicsContext.current?.graphicsPort as! CGContext
  16. // let pageSize = bounds(for: .cropBox).size
  17. //
  18. // drawPageWithContext(context: context, page: self.drawingPage, pageSize: pageSize)
  19. // }
  20. override func draw(with box: CPDFDisplayBox, to context: CGContext!) {
  21. super.draw(with: box, to: context)
  22. let pageSize = bounds(for: .cropBox).size
  23. drawPageWithContext(context: context, page: self.drawingPage, pageSize: pageSize)
  24. }
  25. func drawPageWithContext(context: CGContext, page: CPDFPage, pageSize: NSSize) {
  26. var originalSize = page.bounds(for: .cropBox).size
  27. /// 如果page的旋转角度为90,或者270,宽高交换
  28. if ((page.rotation % 180) != 0) {
  29. originalSize = NSSize(width: originalSize.height, height: originalSize.width)
  30. }
  31. let wRadio: CGFloat = pageSize.width/originalSize.width
  32. let hRadio: CGFloat = pageSize.height/originalSize.height
  33. let radio = min(wRadio, hRadio)
  34. context.saveGState()
  35. var xTransform: CGFloat = (pageSize.width-originalSize.width * radio) / 2
  36. var yTransform: CGFloat = (pageSize.height-originalSize.height * radio) / 2
  37. context.translateBy(x: xTransform, y: yTransform)
  38. context.scaleBy(x: radio, y: radio)
  39. page.draw(with: .cropBox, to: context)
  40. page.transform(context, for: .cropBox)
  41. // var contextRef: CGContextRef = context
  42. }
  43. }
  44. class KMMergeTestWindow: NSWindow {
  45. private var mergeController: KMMergeViewController!
  46. override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
  47. super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag);
  48. isReleasedWhenClosed = false
  49. let controller: KMMergeViewController = KMMergeViewController()
  50. contentView?.addSubview(controller.view)
  51. controller.view.frame = CGRect(x: 0, y: 0, width: contentRect.size.width, height: contentRect.size.height)
  52. mergeController = controller
  53. }
  54. }
  55. protocol KMMergeViewController_collectionView_delegate : NSObjectProtocol {
  56. func collection_menu(for event: NSEvent) -> NSMenu?
  57. }
  58. class KMMergeViewController_collectionView: NSCollectionView {
  59. weak var myDelegate: KMMergeViewController_collectionView_delegate!
  60. override func menu(for event: NSEvent) -> NSMenu? {
  61. guard let myDelegate = self.myDelegate else {
  62. return super.menu(for: event)
  63. }
  64. return myDelegate.collection_menu(for: event)
  65. // return super.menu(for: event)
  66. }
  67. }
  68. class KMMergeViewController: NSViewController {
  69. @IBOutlet weak var titleBar: NSBox!
  70. @IBOutlet weak var contentBox: NSBox!
  71. private var titleBarView: KMMergeTitleBar?
  72. private var scrollView: NSScrollView?
  73. private var contentionView: KMMergeViewController_collectionView?
  74. private var zoomScale: CGFloat = 0
  75. private var zoomMinScale: CGFloat = 0.5
  76. private var zoomMaxScale: CGFloat = 8
  77. private lazy var dataArray: [KMMergeFileModel] = []
  78. private lazy var deleteArray: [Int] = []
  79. private var dragedIndexPaths: [IndexPath] = []
  80. private let localForDraggedTypes = NSPasteboard.PasteboardType(rawValue: "localForDraggedTypes")
  81. private var pageRangeWindowController: KMPageRangePickerWindowController!
  82. private var mergeSettingWindowController: KMMergeSettingWindowController!
  83. private var outPDFDocument = CPDFDocument()
  84. private var lockedFiles: [URL] = []
  85. override func viewDidLoad() {
  86. super.viewDidLoad()
  87. initDefaultValue()
  88. initSubViews()
  89. }
  90. /**
  91. * MARK: - 初始化值
  92. */
  93. func initDefaultValue() {
  94. titleBar.titlePosition = NSBox.TitlePosition.noTitle
  95. titleBar.contentViewMargins = NSSize.zero
  96. titleBar.boxType = NSBox.BoxType.custom
  97. titleBar.borderWidth = 0
  98. zoomScale = 0
  99. }
  100. func initSubViews() {
  101. let titleBarView_: KMMergeTitleBar = KMMergeTitleBar()
  102. titleBar.contentView?.addSubview(titleBarView_)
  103. titleBarView_.frame = NSMakeRect(0, 0, NSWidth(titleBar.bounds), NSHeight(titleBar.bounds))
  104. titleBarView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
  105. titleBarView_.delegate = self
  106. titleBarView_.wantsLayer = true
  107. titleBarView_.layer?.backgroundColor = NSColor.white.cgColor
  108. titleBarView = titleBarView_
  109. titleBarView?.setDeleteItemEnable(enable: false)
  110. titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
  111. titleBarView_.itemClick = {
  112. [self] (itemIndex: KMMergeTitleBarButtonID) -> () in
  113. switch itemIndex {
  114. case .add:
  115. self.showAddMenu()
  116. break
  117. case .delete:
  118. for index in deleteArray {
  119. if index < dataArray.count {
  120. dataArray.remove(at: index)
  121. }
  122. }
  123. deleteArray.removeAll()
  124. self.titleBarView?.setDeleteItemEnable(enable: false)
  125. self.contentionView?.reloadData()
  126. break
  127. case .zoomOut:
  128. if zoomScale > zoomMaxScale {
  129. titleBarView?.setZoomItemEnable(zoomIn: false, enable: false)
  130. return
  131. }
  132. titleBarView?.setZoomItemEnable(zoomIn: true, enable: true)
  133. zoomScale += 0.5
  134. contentionView?.reloadData()
  135. break
  136. case .zoomIn:
  137. if zoomScale < zoomMinScale {
  138. titleBarView?.setZoomItemEnable(zoomIn: true, enable: false)
  139. return
  140. }
  141. titleBarView?.setZoomItemEnable(zoomIn: false, enable: true)
  142. zoomScale -= 0.5
  143. contentionView?.reloadData()
  144. break
  145. case .merge:
  146. if dataArray.count == 0 {
  147. let alert = NSAlert()
  148. alert.messageText = NSLocalizedString("没有文件", comment: "")
  149. alert.runModal()
  150. return
  151. }
  152. let windowController = KMMergeSettingWindowController.init(windowNibName: "KMMergeSettingWindowController")
  153. self.view.window?.beginSheet(windowController.window!)
  154. mergeSettingWindowController = windowController
  155. windowController.odd_even_mergeComboBox.isEnabled = dataArray.count == 2
  156. windowController.cancelClick = {
  157. [self] (window: NSWindow) -> () in
  158. self.view.window?.endSheet(window)
  159. }
  160. windowController.mergeClick = {
  161. [self] (windowController: NSWindowController) -> () in
  162. if mergeSettingWindowController.odd_even_mergeComboBox.state == .on { /// 奇偶数穿插合并
  163. let document = CPDFDocument()
  164. outPDFDocument = document
  165. mergeActionForOddEven()
  166. let panel = NSSavePanel()
  167. panel.nameFieldStringValue = "[新文件].pdf"
  168. let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
  169. button.state = .on
  170. panel.accessoryView = button
  171. panel.isExtensionHidden = true
  172. let response = panel.runModal()
  173. if response == .OK {
  174. let url = panel.url
  175. let result = outPDFDocument!.write(to: panel.url!)
  176. if result {
  177. if button.state == .on { /// 开启文档
  178. } else {
  179. NSWorkspace.shared.openFile(url!.path)
  180. }
  181. }
  182. }
  183. } else { /// 正常合并
  184. let document = CPDFDocument()
  185. outPDFDocument = document
  186. mergeAction()
  187. let panel = NSSavePanel()
  188. panel.nameFieldStringValue = "[新文件].pdf"
  189. let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
  190. button.state = .on
  191. panel.accessoryView = button
  192. panel.isExtensionHidden = true
  193. let response = panel.runModal()
  194. if response == .OK {
  195. let url = panel.url
  196. let result = document!.write(to: panel.url!)
  197. if result {
  198. if button.state == .on { /// 开启文档
  199. } else {
  200. NSWorkspace.shared.openFile(url!.path)
  201. }
  202. }
  203. }
  204. }
  205. self.view.window?.endSheet(windowController.window!)
  206. }
  207. break
  208. case .cancel:
  209. if dataArray.count == 0 {
  210. self.view.window?.close()
  211. } else {
  212. let alert = NSAlert()
  213. alert.messageText = NSLocalizedString("关闭将不会保存当前操作", comment: "")
  214. alert.addButton(withTitle: NSLocalizedString("关闭", comment: ""))
  215. alert.addButton(withTitle: NSLocalizedString("取消", comment: ""))
  216. let response = alert.runModal()
  217. if response == .alertFirstButtonReturn {
  218. self.view.window?.close()
  219. }
  220. }
  221. break
  222. }
  223. }
  224. titleBarView_.pageRangeClick = {
  225. [self] (index: Int, pageString: String) -> () in
  226. let model = self.titleBarView?.model
  227. if index == 0 {
  228. model?.pageRange = .all
  229. model?.updateChildPageRange(pageRange: .all)
  230. } else if index == 1 {
  231. model?.pageRange = .oddPages
  232. model?.updateChildPageRange(pageRange: .oddPages)
  233. } else if index == 2 {
  234. model?.pageRange = .evenPages
  235. model?.updateChildPageRange(pageRange: .evenPages)
  236. } else if index == 3 {
  237. if !isValidPagesString(pagesString: pageString) {
  238. let alert = NSAlert()
  239. alert.alertStyle = .warning
  240. alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
  241. alert.runModal()
  242. return
  243. }
  244. model?.pageRangeString = pageString
  245. model?.updateChildPageRange(pageRange: .custom)
  246. let pageNumbers = findSelectPage(fileModel: model!)
  247. for i in 0 ... (model?.pages.count)!-1 {
  248. let pageModel = model?.pages[i]
  249. if pageNumbers .contains(Int(pageModel!.pageID)+1) {
  250. pageModel!.selected = true
  251. } else {
  252. pageModel!.selected = false
  253. }
  254. }
  255. }
  256. self.contentionView?.reloadData()
  257. }
  258. let scrollView_ = NSScrollView()
  259. contentBox.contentView?.addSubview(scrollView_)
  260. scrollView_.frame = NSMakeRect(0, 0, NSWidth(contentBox.bounds), NSHeight(contentBox.bounds))
  261. scrollView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
  262. scrollView = scrollView_
  263. let layout = NSCollectionViewFlowLayout()
  264. layout.sectionInset = NSEdgeInsetsMake(20, 20, 20, 20)
  265. layout.minimumLineSpacing = 0
  266. layout.minimumInteritemSpacing = 2
  267. let contentionView_ = KMMergeViewController_collectionView()
  268. contentionView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
  269. contentionView_.collectionViewLayout = layout
  270. contentionView_.dataSource = self
  271. contentionView_.delegate = self
  272. contentionView_.register(KMMergeCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"))
  273. contentionView_.register(KMMergeCollectionPageViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PageCellID"))
  274. contentionView_.registerForDraggedTypes([localForDraggedTypes])
  275. scrollView?.documentView = contentionView_
  276. contentionView = contentionView_
  277. contentionView?.isSelectable = true
  278. contentionView?.allowsMultipleSelection = true
  279. contentionView?.myDelegate = self
  280. contentionView?.reloadData()
  281. }
  282. func mergeActionForOddEven() {
  283. if (dataArray.count <= 1) {
  284. return
  285. }
  286. var rootPDFOutlineArray: [CPDFOutline] = []
  287. var pdfDocument = outPDFDocument
  288. var mergeOutline: Bool = true
  289. for fileModel in dataArray {
  290. if fileModel.pageRange != .all {
  291. mergeOutline = false
  292. }
  293. var pdfOutlineArray: [CPDFOutline] = []
  294. if (fileModel.document.outlineRoot != nil) {
  295. rootPDFOutlineArray.append(fileModel.document.outlineRoot())
  296. fetchAllChildren(outline: fileModel.document.outlineRoot(), containers: &pdfOutlineArray)
  297. pdfOutlineArray.removeObject(fileModel.document.outlineRoot())
  298. } else {
  299. var rootOutline = CPDFOutline()
  300. fileModel.document.setOutlineRoot(rootOutline)
  301. if fileModel.document.outlineRoot() != nil {
  302. rootPDFOutlineArray.append(fileModel.document.outlineRoot())
  303. }
  304. }
  305. for outline in pdfOutlineArray {
  306. /// 这段代码主要是调用他的getter方法;outline显示正确
  307. outline.destination?.page().document.dataRepresentation()
  308. }
  309. }
  310. let oddDocument = dataArray.first?.document
  311. let oddCount: Int = Int(oddDocument!.pageCount)
  312. let evenDocument = dataArray.last?.document!
  313. let evenCount: Int = Int(evenDocument!.pageCount)
  314. let count = min(oddCount-1, evenCount-1)
  315. for i in 0 ... count {
  316. pdfDocument!.insertPageObject((oddDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
  317. pdfDocument!.insertPageObject((evenDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
  318. }
  319. if oddCount > evenCount {
  320. for i in count ... oddCount-1 {
  321. pdfDocument!.insertPageObject((oddDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
  322. }
  323. } else if oddCount < evenCount {
  324. for i in count ... evenCount-1 {
  325. pdfDocument!.insertPageObject((evenDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
  326. }
  327. }
  328. if mergeOutline {
  329. pdfDocument?.setOutlineRoot(CPDFOutline())
  330. var index = 0
  331. for outlineRoot in rootPDFOutlineArray {
  332. if outlineRoot != nil && outlineRoot.numberOfChildren > 0 {
  333. for i in 0 ... outlineRoot.numberOfChildren-1 {
  334. pdfDocument!.outlineRoot().insertChild(outlineRoot.child(at: UInt(i)), at: UInt(index))
  335. index += 1
  336. }
  337. }
  338. }
  339. }
  340. handerReDraw()
  341. }
  342. func mergeAction() {
  343. if (dataArray.count <= 1) {
  344. // return
  345. }
  346. var rootPDFOutlineArray: [CPDFOutline] = []
  347. var pdfDocument = outPDFDocument
  348. var mergeOutline: Bool = true
  349. for fileModel in dataArray {
  350. if fileModel.pageRange != .all {
  351. mergeOutline = false
  352. }
  353. var pdfOutlineArray: [CPDFOutline] = []
  354. if (fileModel.document.outlineRoot() != nil) {
  355. rootPDFOutlineArray.append(fileModel.document.outlineRoot())
  356. fetchAllChildren(outline: fileModel.document.outlineRoot(), containers: &pdfOutlineArray)
  357. pdfOutlineArray.removeObject(fileModel.document.outlineRoot())
  358. } else {
  359. var rootOutline = CPDFOutline()
  360. fileModel.document.setOutlineRoot(rootOutline)
  361. if fileModel.document.outlineRoot() != nil {
  362. rootPDFOutlineArray.append(fileModel.document.outlineRoot())
  363. }
  364. }
  365. for outline in pdfOutlineArray {
  366. /// 这段代码主要是调用他的getter方法;outline显示正确
  367. outline.destination?.page().document.dataRepresentation()
  368. }
  369. if fileModel.pageRange == .all {
  370. for i in 0 ... fileModel.document.pageCount-1 {
  371. pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
  372. }
  373. } else if fileModel.pageRange == .oddPages {
  374. for i in 0 ... fileModel.document.pageCount-1 {
  375. if i % 2 == 1 {
  376. continue
  377. }
  378. pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
  379. }
  380. } else if fileModel.pageRange == .evenPages {
  381. for i in 0 ... fileModel.document.pageCount-1 {
  382. if i % 2 == 0 {
  383. continue
  384. }
  385. pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
  386. }
  387. } else if fileModel.pageRange == .custom {
  388. let pageNumbers = self.findSelectPage(fileModel: fileModel)
  389. for i in pageNumbers {
  390. pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i-1))!, at: pdfDocument!.pageCount)
  391. }
  392. }
  393. }
  394. if mergeOutline {
  395. pdfDocument?.setOutlineRoot( CPDFOutline())
  396. var index = 0
  397. for outlineRoot in rootPDFOutlineArray {
  398. if outlineRoot != nil && outlineRoot.numberOfChildren > 0 {
  399. for i in 0 ... outlineRoot.numberOfChildren-1 {
  400. pdfDocument!.outlineRoot().insertChild(outlineRoot.child(at: UInt(i)), at: UInt(index))
  401. index += 1
  402. }
  403. }
  404. }
  405. }
  406. handerReDraw()
  407. }
  408. func handerReDraw() {
  409. if mergeSettingWindowController.selectedIndex == 0 { /// 原始尺寸
  410. } else {
  411. var pageSize = NSMakeSize(595, 841)
  412. if mergeSettingWindowController.selectedIndex == 1 { /// A4 595 x 841
  413. pageSize = NSMakeSize(595, 841)
  414. } else if mergeSettingWindowController.selectedIndex == 2 { /// A3 841 x 1190
  415. pageSize = NSMakeSize(841, 1190)
  416. } else if mergeSettingWindowController.selectedIndex == 3 { /// U.S.Letter 612 x 792
  417. pageSize = NSMakeSize(612, 792)
  418. } else if mergeSettingWindowController.selectedIndex == 4 { /// U.S.Legal 612 x 1108
  419. pageSize = NSMakeSize(612, 1108)
  420. } else if mergeSettingWindowController.selectedIndex == 5 { /// 自定义 595 x 841
  421. // pageSize = NSMakeSize(595, 841)
  422. pageSize.width = CGFloat(mergeSettingWindowController.customWidthTextField.floatValue)
  423. pageSize.height = CGFloat(mergeSettingWindowController.customHeightTextField.floatValue)
  424. }
  425. var pagesArray: [CPDFPage] = []
  426. let pageCount = outPDFDocument!.pageCount
  427. for _ in 0 ... pageCount-1 {
  428. pagesArray.append(outPDFDocument!.page(at: 0)!)
  429. outPDFDocument!.removePage(at: 0)
  430. }
  431. for i in 0 ... pageCount-1 {
  432. var page = KMMergePage()
  433. page.drawingPage = pagesArray[Int(i)]
  434. page.setBounds(NSMakeRect(0, 0, pageSize.width, pageSize.height), for: .cropBox)
  435. outPDFDocument!.insertPageObject(page, at: i)
  436. }
  437. /// 如果是自定义大小,删除所有的outline,因为合并出来的outline是无效的
  438. if mergeSettingWindowController.pageSizeComboBox.indexOfSelectedItem == 5 { /// 自定义 595 x 841
  439. let childCount: Int = Int(outPDFDocument!.outlineRoot().numberOfChildren)
  440. var array: [CPDFOutline] = []
  441. for i in 0 ... childCount-1 {
  442. array.append((outPDFDocument!.outlineRoot().child(at: UInt(i)))!)
  443. }
  444. for outline in array {
  445. outline.removeFromParent()
  446. }
  447. }
  448. }
  449. }
  450. func fetchAllChildren(outline: CPDFOutline, containers: inout [CPDFOutline]) {
  451. if !containers.contains(outline) {
  452. containers.append(outline)
  453. }
  454. if outline != nil && outline.numberOfChildren > 0 {
  455. for i in 0 ... (outline.numberOfChildren-1) {
  456. containers.append(outline.child(at: i)!)
  457. fetchAllChildren(outline: outline.child(at: i)!, containers: &containers)
  458. }
  459. }
  460. }
  461. func showAddMenu() {
  462. let menu: NSMenu = NSMenu()
  463. let addFileitem = menu.addItem(withTitle: NSLocalizedString("添加文件", comment: ""), action: #selector(itemAddFileAction), keyEquivalent: "")
  464. addFileitem.target = self
  465. let addFolderitem = menu.addItem(withTitle: NSLocalizedString("添加文件夹", comment: ""), action: #selector(itemAddFolderAction), keyEquivalent: "")
  466. addFolderitem.target = self
  467. let addOpenFileitem = menu.addItem(withTitle: NSLocalizedString("添加已打开文件", comment: ""), action: #selector(itemAddOpenFileAction), keyEquivalent: "")
  468. addOpenFileitem.target = self
  469. addOpenFileitem.action = nil
  470. let point: NSPoint = NSMakePoint(0, -10)
  471. menu.popUp(positioning: nil, at: point, in: titleBarView?.addItem)
  472. }
  473. @objc func itemAddFileAction() {
  474. let openPanel = NSOpenPanel()
  475. openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
  476. openPanel.canChooseDirectories = false //是否允许选择目录
  477. openPanel.canChooseFiles = true //是否可以选择文件
  478. openPanel.allowsMultipleSelection = true //是否允许多选
  479. openPanel.allowedFileTypes = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
  480. openPanel.beginSheetModal(for: view.window!, completionHandler: { result in
  481. if result != .OK {
  482. } else {
  483. for documentURL in openPanel.urls {
  484. self.addModel(documentURL: documentURL)
  485. }
  486. self.contentionView?.reloadData()
  487. self.dealLockedFiles()
  488. }
  489. })
  490. }
  491. @objc func itemAddFolderAction() {
  492. let openPanel = NSOpenPanel()
  493. openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
  494. openPanel.canChooseDirectories = true
  495. openPanel.canChooseFiles = false
  496. openPanel.allowsMultipleSelection = true
  497. openPanel.beginSheetModal(for: view.window!, completionHandler: { [self] result in
  498. if result != .OK {
  499. } else {
  500. var result: [URL] = []
  501. for folderURL in openPanel.urls {
  502. findAllFiles(folder: folderURL, result: &result)
  503. }
  504. for documentURL in result {
  505. addModel(documentURL: documentURL)
  506. }
  507. self.contentionView?.reloadData()
  508. self.dealLockedFiles()
  509. }
  510. })
  511. }
  512. func findAllFiles(folder: URL, result: inout [URL]) {
  513. let fileManager = FileManager.default
  514. var isDirectory: ObjCBool = ObjCBool(false)
  515. fileManager.fileExists(atPath: folder.path, isDirectory: &isDirectory)
  516. if (!isDirectory.boolValue) {
  517. return
  518. }
  519. let contents = try?fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil)
  520. if contents?.count == 0 {
  521. return
  522. }
  523. let array = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
  524. for documentURL in contents! {
  525. var isDirectory: ObjCBool = ObjCBool(false)
  526. fileManager.fileExists(atPath: documentURL.path, isDirectory: &isDirectory)
  527. if (isDirectory.boolValue) {
  528. findAllFiles(folder: documentURL, result: &result)
  529. } else {
  530. if !array.contains(documentURL.pathExtension.lowercased()) {
  531. continue
  532. }
  533. result.append(documentURL)
  534. }
  535. }
  536. }
  537. @objc func itemAddOpenFileAction() {
  538. }
  539. func addModel(documentURL: URL) {
  540. let model: KMMergeFileModel = KMMergeFileModel();
  541. model.documentURL = documentURL
  542. if documentURL.pathExtension.lowercased() == "pdf" {
  543. model.document = CPDFDocument.init(url: documentURL)
  544. if model.document.isLocked {
  545. lockedFiles.append(documentURL)
  546. return
  547. }
  548. model.myDocument = CPDFDocument.init(url: documentURL)
  549. model.pageRange = .all
  550. model.page = model.document.page(at: 0)
  551. if model.document.pageCount > 1 {
  552. for i in 0 ... model.document.pageCount-1 {
  553. let pageModel = KMMergePageModel()
  554. pageModel.selected = true
  555. pageModel.pageID = Int(i)
  556. model.pages.append(pageModel)
  557. }
  558. } else {
  559. }
  560. } else {
  561. let doucument = CPDFDocument.init(url: documentURL)
  562. model.document = doucument
  563. model.page = doucument?.page(at: 0)
  564. model.document.insertPageObject(model.page, at: 0)
  565. }
  566. self.dataArray.append(model)
  567. }
  568. func replaceModel(documentURL: URL, index: Int) {
  569. if index >= 0 && index < dataArray.count {
  570. let model: KMMergeFileModel = KMMergeFileModel();
  571. model.documentURL = documentURL
  572. if documentURL.pathExtension.lowercased() == "pdf" {
  573. model.document = CPDFDocument.init(url: documentURL)
  574. model.myDocument = CPDFDocument.init(url: documentURL)
  575. model.pageRange = .all
  576. model.page = model.document.page(at: 0)
  577. if model.document.pageCount > 1 {
  578. for i in 0 ... model.document.pageCount {
  579. let pageModel = KMMergePageModel()
  580. pageModel.selected = true
  581. pageModel.pageID = Int(i)
  582. model.pages.append(pageModel)
  583. }
  584. } else {
  585. }
  586. } else {
  587. let doucument = CPDFDocument.init(url: documentURL)
  588. model.document = doucument
  589. model.page = doucument?.page(at: 0)
  590. model.document.insertPageObject(model.page, at: 0)
  591. }
  592. self.dataArray[index] = model
  593. }
  594. }
  595. func isValidPagesString(pagesString: String)-> Bool {
  596. var valid = false
  597. for ch in pagesString {
  598. if ch != "0" && ch != "1" && ch != "2" && ch != "3" && ch != "4" && ch != "5" && ch != "6" && ch != "7" && ch != "8" && ch != "9" && ch != "," && ch != "-" {
  599. valid = false
  600. break
  601. } else {
  602. valid = true
  603. }
  604. }
  605. return valid
  606. }
  607. func findSelectPage(fileModel: KMMergeFileModel) -> ([Int]) {
  608. if !isValidPagesString(pagesString: fileModel.pageRangeString) {
  609. return []
  610. }
  611. var result: [Int] = []
  612. let array = fileModel.pageRangeString.components(separatedBy: ",")
  613. for string in array {
  614. if string.isEmpty {
  615. return []
  616. } else {
  617. let pages = string .components(separatedBy: "-")
  618. if pages.count > 2 {
  619. return []
  620. } else if pages.count == 1 {
  621. let page = pages[0]
  622. if page.isEmpty || Int(page)! > fileModel.document.pageCount || Int(page)! == 0 {
  623. return []
  624. } else {
  625. var hasSame: Bool = false
  626. for i in result {
  627. if i == Int(page)! {
  628. hasSame = true
  629. return []
  630. }
  631. }
  632. if !hasSame {
  633. result.append(Int(page)!)
  634. }
  635. }
  636. } else if pages.count == 2 {
  637. let page1 = pages[0]
  638. let page2 = pages[1]
  639. if page1.isEmpty || page2.isEmpty || Int(page1)! >= Int(page2)! || Int(page2)! > fileModel.myDocument.pageCount || Int(page1)! == 0 {
  640. return []
  641. } else {
  642. var hasSame: Bool = false
  643. for i in Int(page1)! ... Int(page2)! {
  644. for j in result {
  645. if j == i {
  646. hasSame = true
  647. return []
  648. }
  649. }
  650. }
  651. if !hasSame {
  652. for i in Int(page1)! ... Int(page2)! {
  653. result.append(i)
  654. }
  655. }
  656. }
  657. }
  658. }
  659. }
  660. return result
  661. }
  662. func findFileModel(indexPath: IndexPath) -> (fileModel: KMMergeFileModel, pageIndex: Int) {
  663. var count: Int = 0
  664. var flagModel : KMMergeFileModel!
  665. var index: Int = NSNotFound
  666. for model in dataArray {
  667. if (flagModel != nil) {
  668. break
  669. }
  670. if model.open {
  671. for i in 0...(model.document.pageCount-1) {
  672. if count == indexPath.item {
  673. index = Int(i)
  674. flagModel = model
  675. break
  676. }
  677. count += 1
  678. }
  679. } else {
  680. if count == indexPath.item {
  681. flagModel = model
  682. break
  683. }
  684. count += 1
  685. }
  686. }
  687. return (flagModel, index)
  688. }
  689. func allItemIsExpanded() -> Bool {
  690. for fileModel in dataArray {
  691. if fileModel.canExpand() && !fileModel.open {
  692. return false
  693. }
  694. }
  695. return true
  696. }
  697. func allItemIsFolded() -> Bool {
  698. for fileModel in dataArray {
  699. if fileModel.open {
  700. return false
  701. }
  702. }
  703. return true
  704. }
  705. func dealLockedFiles() {
  706. if lockedFiles.count > 0 {
  707. let documentURL = lockedFiles.first
  708. let alert = NSAlert()
  709. alert.messageText = documentURL!.lastPathComponent.appending(", 已被保护")
  710. alert.addButton(withTitle: "输入密码")
  711. alert.addButton(withTitle: "关闭")
  712. let response = alert.runModal()
  713. if response == .alertFirstButtonReturn {
  714. let window = KMPasswordInputWindow().window()
  715. window?.documentURL = documentURL!
  716. window?.type = .open
  717. window?.itemClick = {
  718. (index: Int, string: String) in
  719. if index == 1 {
  720. self.view.window?.endSheet(window!)
  721. self.lockedFiles.remove(at: 0)
  722. self.dealLockedFiles()
  723. } else {
  724. self.view.window?.endSheet(window!)
  725. let model = KMMergeFileModel()
  726. model.documentURL = documentURL
  727. model.document = CPDFDocument(url: documentURL!)
  728. model.document.unlock(withPassword: string)
  729. model.myDocument = CPDFDocument.init(url: documentURL)
  730. model.pageRange = .all
  731. model.page = model.document.page(at: 0)
  732. model.password = string
  733. if model.document.pageCount > 1 {
  734. for i in 0 ... model.document.pageCount-1 {
  735. let pageModel = KMMergePageModel()
  736. pageModel.selected = true
  737. pageModel.pageID = Int(i)
  738. model.pages.append(pageModel)
  739. }
  740. }
  741. self.dataArray.append(model)
  742. self.contentionView?.reloadData()
  743. self.lockedFiles.remove(at: 0)
  744. self.dealLockedFiles()
  745. }
  746. }
  747. self.view.window?.beginSheet(window!)
  748. } else {
  749. self.lockedFiles.remove(at: 0)
  750. self.dealLockedFiles()
  751. }
  752. }
  753. }
  754. /**
  755. * MARK: Menu Actions
  756. */
  757. @objc func expandAllMenuAction() {
  758. for fileModel in dataArray {
  759. if fileModel.canExpand() {
  760. fileModel.open = true
  761. }
  762. }
  763. self.contentionView?.reloadData()
  764. deleteArray.removeAll()
  765. titleBarView?.setDeleteItemEnable(enable: false)
  766. }
  767. @objc func foldAllMenuAction() {
  768. for fileModel in dataArray {
  769. fileModel.open = false
  770. }
  771. self.contentionView?.reloadData()
  772. }
  773. @objc func expandMenuAction(sender: NSMenuItem) {
  774. let index = sender.tag
  775. if index >= 0 && index < dataArray.count {
  776. let fileModel: KMMergeFileModel = dataArray[index]
  777. if fileModel.canExpand() {
  778. fileModel.open = true
  779. }
  780. self.contentionView?.reloadData()
  781. // if index < deleteArray.count {
  782. // deleteArray.remove(at: index)
  783. // }
  784. deleteArray.removeAll()
  785. if deleteArray.count > 0 {
  786. titleBarView?.setDeleteItemEnable(enable: true)
  787. } else {
  788. titleBarView?.setDeleteItemEnable(enable: false)
  789. }
  790. }
  791. }
  792. @objc func addMenuAction() {
  793. itemAddFileAction()
  794. }
  795. @objc func removeMenuAction(sender: NSMenuItem) {
  796. let index = sender.tag
  797. if index >= 0 && index < dataArray.count {
  798. dataArray.remove(at: index)
  799. self.contentionView?.reloadData()
  800. }
  801. }
  802. @objc func replaceMenuAction(sender: NSMenuItem) {
  803. let index = sender.tag
  804. if index >= 0 && index < dataArray.count {
  805. let openPanel = NSOpenPanel()
  806. openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
  807. openPanel.canChooseDirectories = false
  808. openPanel.canChooseFiles = true
  809. openPanel.allowsMultipleSelection = false
  810. openPanel.allowedFileTypes = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
  811. openPanel.beginSheetModal(for: view.window!, completionHandler: { result in
  812. if result != .OK {
  813. } else {
  814. for documentURL in openPanel.urls {
  815. self.replaceModel(documentURL: documentURL, index: index)
  816. }
  817. self.contentionView?.reloadData()
  818. }
  819. })
  820. }
  821. }
  822. }
  823. extension KMMergeViewController: KMMergeTitleBarDelegate {
  824. func titleBar(titleBar: KMMergeTitleBar, itemDidClick: KMMergeTitleBarButtonID) {
  825. KMPrint();
  826. }
  827. }
  828. extension KMMergeViewController: NSCollectionViewDataSource {
  829. func numberOfSections(in collectionView: NSCollectionView) -> Int {
  830. return 1
  831. }
  832. func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
  833. var count: Int = 0
  834. for model in dataArray {
  835. if model.open {
  836. count += Int(model.document.pageCount)
  837. } else {
  838. count += 1
  839. }
  840. }
  841. return count
  842. }
  843. func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
  844. var count: Int = 0
  845. var flagModel : KMMergeFileModel!
  846. var index: Int = NSNotFound
  847. for model in dataArray {
  848. if (flagModel != nil) {
  849. break
  850. }
  851. if model.open {
  852. for i in 0...(model.document.pageCount-1) {
  853. if count == indexPath.item {
  854. index = Int(i)
  855. flagModel = model
  856. break
  857. }
  858. count += 1
  859. }
  860. } else {
  861. if count == indexPath.item {
  862. flagModel = model
  863. break
  864. }
  865. count += 1
  866. }
  867. }
  868. if index == NSNotFound {
  869. let cellView: KMMergeCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"), for: indexPath) as! KMMergeCollectionViewItem
  870. cellView.model = flagModel
  871. cellView.doubleClick = {
  872. [self] (viewItem: AnyObject) -> () in
  873. let cellItemView: KMMergeCollectionViewItem = viewItem as! KMMergeCollectionViewItem
  874. let model = cellItemView.model
  875. if model.canExpand() {
  876. model.open = true
  877. self.titleBarView?.setPageRangeComboBoxHidden(isHidden: false)
  878. self.titleBarView?.model = model
  879. self.contentionView?.reloadData()
  880. // if deleteArray.contains(indexPath.item) {
  881. // deleteArray.removeObject(indexPath.item)
  882. // }
  883. deleteArray.removeAll()
  884. if deleteArray.count > 0 {
  885. titleBarView?.setDeleteItemEnable(enable: true)
  886. } else {
  887. titleBarView?.setDeleteItemEnable(enable: false)
  888. }
  889. }
  890. }
  891. cellView.pageRangeClick = {
  892. [self] (viewItem: AnyObject) -> () in
  893. let cellItemView: KMMergeCollectionViewItem = viewItem as! KMMergeCollectionViewItem
  894. let model = cellItemView.model
  895. let window = KMPageRangePickerWindowController.init(windowNibName: "KMPageRangePickerWindowController")
  896. window.fileModel = model
  897. self.view.window?.beginSheet(window.window!)
  898. pageRangeWindowController = window
  899. window.cancelClick = {
  900. [self] (window: NSWindow)->() in
  901. self.view.window?.endSheet(window)
  902. }
  903. window.confirmClick = {
  904. [self] (windowController: NSWindowController)->() in
  905. if pageRangeWindowController.selectIndex == 0 {
  906. model.pageRange = .all
  907. model.updateChildPageRange(pageRange: .all)
  908. } else if pageRangeWindowController.selectIndex == 1 {
  909. model.pageRange = .oddPages
  910. model.updateChildPageRange(pageRange: .oddPages)
  911. } else if pageRangeWindowController.selectIndex == 2 {
  912. model.pageRange = .evenPages
  913. model.updateChildPageRange(pageRange: .evenPages)
  914. } else if pageRangeWindowController.selectIndex == 3 {
  915. model.pageRange = .custom
  916. model.pageRangeString = pageRangeWindowController.customPagesTextField.stringValue
  917. model.updateChildPageRange(pageRange: .custom)
  918. let pageNumbers = findSelectPage(fileModel: model)
  919. for i in 0 ... (model.pages.count)-1 {
  920. let pageModel = model.pages[i]
  921. if pageNumbers .contains(Int(pageModel.pageID)+1) {
  922. pageModel.selected = true
  923. } else {
  924. pageModel.selected = false
  925. }
  926. }
  927. }
  928. self.contentionView?.reloadItems(at: [indexPath])
  929. self.view.window?.endSheet(windowController.window!)
  930. }
  931. }
  932. return cellView
  933. } else {
  934. let cellView: KMMergeCollectionPageViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PageCellID"), for: indexPath) as! KMMergeCollectionPageViewItem
  935. let model = flagModel.pages[index]
  936. model.page = flagModel.document.page(at: UInt(index))
  937. cellView.fileModel = flagModel
  938. cellView.model = model
  939. cellView.flodClick = {
  940. [self] (viewItem: AnyObject) -> () in
  941. let cellItemView: KMMergeCollectionPageViewItem = viewItem as! KMMergeCollectionPageViewItem
  942. let model = cellItemView.fileModel
  943. model.open = false
  944. self.titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
  945. self.contentionView?.reloadData()
  946. }
  947. cellView.selectedClick = {
  948. [self] (viewItem: AnyObject) -> () in
  949. let cellItemView: KMMergeCollectionPageViewItem = viewItem as! KMMergeCollectionPageViewItem
  950. let model = cellItemView.model
  951. model.selected = !model.selected
  952. self.titleBarView?.setPageRangeComboBoxHidden(isHidden: false)
  953. cellView.fileModel.updatePagePange()
  954. self.titleBarView?.model = cellView.fileModel
  955. self.contentionView?.reloadItems(at: [indexPath])
  956. }
  957. cellView.view.wantsLayer = true
  958. cellView.view.layer?.backgroundColor = NSColor.lightGray.cgColor
  959. return cellView
  960. }
  961. return NSCollectionViewItem()
  962. }
  963. }
  964. extension KMMergeViewController: NSCollectionViewDelegateFlowLayout {
  965. /**
  966. * MARK: item大小
  967. */
  968. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
  969. return NSMakeSize(246 * (1 + zoomScale), 322 * (1 + zoomScale))
  970. }
  971. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  972. return 0.01
  973. }
  974. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  975. return -5
  976. }
  977. }
  978. extension KMMergeViewController: NSCollectionViewDelegate {
  979. func collectionView(_ collectionView: NSCollectionView, shouldSelectItemsAt indexPaths: Set<IndexPath>) -> Set<IndexPath> {
  980. return indexPaths
  981. }
  982. func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
  983. let index: IndexPath = indexPaths.first!
  984. var i = 0
  985. for model in dataArray {
  986. if i == index.item {
  987. model.selected = true
  988. } else {
  989. model.selected = false
  990. }
  991. i += 1
  992. }
  993. deleteArray.append(index.item)
  994. if collectionView.selectionIndexes.count > 0 {
  995. titleBarView?.setDeleteItemEnable(enable: true)
  996. } else {
  997. titleBarView?.setDeleteItemEnable(enable: false)
  998. }
  999. }
  1000. func collectionView(_ collectionView: NSCollectionView, shouldDeselectItemsAt indexPaths: Set<IndexPath>) -> Set<IndexPath> {
  1001. return indexPaths
  1002. }
  1003. func collectionView(_ collectionView: NSCollectionView, didDeselectItemsAt indexPaths: Set<IndexPath>) {
  1004. let index: IndexPath = indexPaths.first!
  1005. deleteArray.removeObject(index.item)
  1006. if collectionView.selectionIndexes.count > 0 {
  1007. titleBarView?.setDeleteItemEnable(enable: true)
  1008. } else {
  1009. titleBarView?.setDeleteItemEnable(enable: false)
  1010. titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
  1011. }
  1012. }
  1013. func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set<IndexPath>, with event: NSEvent) -> Bool {
  1014. for indexPath in indexPaths {
  1015. let pageIndex = findFileModel(indexPath: indexPath).pageIndex
  1016. if pageIndex != NSNotFound { /// 页面不用拖拽
  1017. return false
  1018. }
  1019. }
  1020. return true
  1021. }
  1022. func collectionView(_ collectionView: NSCollectionView, writeItemsAt indexPaths: Set<IndexPath>, to pasteboard: NSPasteboard) -> Bool {
  1023. let data: Data = try! NSKeyedArchiver.archivedData(withRootObject: indexPaths, requiringSecureCoding: true)
  1024. pasteboard.declareTypes([self.localForDraggedTypes], owner: self)
  1025. pasteboard.setData(data, forType: self.localForDraggedTypes)
  1026. dragedIndexPaths.removeAll()
  1027. for indexPath in indexPaths {
  1028. dragedIndexPaths.append(indexPath)
  1029. }
  1030. return true
  1031. }
  1032. func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
  1033. let pboard = draggingInfo.draggingPasteboard
  1034. if (pboard.availableType(from: [localForDraggedTypes]) != nil) {
  1035. return .move
  1036. }
  1037. return NSDragOperation.generic
  1038. }
  1039. func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {
  1040. let pboard = draggingInfo.draggingPasteboard
  1041. if (pboard.availableType(from: [localForDraggedTypes]) != nil) {
  1042. // let indexPathsData: Data = pboard.data(forType: self.localForDraggedTypes)!
  1043. // let set = try!NSKeyedUnarchiver.unarchivedObject(ofClasses: Set<IndexPath.self>, from: indexPathsData)!
  1044. let dragIndex: Int = dragedIndexPaths.first!.item
  1045. let toIndex = max(0, indexPath.item-1)
  1046. if dragIndex < 0 || dragIndex > dataArray.count {
  1047. return false
  1048. }
  1049. if dragIndex == toIndex {
  1050. return false
  1051. }
  1052. /// 交互数据
  1053. let dragFileModel = dataArray[dragIndex]
  1054. dataArray.removeObject(dragFileModel)
  1055. dataArray.insert(dragFileModel, at: toIndex)
  1056. self.contentionView?.reloadData()
  1057. return true
  1058. }
  1059. return false
  1060. }
  1061. }
  1062. extension KMMergeViewController : KMMergeViewController_collectionView_delegate {
  1063. func collection_menu(for event: NSEvent) -> NSMenu? {
  1064. let point = event.locationInWindow
  1065. let rigthIndex = self.contentionView!.indexPathForItem(at: self.contentionView!.convert(point, from: nil))
  1066. if rigthIndex == nil { /// 空白处
  1067. let menu = NSMenu(title: "")
  1068. if dataArray.count == 0 {
  1069. } else {
  1070. if allItemIsExpanded() {
  1071. let foldAllItem = NSMenuItem(title: NSLocalizedString("折叠全部文件", comment: ""), action: #selector(foldAllMenuAction), keyEquivalent: "")
  1072. foldAllItem.target = self
  1073. menu.addItem(foldAllItem)
  1074. } else if allItemIsFolded() {
  1075. let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
  1076. expandAllItem.target = self
  1077. menu.addItem(expandAllItem)
  1078. } else {
  1079. let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
  1080. expandAllItem.target = self
  1081. menu.addItem(expandAllItem)
  1082. let foldAllItem = NSMenuItem(title: NSLocalizedString("折叠全部文件", comment: ""), action: #selector(foldAllMenuAction), keyEquivalent: "")
  1083. foldAllItem.target = self
  1084. menu.addItem(foldAllItem)
  1085. }
  1086. }
  1087. let addItem = NSMenuItem(title: NSLocalizedString("添加文件", comment: ""), action: #selector(addMenuAction), keyEquivalent: "")
  1088. addItem.target = self
  1089. menu.addItem(addItem)
  1090. return menu
  1091. }
  1092. let cellView = self.contentionView!.item(at: rigthIndex!)
  1093. if ((cellView?.isKind(of: KMMergeCollectionViewItem.self))! == true) {
  1094. let fileCellView: KMMergeCollectionViewItem = cellView! as! KMMergeCollectionViewItem
  1095. var index = 0
  1096. var indexTag = NSNotFound
  1097. for fileModel in dataArray {
  1098. if fileModel.isEqual(to: fileCellView.model) {
  1099. indexTag = index
  1100. break
  1101. }
  1102. index += 1
  1103. }
  1104. let menu = NSMenu(title: "")
  1105. let expandItem = NSMenuItem(title: NSLocalizedString("展开文件", comment: ""), action: #selector(expandMenuAction), keyEquivalent: "")
  1106. expandItem.target = self
  1107. expandItem.tag = indexTag
  1108. if fileCellView.model.canExpand() {
  1109. expandItem.action = #selector(expandMenuAction)
  1110. } else {
  1111. expandItem.action = nil
  1112. }
  1113. menu.addItem(expandItem)
  1114. let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
  1115. expandAllItem.target = self
  1116. menu.addItem(expandAllItem)
  1117. menu.addItem(NSMenuItem.separator())
  1118. let removeItem = NSMenuItem(title: NSLocalizedString("移除文件", comment: ""), action: #selector(removeMenuAction), keyEquivalent: "")
  1119. removeItem.target = self
  1120. removeItem.tag = indexTag
  1121. menu.addItem(removeItem)
  1122. menu.addItem(NSMenuItem.separator())
  1123. let replaceItem = NSMenuItem(title: NSLocalizedString("替换文件", comment: ""), action: #selector(replaceMenuAction), keyEquivalent: "")
  1124. replaceItem.target = self
  1125. replaceItem.tag = indexTag
  1126. menu.addItem(replaceItem)
  1127. let addItem = NSMenuItem(title: NSLocalizedString("添加文件", comment: ""), action: #selector(addMenuAction), keyEquivalent: "")
  1128. addItem.target = self
  1129. menu.addItem(addItem)
  1130. return menu
  1131. }
  1132. return nil
  1133. }
  1134. }