123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347 |
- //
- // KMMergeViewController.swift
- // PDF Master
- //
- // 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().window()
- 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
- }
- }
|