12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346 |
- //
- // KMMergeViewController.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2022/11/23.
- //
- import Cocoa
- import PDFKit
- import CoreGraphics
- class KMMergePage: CPDFPage {
- var drawingPage: CPDFPage!
-
- // override func draw(with box: PDFDisplayBox) {
- // super.draw(with: box)
- //
- // let context: CGContext = NSGraphicsContext.current?.graphicsPort as! CGContext
- // let pageSize = bounds(for: .cropBox).size
- //
- // drawPageWithContext(context: context, page: self.drawingPage, pageSize: pageSize)
- // }
-
- override func draw(with box: CPDFDisplayBox, to context: CGContext!) {
- super.draw(with: box, to: context)
- let pageSize = bounds(for: .cropBox).size
-
- drawPageWithContext(context: context, page: self.drawingPage, pageSize: pageSize)
- }
-
- func drawPageWithContext(context: CGContext, page: CPDFPage, pageSize: NSSize) {
- var originalSize = page.bounds(for: .cropBox).size
-
- /// 如果page的旋转角度为90,或者270,宽高交换
- if ((page.rotation % 180) != 0) {
- originalSize = NSSize(width: originalSize.height, height: originalSize.width)
- }
-
- let wRadio: CGFloat = pageSize.width/originalSize.width
- let hRadio: CGFloat = pageSize.height/originalSize.height
- let radio = min(wRadio, hRadio)
-
- context.saveGState()
- var xTransform: CGFloat = (pageSize.width-originalSize.width * radio) / 2
- var yTransform: CGFloat = (pageSize.height-originalSize.height * radio) / 2
- context.translateBy(x: xTransform, y: yTransform)
- context.scaleBy(x: radio, y: radio)
-
- page.draw(with: .cropBox, to: context)
- page.transform(context, for: .cropBox)
-
-
- // var contextRef: CGContextRef = context
- }
- }
- class KMMergeTestWindow: NSWindow {
-
- private var mergeController: KMMergeViewController!
-
- override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
- super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag);
-
- isReleasedWhenClosed = false
-
- let controller: KMMergeViewController = KMMergeViewController()
- contentView?.addSubview(controller.view)
- controller.view.frame = CGRect(x: 0, y: 0, width: contentRect.size.width, height: contentRect.size.height)
- mergeController = controller
- }
-
- }
- protocol KMMergeViewController_collectionView_delegate : NSObjectProtocol {
- func collection_menu(for event: NSEvent) -> NSMenu?
- }
- class KMMergeViewController_collectionView: NSCollectionView {
-
- weak var myDelegate: KMMergeViewController_collectionView_delegate!
-
- override func menu(for event: NSEvent) -> NSMenu? {
- guard let myDelegate = self.myDelegate else {
- return super.menu(for: event)
- }
-
- return myDelegate.collection_menu(for: event)
-
- // return super.menu(for: event)
- }
- }
- class KMMergeViewController: NSViewController {
- @IBOutlet weak var titleBar: NSBox!
- @IBOutlet weak var contentBox: NSBox!
-
- private var titleBarView: KMMergeTitleBar?
- private var scrollView: NSScrollView?
- private var contentionView: KMMergeViewController_collectionView?
-
- private var zoomScale: CGFloat = 0
- private var zoomMinScale: CGFloat = 0.5
- private var zoomMaxScale: CGFloat = 8
-
- private lazy var dataArray: [KMMergeFileModel] = []
- private lazy var deleteArray: [Int] = []
-
- private var dragedIndexPaths: [IndexPath] = []
- private let localForDraggedTypes = NSPasteboard.PasteboardType(rawValue: "localForDraggedTypes")
-
- private var pageRangeWindowController: KMPageRangePickerWindowController!
- private var mergeSettingWindowController: KMMergeSettingWindowController!
-
- private var outPDFDocument = CPDFDocument()
-
- private var lockedFiles: [URL] = []
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- initDefaultValue()
- initSubViews()
- }
-
- /**
- * MARK: - 初始化值
- */
- func initDefaultValue() {
- titleBar.titlePosition = NSBox.TitlePosition.noTitle
- titleBar.contentViewMargins = NSSize.zero
- titleBar.boxType = NSBox.BoxType.custom
- titleBar.borderWidth = 0
-
- zoomScale = 0
- }
-
- func initSubViews() {
- let titleBarView_: KMMergeTitleBar = KMMergeTitleBar()
- titleBar.contentView?.addSubview(titleBarView_)
- titleBarView_.frame = NSMakeRect(0, 0, NSWidth(titleBar.bounds), NSHeight(titleBar.bounds))
- titleBarView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
- titleBarView_.delegate = self
- titleBarView_.wantsLayer = true
- titleBarView_.layer?.backgroundColor = NSColor.white.cgColor
- titleBarView = titleBarView_
- titleBarView?.setDeleteItemEnable(enable: false)
- titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
-
- titleBarView_.itemClick = {
- [self] (itemIndex: KMMergeTitleBarButtonID) -> () in
- switch itemIndex {
- case .add:
- self.showAddMenu()
- break
- case .delete:
- for index in deleteArray {
- if index < dataArray.count {
- dataArray.remove(at: index)
- }
- }
- deleteArray.removeAll()
- self.titleBarView?.setDeleteItemEnable(enable: false)
- self.contentionView?.reloadData()
- break
- case .zoomOut:
- if zoomScale > zoomMaxScale {
- titleBarView?.setZoomItemEnable(zoomIn: false, enable: false)
- return
- }
-
- titleBarView?.setZoomItemEnable(zoomIn: true, enable: true)
- zoomScale += 0.5
-
- contentionView?.reloadData()
- break
- case .zoomIn:
- if zoomScale < zoomMinScale {
- titleBarView?.setZoomItemEnable(zoomIn: true, enable: false)
- return
- }
-
- titleBarView?.setZoomItemEnable(zoomIn: false, enable: true)
- zoomScale -= 0.5
- contentionView?.reloadData()
- break
- case .merge:
- if dataArray.count == 0 {
- let alert = NSAlert()
- alert.messageText = NSLocalizedString("没有文件", comment: "")
- alert.runModal()
-
- return
- }
-
- let windowController = KMMergeSettingWindowController.init(windowNibName: "KMMergeSettingWindowController")
- self.view.window?.beginSheet(windowController.window!)
- mergeSettingWindowController = windowController
- windowController.odd_even_mergeComboBox.isEnabled = dataArray.count == 2
-
- windowController.cancelClick = {
- [self] (window: NSWindow) -> () in
-
- self.view.window?.endSheet(window)
- }
-
- windowController.mergeClick = {
- [self] (windowController: NSWindowController) -> () in
-
- if mergeSettingWindowController.odd_even_mergeComboBox.state == .on { /// 奇偶数穿插合并
- let document = CPDFDocument()
- outPDFDocument = document
-
- mergeActionForOddEven()
-
- let panel = NSSavePanel()
- panel.nameFieldStringValue = "[新文件].pdf"
- let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
- button.state = .on
- panel.accessoryView = button
- panel.isExtensionHidden = true
- let response = panel.runModal()
- if response == .OK {
- let url = panel.url
- let result = outPDFDocument!.write(to: panel.url!)
- if result {
- if button.state == .on { /// 开启文档
- } else {
- NSWorkspace.shared.openFile(url!.path)
- }
- }
- }
- } else { /// 正常合并
- let document = CPDFDocument()
- outPDFDocument = document
-
- mergeAction()
- let panel = NSSavePanel()
- panel.nameFieldStringValue = "[新文件].pdf"
- let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
- button.state = .on
- panel.accessoryView = button
- panel.isExtensionHidden = true
- let response = panel.runModal()
- if response == .OK {
- let url = panel.url
- let result = document!.write(to: panel.url!)
- if result {
- if button.state == .on { /// 开启文档
- } else {
- NSWorkspace.shared.openFile(url!.path)
- }
- }
- }
- }
-
- self.view.window?.endSheet(windowController.window!)
- }
- break
- case .cancel:
- if dataArray.count == 0 {
- self.view.window?.close()
- } else {
- let alert = NSAlert()
- alert.messageText = NSLocalizedString("关闭将不会保存当前操作", comment: "")
- alert.addButton(withTitle: NSLocalizedString("关闭", comment: ""))
- alert.addButton(withTitle: NSLocalizedString("取消", comment: ""))
- let response = alert.runModal()
- if response == .alertFirstButtonReturn {
- self.view.window?.close()
- }
- }
-
- break
- }
- }
- titleBarView_.pageRangeClick = {
- [self] (index: Int, pageString: String) -> () in
- let model = self.titleBarView?.model
- if index == 0 {
- model?.pageRange = .all
- model?.updateChildPageRange(pageRange: .all)
- } else if index == 1 {
- model?.pageRange = .oddPages
- model?.updateChildPageRange(pageRange: .oddPages)
- } else if index == 2 {
- model?.pageRange = .evenPages
- model?.updateChildPageRange(pageRange: .evenPages)
- } else if index == 3 {
- if !isValidPagesString(pagesString: pageString) {
- let alert = NSAlert()
- alert.alertStyle = .warning
- alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
- alert.runModal()
- return
- }
-
- model?.pageRangeString = pageString
- model?.updateChildPageRange(pageRange: .custom)
-
- let pageNumbers = findSelectPage(fileModel: model!)
- for i in 0 ... (model?.pages.count)!-1 {
- let pageModel = model?.pages[i]
- if pageNumbers .contains(Int(pageModel!.pageID)+1) {
- pageModel!.selected = true
- } else {
- pageModel!.selected = false
- }
- }
-
- }
-
- self.contentionView?.reloadData()
- }
-
- let scrollView_ = NSScrollView()
- contentBox.contentView?.addSubview(scrollView_)
- scrollView_.frame = NSMakeRect(0, 0, NSWidth(contentBox.bounds), NSHeight(contentBox.bounds))
- scrollView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
- scrollView = scrollView_
-
- let layout = NSCollectionViewFlowLayout()
- layout.sectionInset = NSEdgeInsetsMake(20, 20, 20, 20)
- layout.minimumLineSpacing = 0
- layout.minimumInteritemSpacing = 2
-
- let contentionView_ = KMMergeViewController_collectionView()
- contentionView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
- contentionView_.collectionViewLayout = layout
- contentionView_.dataSource = self
- contentionView_.delegate = self
- contentionView_.register(KMMergeCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"))
- contentionView_.register(KMMergeCollectionPageViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PageCellID"))
- contentionView_.registerForDraggedTypes([localForDraggedTypes])
-
- scrollView?.documentView = contentionView_
- contentionView = contentionView_
- contentionView?.isSelectable = true
- contentionView?.allowsMultipleSelection = true
- contentionView?.myDelegate = self
- contentionView?.reloadData()
- }
-
- func mergeActionForOddEven() {
- if (dataArray.count <= 1) {
- return
- }
-
- var rootPDFOutlineArray: [CPDFOutline] = []
- var pdfDocument = outPDFDocument
-
- var mergeOutline: Bool = true
- for fileModel in dataArray {
- if fileModel.pageRange != .all {
- mergeOutline = false
- }
-
- var pdfOutlineArray: [CPDFOutline] = []
- if (fileModel.document.outlineRoot != nil) {
- rootPDFOutlineArray.append(fileModel.document.outlineRoot())
- fetchAllChildren(outline: fileModel.document.outlineRoot(), containers: &pdfOutlineArray)
- pdfOutlineArray.removeObject(fileModel.document.outlineRoot())
- } else {
- var rootOutline = CPDFOutline()
- fileModel.document.setOutlineRoot(rootOutline)
- if fileModel.document.outlineRoot() != nil {
- rootPDFOutlineArray.append(fileModel.document.outlineRoot())
- }
- }
-
- for outline in pdfOutlineArray {
- /// 这段代码主要是调用他的getter方法;outline显示正确
- outline.destination?.page().document.dataRepresentation()
- }
- }
-
- let oddDocument = dataArray.first?.document
- let oddCount: Int = Int(oddDocument!.pageCount)
- let evenDocument = dataArray.last?.document!
- let evenCount: Int = Int(evenDocument!.pageCount)
- let count = min(oddCount-1, evenCount-1)
- for i in 0 ... count {
- pdfDocument!.insertPageObject((oddDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
- pdfDocument!.insertPageObject((evenDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
- }
-
- if oddCount > evenCount {
- for i in count ... oddCount-1 {
- pdfDocument!.insertPageObject((oddDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
- }
- } else if oddCount < evenCount {
- for i in count ... evenCount-1 {
- pdfDocument!.insertPageObject((evenDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
- }
- }
-
- if mergeOutline {
- pdfDocument?.setOutlineRoot(CPDFOutline())
- var index = 0
- for outlineRoot in rootPDFOutlineArray {
- if outlineRoot != nil && outlineRoot.numberOfChildren > 0 {
- for i in 0 ... outlineRoot.numberOfChildren-1 {
- pdfDocument!.outlineRoot().insertChild(outlineRoot.child(at: UInt(i)), at: UInt(index))
- index += 1
- }
- }
- }
- }
-
- handerReDraw()
- }
-
- func mergeAction() {
- if (dataArray.count <= 1) {
- // return
- }
-
- var rootPDFOutlineArray: [CPDFOutline] = []
- var pdfDocument = outPDFDocument
-
- var mergeOutline: Bool = true
- for fileModel in dataArray {
- if fileModel.pageRange != .all {
- mergeOutline = false
- }
-
- var pdfOutlineArray: [CPDFOutline] = []
- if (fileModel.document.outlineRoot() != nil) {
- rootPDFOutlineArray.append(fileModel.document.outlineRoot())
- fetchAllChildren(outline: fileModel.document.outlineRoot(), containers: &pdfOutlineArray)
- pdfOutlineArray.removeObject(fileModel.document.outlineRoot())
- } else {
- var rootOutline = CPDFOutline()
- fileModel.document.setOutlineRoot(rootOutline)
- if fileModel.document.outlineRoot() != nil {
- rootPDFOutlineArray.append(fileModel.document.outlineRoot())
- }
- }
-
- for outline in pdfOutlineArray {
- /// 这段代码主要是调用他的getter方法;outline显示正确
- outline.destination?.page().document.dataRepresentation()
- }
-
- if fileModel.pageRange == .all {
- for i in 0 ... fileModel.document.pageCount-1 {
- pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
- }
- } else if fileModel.pageRange == .oddPages {
- for i in 0 ... fileModel.document.pageCount-1 {
- if i % 2 == 1 {
- continue
- }
-
- pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
- }
- } else if fileModel.pageRange == .evenPages {
- for i in 0 ... fileModel.document.pageCount-1 {
- if i % 2 == 0 {
- continue
- }
-
- pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
- }
- } else if fileModel.pageRange == .custom {
- let pageNumbers = self.findSelectPage(fileModel: fileModel)
- for i in pageNumbers {
- pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i-1))!, at: pdfDocument!.pageCount)
- }
- }
- }
-
- if mergeOutline {
- pdfDocument?.setOutlineRoot( CPDFOutline())
- var index = 0
- for outlineRoot in rootPDFOutlineArray {
- if outlineRoot != nil && outlineRoot.numberOfChildren > 0 {
- for i in 0 ... outlineRoot.numberOfChildren-1 {
- pdfDocument!.outlineRoot().insertChild(outlineRoot.child(at: UInt(i)), at: UInt(index))
- index += 1
- }
- }
- }
- }
-
- handerReDraw()
- }
-
- func handerReDraw() {
- if mergeSettingWindowController.selectedIndex == 0 { /// 原始尺寸
-
- } else {
- var pageSize = NSMakeSize(595, 841)
- if mergeSettingWindowController.selectedIndex == 1 { /// A4 595 x 841
- pageSize = NSMakeSize(595, 841)
- } else if mergeSettingWindowController.selectedIndex == 2 { /// A3 841 x 1190
- pageSize = NSMakeSize(841, 1190)
- } else if mergeSettingWindowController.selectedIndex == 3 { /// U.S.Letter 612 x 792
- pageSize = NSMakeSize(612, 792)
- } else if mergeSettingWindowController.selectedIndex == 4 { /// U.S.Legal 612 x 1108
- pageSize = NSMakeSize(612, 1108)
- } else if mergeSettingWindowController.selectedIndex == 5 { /// 自定义 595 x 841
- // pageSize = NSMakeSize(595, 841)
- pageSize.width = CGFloat(mergeSettingWindowController.customWidthTextField.floatValue)
- pageSize.height = CGFloat(mergeSettingWindowController.customHeightTextField.floatValue)
- }
-
- var pagesArray: [CPDFPage] = []
- let pageCount = outPDFDocument!.pageCount
- for _ in 0 ... pageCount-1 {
- pagesArray.append(outPDFDocument!.page(at: 0)!)
- outPDFDocument!.removePage(at: 0)
- }
-
- for i in 0 ... pageCount-1 {
- var page = KMMergePage()
- page.drawingPage = pagesArray[Int(i)]
- page.setBounds(NSMakeRect(0, 0, pageSize.width, pageSize.height), for: .cropBox)
- outPDFDocument!.insertPageObject(page, at: i)
- }
-
- /// 如果是自定义大小,删除所有的outline,因为合并出来的outline是无效的
- if mergeSettingWindowController.pageSizeComboBox.indexOfSelectedItem == 5 { /// 自定义 595 x 841
- let childCount: Int = Int(outPDFDocument!.outlineRoot().numberOfChildren)
- var array: [CPDFOutline] = []
- for i in 0 ... childCount-1 {
- array.append((outPDFDocument!.outlineRoot().child(at: UInt(i)))!)
- }
-
- for outline in array {
- outline.removeFromParent()
- }
- }
- }
- }
-
- func fetchAllChildren(outline: CPDFOutline, containers: inout [CPDFOutline]) {
- if !containers.contains(outline) {
- containers.append(outline)
- }
-
- if outline != nil && outline.numberOfChildren > 0 {
- for i in 0 ... (outline.numberOfChildren-1) {
- containers.append(outline.child(at: i)!)
-
- fetchAllChildren(outline: outline.child(at: i)!, containers: &containers)
- }
- }
- }
-
- func showAddMenu() {
- let menu: NSMenu = NSMenu()
- let addFileitem = menu.addItem(withTitle: NSLocalizedString("添加文件", comment: ""), action: #selector(itemAddFileAction), keyEquivalent: "")
- addFileitem.target = self
- let addFolderitem = menu.addItem(withTitle: NSLocalizedString("添加文件夹", comment: ""), action: #selector(itemAddFolderAction), keyEquivalent: "")
- addFolderitem.target = self
- let addOpenFileitem = menu.addItem(withTitle: NSLocalizedString("添加已打开文件", comment: ""), action: #selector(itemAddOpenFileAction), keyEquivalent: "")
- addOpenFileitem.target = self
- addOpenFileitem.action = nil
-
- let point: NSPoint = NSMakePoint(0, -10)
- menu.popUp(positioning: nil, at: point, in: titleBarView?.addItem)
- }
-
- @objc func itemAddFileAction() {
- let openPanel = NSOpenPanel()
- openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
- openPanel.canChooseDirectories = false //是否允许选择目录
- openPanel.canChooseFiles = true //是否可以选择文件
- openPanel.allowsMultipleSelection = true //是否允许多选
- openPanel.allowedFileTypes = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
-
- openPanel.beginSheetModal(for: view.window!, completionHandler: { result in
- if result != .OK {
-
- } else {
- for documentURL in openPanel.urls {
- self.addModel(documentURL: documentURL)
- }
-
- self.contentionView?.reloadData()
-
- self.dealLockedFiles()
- }
- })
- }
-
- @objc func itemAddFolderAction() {
- let openPanel = NSOpenPanel()
- openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
- openPanel.canChooseDirectories = true
- openPanel.canChooseFiles = false
- openPanel.allowsMultipleSelection = true
-
- openPanel.beginSheetModal(for: view.window!, completionHandler: { [self] result in
- if result != .OK {
-
- } else {
- var result: [URL] = []
- for folderURL in openPanel.urls {
- findAllFiles(folder: folderURL, result: &result)
- }
-
- for documentURL in result {
- addModel(documentURL: documentURL)
- }
- self.contentionView?.reloadData()
-
- self.dealLockedFiles()
- }
- })
- }
-
- func findAllFiles(folder: URL, result: inout [URL]) {
- let fileManager = FileManager.default
- var isDirectory: ObjCBool = ObjCBool(false)
- fileManager.fileExists(atPath: folder.path, isDirectory: &isDirectory)
- if (!isDirectory.boolValue) {
- return
- }
-
- let contents = try?fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil)
- if contents?.count == 0 {
- return
- }
-
- let array = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
- for documentURL in contents! {
- var isDirectory: ObjCBool = ObjCBool(false)
- fileManager.fileExists(atPath: documentURL.path, isDirectory: &isDirectory)
- if (isDirectory.boolValue) {
- findAllFiles(folder: documentURL, result: &result)
- } else {
- if !array.contains(documentURL.pathExtension.lowercased()) {
- continue
- }
-
- result.append(documentURL)
- }
- }
- }
-
- @objc func itemAddOpenFileAction() {
-
- }
-
- func addModel(documentURL: URL) {
- let model: KMMergeFileModel = KMMergeFileModel();
- model.documentURL = documentURL
- if documentURL.pathExtension.lowercased() == "pdf" {
- model.document = CPDFDocument.init(url: documentURL)
- if model.document.isLocked {
- lockedFiles.append(documentURL)
-
- return
- }
-
- model.myDocument = CPDFDocument.init(url: documentURL)
- model.pageRange = .all
- model.page = model.document.page(at: 0)
- if model.document.pageCount > 1 {
- for i in 0 ... model.document.pageCount-1 {
- let pageModel = KMMergePageModel()
- pageModel.selected = true
- pageModel.pageID = Int(i)
- model.pages.append(pageModel)
- }
- } else {
-
- }
- } else {
- let doucument = CPDFDocument.init(url: documentURL)
- model.document = doucument
- model.page = doucument?.page(at: 0)
- model.document.insertPageObject(model.page, at: 0)
- }
- self.dataArray.append(model)
- }
-
- func replaceModel(documentURL: URL, index: Int) {
- if index >= 0 && index < dataArray.count {
- let model: KMMergeFileModel = KMMergeFileModel();
- model.documentURL = documentURL
- if documentURL.pathExtension.lowercased() == "pdf" {
- model.document = CPDFDocument.init(url: documentURL)
- model.myDocument = CPDFDocument.init(url: documentURL)
- model.pageRange = .all
- model.page = model.document.page(at: 0)
- if model.document.pageCount > 1 {
- for i in 0 ... model.document.pageCount {
- let pageModel = KMMergePageModel()
- pageModel.selected = true
- pageModel.pageID = Int(i)
- model.pages.append(pageModel)
- }
- } else {
-
- }
- } else {
- let doucument = CPDFDocument.init(url: documentURL)
- model.document = doucument
- model.page = doucument?.page(at: 0)
- model.document.insertPageObject(model.page, at: 0)
- }
- self.dataArray[index] = model
- }
- }
-
- func isValidPagesString(pagesString: String)-> Bool {
- var valid = false
- for ch in pagesString {
- if ch != "0" && ch != "1" && ch != "2" && ch != "3" && ch != "4" && ch != "5" && ch != "6" && ch != "7" && ch != "8" && ch != "9" && ch != "," && ch != "-" {
- valid = false
- break
- } else {
- valid = true
- }
- }
-
- return valid
- }
-
- func findSelectPage(fileModel: KMMergeFileModel) -> ([Int]) {
- if !isValidPagesString(pagesString: fileModel.pageRangeString) {
- return []
- }
-
- var result: [Int] = []
- let array = fileModel.pageRangeString.components(separatedBy: ",")
- for string in array {
- if string.isEmpty {
- return []
- } else {
- let pages = string .components(separatedBy: "-")
- if pages.count > 2 {
- return []
- } else if pages.count == 1 {
- let page = pages[0]
- if page.isEmpty || Int(page)! > fileModel.document.pageCount || Int(page)! == 0 {
- return []
- } else {
- var hasSame: Bool = false
- for i in result {
- if i == Int(page)! {
- hasSame = true
- return []
- }
- }
- if !hasSame {
- result.append(Int(page)!)
- }
- }
- } else if pages.count == 2 {
- let page1 = pages[0]
- let page2 = pages[1]
- if page1.isEmpty || page2.isEmpty || Int(page1)! >= Int(page2)! || Int(page2)! > fileModel.myDocument.pageCount || Int(page1)! == 0 {
- return []
- } else {
- var hasSame: Bool = false
- for i in Int(page1)! ... Int(page2)! {
- for j in result {
- if j == i {
- hasSame = true
- return []
- }
- }
- }
- if !hasSame {
- for i in Int(page1)! ... Int(page2)! {
- result.append(i)
- }
- }
- }
- }
- }
- }
-
- return result
- }
-
- func findFileModel(indexPath: IndexPath) -> (fileModel: KMMergeFileModel, pageIndex: Int) {
- var count: Int = 0
- var flagModel : KMMergeFileModel!
- var index: Int = NSNotFound
- for model in dataArray {
- if (flagModel != nil) {
- break
- }
-
- if model.open {
- for i in 0...(model.document.pageCount-1) {
- if count == indexPath.item {
- index = Int(i)
- flagModel = model
- break
- }
-
- count += 1
- }
- } else {
- if count == indexPath.item {
- flagModel = model
- break
- }
-
- count += 1
- }
- }
-
- return (flagModel, index)
- }
-
- func allItemIsExpanded() -> Bool {
- for fileModel in dataArray {
- if fileModel.canExpand() && !fileModel.open {
- return false
- }
- }
- return true
- }
-
- func allItemIsFolded() -> Bool {
- for fileModel in dataArray {
- if fileModel.open {
- return false
- }
- }
- return true
- }
-
- func dealLockedFiles() {
- if lockedFiles.count > 0 {
- let documentURL = lockedFiles.first
- let alert = NSAlert()
- alert.messageText = documentURL!.lastPathComponent.appending(", 已被保护")
- alert.addButton(withTitle: "输入密码")
- alert.addButton(withTitle: "关闭")
- let response = alert.runModal()
- if response == .alertFirstButtonReturn {
- let window = KMPasswordInputWindow.createWindow()
- window?.documentURL = documentURL!
- window?.type = .open
-
- window?.itemClick = { (_, index: Int, string: String) in
- if index == 1 {
- self.view.window?.endSheet(window!)
-
- self.lockedFiles.remove(at: 0)
- self.dealLockedFiles()
- } else {
- self.view.window?.endSheet(window!)
-
- let model = KMMergeFileModel()
- model.documentURL = documentURL
- model.document = CPDFDocument(url: documentURL!)
- model.document.unlock(withPassword: string)
- model.myDocument = CPDFDocument.init(url: documentURL)
- model.pageRange = .all
- model.page = model.document.page(at: 0)
- model.password = string
- if model.document.pageCount > 1 {
- for i in 0 ... model.document.pageCount-1 {
- let pageModel = KMMergePageModel()
- pageModel.selected = true
- pageModel.pageID = Int(i)
- model.pages.append(pageModel)
- }
- }
-
- self.dataArray.append(model)
-
- self.contentionView?.reloadData()
- self.lockedFiles.remove(at: 0)
- self.dealLockedFiles()
- }
- }
-
- self.view.window?.beginSheet(window!)
- } else {
- self.lockedFiles.remove(at: 0)
- self.dealLockedFiles()
- }
- }
- }
-
- /**
- * MARK: Menu Actions
- */
- @objc func expandAllMenuAction() {
- for fileModel in dataArray {
- if fileModel.canExpand() {
- fileModel.open = true
- }
- }
-
- self.contentionView?.reloadData()
-
- deleteArray.removeAll()
- titleBarView?.setDeleteItemEnable(enable: false)
- }
-
- @objc func foldAllMenuAction() {
- for fileModel in dataArray {
- fileModel.open = false
- }
-
- self.contentionView?.reloadData()
- }
-
- @objc func expandMenuAction(sender: NSMenuItem) {
- let index = sender.tag
- if index >= 0 && index < dataArray.count {
- let fileModel: KMMergeFileModel = dataArray[index]
- if fileModel.canExpand() {
- fileModel.open = true
- }
-
- self.contentionView?.reloadData()
-
- // if index < deleteArray.count {
- // deleteArray.remove(at: index)
- // }
- deleteArray.removeAll()
-
- if deleteArray.count > 0 {
- titleBarView?.setDeleteItemEnable(enable: true)
- } else {
- titleBarView?.setDeleteItemEnable(enable: false)
- }
- }
- }
-
- @objc func addMenuAction() {
- itemAddFileAction()
- }
-
- @objc func removeMenuAction(sender: NSMenuItem) {
- let index = sender.tag
- if index >= 0 && index < dataArray.count {
- dataArray.remove(at: index)
-
- self.contentionView?.reloadData()
- }
- }
-
- @objc func replaceMenuAction(sender: NSMenuItem) {
- let index = sender.tag
- if index >= 0 && index < dataArray.count {
- let openPanel = NSOpenPanel()
- openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
- openPanel.canChooseDirectories = false
- openPanel.canChooseFiles = true
- openPanel.allowsMultipleSelection = false
- openPanel.allowedFileTypes = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
-
- openPanel.beginSheetModal(for: view.window!, completionHandler: { result in
- if result != .OK {
-
- } else {
- for documentURL in openPanel.urls {
- self.replaceModel(documentURL: documentURL, index: index)
- }
- self.contentionView?.reloadData()
- }
- })
- }
- }
- }
- extension KMMergeViewController: KMMergeTitleBarDelegate {
- func titleBar(titleBar: KMMergeTitleBar, itemDidClick: KMMergeTitleBarButtonID) {
- KMPrint();
- }
- }
- extension KMMergeViewController: NSCollectionViewDataSource {
- func numberOfSections(in collectionView: NSCollectionView) -> Int {
- return 1
- }
-
- func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
- var count: Int = 0
- for model in dataArray {
- if model.open {
- count += Int(model.document.pageCount)
- } else {
- count += 1
- }
- }
-
- return count
- }
-
- func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
- var count: Int = 0
- var flagModel : KMMergeFileModel!
- var index: Int = NSNotFound
- for model in dataArray {
- if (flagModel != nil) {
- break
- }
-
- if model.open {
- for i in 0...(model.document.pageCount-1) {
- if count == indexPath.item {
- index = Int(i)
- flagModel = model
- break
- }
-
- count += 1
- }
- } else {
- if count == indexPath.item {
- flagModel = model
- break
- }
-
- count += 1
- }
- }
-
- if index == NSNotFound {
- let cellView: KMMergeCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"), for: indexPath) as! KMMergeCollectionViewItem
- cellView.model = flagModel
- cellView.doubleClick = {
- [self] (viewItem: AnyObject) -> () in
- let cellItemView: KMMergeCollectionViewItem = viewItem as! KMMergeCollectionViewItem
- let model = cellItemView.model
- if model.canExpand() {
- model.open = true
-
- self.titleBarView?.setPageRangeComboBoxHidden(isHidden: false)
- self.titleBarView?.model = model
- self.contentionView?.reloadData()
-
- // if deleteArray.contains(indexPath.item) {
- // deleteArray.removeObject(indexPath.item)
- // }
- deleteArray.removeAll()
-
- if deleteArray.count > 0 {
- titleBarView?.setDeleteItemEnable(enable: true)
- } else {
- titleBarView?.setDeleteItemEnable(enable: false)
- }
- }
- }
- cellView.pageRangeClick = {
- [self] (viewItem: AnyObject) -> () in
- let cellItemView: KMMergeCollectionViewItem = viewItem as! KMMergeCollectionViewItem
- let model = cellItemView.model
- let window = KMPageRangePickerWindowController.init(windowNibName: "KMPageRangePickerWindowController")
- window.fileModel = model
- self.view.window?.beginSheet(window.window!)
- pageRangeWindowController = window
-
- window.cancelClick = {
- [self] (window: NSWindow)->() in
- self.view.window?.endSheet(window)
- }
-
- window.confirmClick = {
- [self] (windowController: NSWindowController)->() in
- if pageRangeWindowController.selectIndex == 0 {
- model.pageRange = .all
- model.updateChildPageRange(pageRange: .all)
- } else if pageRangeWindowController.selectIndex == 1 {
- model.pageRange = .oddPages
- model.updateChildPageRange(pageRange: .oddPages)
- } else if pageRangeWindowController.selectIndex == 2 {
- model.pageRange = .evenPages
- model.updateChildPageRange(pageRange: .evenPages)
- } else if pageRangeWindowController.selectIndex == 3 {
- model.pageRange = .custom
- model.pageRangeString = pageRangeWindowController.customPagesTextField.stringValue
- model.updateChildPageRange(pageRange: .custom)
-
- let pageNumbers = findSelectPage(fileModel: model)
- for i in 0 ... (model.pages.count)-1 {
- let pageModel = model.pages[i]
- if pageNumbers .contains(Int(pageModel.pageID)+1) {
- pageModel.selected = true
- } else {
- pageModel.selected = false
- }
- }
- }
-
- self.contentionView?.reloadItems(at: [indexPath])
- self.view.window?.endSheet(windowController.window!)
- }
- }
-
- return cellView
- } else {
- let cellView: KMMergeCollectionPageViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PageCellID"), for: indexPath) as! KMMergeCollectionPageViewItem
- let model = flagModel.pages[index]
- model.page = flagModel.document.page(at: UInt(index))
- cellView.fileModel = flagModel
- cellView.model = model
- cellView.flodClick = {
- [self] (viewItem: AnyObject) -> () in
- let cellItemView: KMMergeCollectionPageViewItem = viewItem as! KMMergeCollectionPageViewItem
- let model = cellItemView.fileModel
- model.open = false
- self.titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
- self.contentionView?.reloadData()
- }
-
- cellView.selectedClick = {
- [self] (viewItem: AnyObject) -> () in
- let cellItemView: KMMergeCollectionPageViewItem = viewItem as! KMMergeCollectionPageViewItem
- let model = cellItemView.model
- model.selected = !model.selected
- self.titleBarView?.setPageRangeComboBoxHidden(isHidden: false)
- cellView.fileModel.updatePagePange()
- self.titleBarView?.model = cellView.fileModel
-
- self.contentionView?.reloadItems(at: [indexPath])
- }
-
- cellView.view.wantsLayer = true
- cellView.view.layer?.backgroundColor = NSColor.lightGray.cgColor
-
- return cellView
- }
- return NSCollectionViewItem()
- }
- }
- extension KMMergeViewController: NSCollectionViewDelegateFlowLayout {
- /**
- * MARK: item大小
- */
- func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
- return NSMakeSize(246 * (1 + zoomScale), 322 * (1 + zoomScale))
- }
-
- func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
- return 0.01
- }
-
- func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
- return -5
- }
- }
- extension KMMergeViewController: NSCollectionViewDelegate {
- func collectionView(_ collectionView: NSCollectionView, shouldSelectItemsAt indexPaths: Set<IndexPath>) -> Set<IndexPath> {
- return indexPaths
- }
-
- func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
- let index: IndexPath = indexPaths.first!
- var i = 0
- for model in dataArray {
- if i == index.item {
- model.selected = true
- } else {
- model.selected = false
- }
- i += 1
- }
-
- deleteArray.append(index.item)
- if collectionView.selectionIndexes.count > 0 {
- titleBarView?.setDeleteItemEnable(enable: true)
- } else {
- titleBarView?.setDeleteItemEnable(enable: false)
- }
- }
-
- func collectionView(_ collectionView: NSCollectionView, shouldDeselectItemsAt indexPaths: Set<IndexPath>) -> Set<IndexPath> {
- return indexPaths
- }
-
- func collectionView(_ collectionView: NSCollectionView, didDeselectItemsAt indexPaths: Set<IndexPath>) {
- let index: IndexPath = indexPaths.first!
- deleteArray.removeObject(index.item)
-
- if collectionView.selectionIndexes.count > 0 {
- titleBarView?.setDeleteItemEnable(enable: true)
- } else {
- titleBarView?.setDeleteItemEnable(enable: false)
- titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
- }
- }
-
- func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set<IndexPath>, with event: NSEvent) -> Bool {
- for indexPath in indexPaths {
- let pageIndex = findFileModel(indexPath: indexPath).pageIndex
- if pageIndex != NSNotFound { /// 页面不用拖拽
- return false
- }
- }
- return true
- }
-
- func collectionView(_ collectionView: NSCollectionView, writeItemsAt indexPaths: Set<IndexPath>, to pasteboard: NSPasteboard) -> Bool {
- let data: Data = try! NSKeyedArchiver.archivedData(withRootObject: indexPaths, requiringSecureCoding: true)
- pasteboard.declareTypes([self.localForDraggedTypes], owner: self)
- pasteboard.setData(data, forType: self.localForDraggedTypes)
-
- dragedIndexPaths.removeAll()
- for indexPath in indexPaths {
- dragedIndexPaths.append(indexPath)
- }
- return true
- }
-
- func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
- let pboard = draggingInfo.draggingPasteboard
- if (pboard.availableType(from: [localForDraggedTypes]) != nil) {
- return .move
- }
-
- return NSDragOperation.generic
- }
-
- func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {
- let pboard = draggingInfo.draggingPasteboard
- if (pboard.availableType(from: [localForDraggedTypes]) != nil) {
- // let indexPathsData: Data = pboard.data(forType: self.localForDraggedTypes)!
- // let set = try!NSKeyedUnarchiver.unarchivedObject(ofClasses: Set<IndexPath.self>, from: indexPathsData)!
-
- let dragIndex: Int = dragedIndexPaths.first!.item
- let toIndex = max(0, indexPath.item-1)
- if dragIndex < 0 || dragIndex > dataArray.count {
- return false
- }
-
- if dragIndex == toIndex {
- return false
- }
-
- /// 交互数据
- let dragFileModel = dataArray[dragIndex]
- dataArray.removeObject(dragFileModel)
- dataArray.insert(dragFileModel, at: toIndex)
-
- self.contentionView?.reloadData()
-
- return true
- }
-
- return false
- }
- }
- extension KMMergeViewController : KMMergeViewController_collectionView_delegate {
- func collection_menu(for event: NSEvent) -> NSMenu? {
- let point = event.locationInWindow
- let rigthIndex = self.contentionView!.indexPathForItem(at: self.contentionView!.convert(point, from: nil))
-
- if rigthIndex == nil { /// 空白处
- let menu = NSMenu(title: "")
-
- if dataArray.count == 0 {
- } else {
- if allItemIsExpanded() {
- let foldAllItem = NSMenuItem(title: NSLocalizedString("折叠全部文件", comment: ""), action: #selector(foldAllMenuAction), keyEquivalent: "")
- foldAllItem.target = self
- menu.addItem(foldAllItem)
- } else if allItemIsFolded() {
- let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
- expandAllItem.target = self
- menu.addItem(expandAllItem)
- } else {
- let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
- expandAllItem.target = self
- menu.addItem(expandAllItem)
-
- let foldAllItem = NSMenuItem(title: NSLocalizedString("折叠全部文件", comment: ""), action: #selector(foldAllMenuAction), keyEquivalent: "")
- foldAllItem.target = self
- menu.addItem(foldAllItem)
- }
- }
-
- let addItem = NSMenuItem(title: NSLocalizedString("添加文件", comment: ""), action: #selector(addMenuAction), keyEquivalent: "")
- addItem.target = self
- menu.addItem(addItem)
- return menu
- }
-
- let cellView = self.contentionView!.item(at: rigthIndex!)
- if ((cellView?.isKind(of: KMMergeCollectionViewItem.self))! == true) {
- let fileCellView: KMMergeCollectionViewItem = cellView! as! KMMergeCollectionViewItem
- var index = 0
- var indexTag = NSNotFound
- for fileModel in dataArray {
- if fileModel.isEqual(to: fileCellView.model) {
- indexTag = index
- break
- }
- index += 1
- }
-
- let menu = NSMenu(title: "")
- let expandItem = NSMenuItem(title: NSLocalizedString("展开文件", comment: ""), action: #selector(expandMenuAction), keyEquivalent: "")
- expandItem.target = self
- expandItem.tag = indexTag
- if fileCellView.model.canExpand() {
- expandItem.action = #selector(expandMenuAction)
- } else {
- expandItem.action = nil
- }
-
- menu.addItem(expandItem)
-
- let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
- expandAllItem.target = self
- menu.addItem(expandAllItem)
-
- menu.addItem(NSMenuItem.separator())
-
- let removeItem = NSMenuItem(title: NSLocalizedString("移除文件", comment: ""), action: #selector(removeMenuAction), keyEquivalent: "")
- removeItem.target = self
- removeItem.tag = indexTag
-
- menu.addItem(removeItem)
-
- menu.addItem(NSMenuItem.separator())
-
- let replaceItem = NSMenuItem(title: NSLocalizedString("替换文件", comment: ""), action: #selector(replaceMenuAction), keyEquivalent: "")
- replaceItem.target = self
- replaceItem.tag = indexTag
- menu.addItem(replaceItem)
-
- let addItem = NSMenuItem(title: NSLocalizedString("添加文件", comment: ""), action: #selector(addMenuAction), keyEquivalent: "")
- addItem.target = self
- menu.addItem(addItem)
- return menu
- }
- return nil
- }
- }
|