// // KMMainViewController+Action.swift // PDF Master // // Created by wanjun on 2022/12/15. // import Foundation extension KMMainViewController { func search(searchString: String, isCase: Bool) { let document = self.listView.document if ((document?.isFinding) != nil) { document?.cancelFindString() } if searchString == "" { self.searchResults = [] self.leftSideViewController.searchViewController.searchResults = self.searchResults self.leftSideViewController.searchViewController.reloadData() } else { mwcFlags.wholeWordSearch = isCase == true ? 1 : 0 var findArray : [[CPDFSelection]] if isCase { findArray = self.listView.document.findString(searchString) ?? [] } else { findArray = self.listView.document.findString(searchString, with: .caseSensitive) ?? [] } self.searchResults.removeAll() for selections in findArray { for selection in selections { let mode : KMSearchMode = KMSearchMode() mode.selection = selection mode.attributedString = KMOCToolClass.getAttributedString(selection: selection, keyword: searchString) mode.selectionPageIndex = self.listView.document.index(for: selection.page) self.searchResults.insert(mode, at: self.searchResults.count) } } self.leftSideViewController.searchViewController.searchResults = self.searchResults self.leftSideViewController.searchViewController.reloadData() } } func removeSignatures(signatures:[CPDFSignature]) { for signature in signatures { self.listView.document.removeSignature(signature) } for i in 0.. 0 { mSignatures.append(sign) } } self.leftSideViewController.signatureViewController.signatures = signatures self.leftSideViewController.signatureViewController.reloadData() } //MARK: menu菜单 func fontColorMenuItem()->NSMenuItem { let fontColorItem = NSMenuItem(title: NSLocalizedString("Text Color", comment: ""), action: #selector(menuItemEditingClick_FontColor), keyEquivalent: "") return fontColorItem; } func fontSizeMenuItem()->NSMenuItem { let currentFontSize = self.listView.editingTextFontSize() let fontSizes = self.fontSizes() let submenu = NSMenu(title: "") for i in 0 ... fontSizes.count - 1 { let fontSize : String = fontSizes.object(at: i) as! String let item = NSMenuItem(title:fontSize as! String, action: #selector(menuItemEditingClick_FontSize), keyEquivalent: "") item.target = self item.tag = i submenu.addItem(item) if (Int(currentFontSize) == Int(fontSize)) { item.state = .on } } let fontSizeItem = NSMenuItem(title: NSLocalizedString("Font Size", comment: ""), action:nil, keyEquivalent: "") fontSizeItem.submenu = submenu return fontSizeItem; } func corpImageMenuItem()->NSMenuItem { var corpImageItem = NSMenuItem(title: NSLocalizedString("Confirm Crop", comment: ""), action: #selector(menuItemEditingClick_CropImage), target: self) return corpImageItem } func cancelCorpImageMenuItem()->NSMenuItem { let cancelCorpImageItem = NSMenuItem(title: NSLocalizedString("Cancel Crop", comment: ""), action: #selector(menuItemEditingClick_CancelCrop), target: self) return cancelCorpImageItem } func restoreCorpImageMenuItem()->NSMenuItem { let cancelCorpImageItem = NSMenuItem(title: NSLocalizedString("Restore Crop", comment: ""), action: #selector(menuItemEditingClick_RestoreCrop), target: self) return cancelCorpImageItem } func cutImageArea()->NSMenuItem { let deleteItem = NSMenuItem(title: NSLocalizedString("Crop", comment: ""), action: #selector(menuItemEditingClick_CutImage), target: self) return deleteItem } func editAddBlanMenu(menu:NSMenu){ menu.insertItem(withTitle: NSLocalizedString("Add Text", comment: ""), action: #selector(addImageText), target: self, at: 0) menu.insertItem(withTitle: NSLocalizedString("Add Image", comment: ""), action: #selector(addImageText), target: self, at: 1) } func addText() -> NSMenuItem { var addTextItem = NSMenuItem(title: NSLocalizedString("Add Text", comment: ""), action: #selector(addImageText), target: self, tag: 0) return addTextItem } func addImage() -> NSMenuItem { var addImageItem = NSMenuItem(title: NSLocalizedString("Add Image", comment: ""), action: #selector(addImageText), target: self, tag: 1) return addImageItem } func replaceImageArea()->NSMenuItem { let replaceItem = NSMenuItem(title: NSLocalizedString("Replace", comment: ""), action: #selector(menuItemEditingClick_ReplaceImage), target: self) return replaceItem } func exportImageArea()->NSMenuItem { let exportItem = NSMenuItem(title: NSLocalizedString("Export", comment: ""), action: #selector(menuItemEditingClick_ExportImage), target: self) return exportItem } func exportImageStampItem()->NSMenuItem { let exportItem = NSMenuItem(title: NSLocalizedString("Export", comment: ""), action: #selector(menuItemEditingClick_ExportImage), target: self) let menu = NSMenu() menu.insertItem(withTitle: NSLocalizedString("PNG", comment: ""), action:#selector(exportStampImage), target: self, tag:0, at: 0) menu.insertItem(withTitle: NSLocalizedString("PDF", comment: ""), action:#selector(exportStampImage), target: self, tag:2, at: 1) exportItem.submenu = menu return exportItem } func exportMenu() -> NSMenu { let menu = NSMenu() menu.insertItem(withTitle: NSLocalizedString("PNG", comment: ""), action:#selector(exportCorpImage), target: self, tag:0, at: 0) menu.insertItem(withTitle: NSLocalizedString("JPG", comment: ""), action:#selector(exportCorpImage), target: self, tag:1, at: 1) menu.insertItem(withTitle: NSLocalizedString("PDF", comment: ""), action:#selector(exportCorpImage), target: self, tag:2, at: 2) return menu } func cropMenu() -> NSMenu { let menu = NSMenu() menu.insertItem(withTitle: NSLocalizedString("Crop Current Page", comment: ""), action:#selector(cropCurrentPage), target: self, at: 0) menu.insertItem(withTitle: NSLocalizedString("Crop All Pages", comment: ""), action:#selector(cropAllPage), target: self, at: 1) menu.insertItem(withTitle: NSLocalizedString("Auto Crop – Separate", comment: ""), action:#selector(autoCropAll), target: self, at: 2) menu.insertItem(withTitle: NSLocalizedString("Auto Crop – Combined", comment: ""), action:#selector(autoCropAll), target: self, at: 2) return menu } func zoomSelectionMenuItem() -> NSMenuItem { let item = NSMenuItem(title: NSLocalizedString("Zoom To Selection", comment: ""), action: #selector(doZoomToAutoSelection), target: self) return item } func setDefaultAnnotationPorpert(type:CAnnotationType) -> NSMenuItem { let item = NSMenuItem(title: NSLocalizedString("Set as Default", comment: ""), action: #selector(defaultAnnotationPorpert), target: self, tag: type.rawValue) return item } func enterAnnotationStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Add Annotation", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() stypeMenu.addItem(withTitle: NSLocalizedString("Freehand", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 0) stypeMenu.addItem(withTitle: NSLocalizedString("Text", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 1) stypeMenu.addItem(withTitle: NSLocalizedString("Note", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 2) stypeMenu.addItem(withTitle: NSLocalizedString("Rectangle", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 3) stypeMenu.addItem(withTitle: NSLocalizedString("Circle", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 4) stypeMenu.addItem(withTitle: NSLocalizedString("Arrow", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 5) stypeMenu.addItem(withTitle: NSLocalizedString("Line", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 6) if self.isReadMode { } else { stypeMenu.addItem(withTitle: NSLocalizedString("Link", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 7) stypeMenu.addItem(withTitle: NSLocalizedString("Stamp", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 8) stypeMenu.addItem(withTitle: NSLocalizedString("Signature", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 9) } stypItem.submenu = stypeMenu if self.listView.annotationType == .ink { stypeMenu.item(at: 0)?.state = .on } else if self.listView.annotationType == .freeText { stypeMenu.item(at: 1)?.state = .on } else if self.listView.annotationType == .anchored { stypeMenu.item(at: 2)?.state = .on } else if self.listView.annotationType == .square { stypeMenu.item(at: 3)?.state = .on } else if self.listView.annotationType == .circle { stypeMenu.item(at: 4)?.state = .on } else if self.listView.annotationType == .arrow { stypeMenu.item(at: 5)?.state = .on } else if self.listView.annotationType == .line { stypeMenu.item(at: 6)?.state = .on } else if self.listView.annotationType == .link { stypeMenu.item(at: 7)?.state = .on } else if self.listView.annotationType == .stamp { stypeMenu.item(at: 8)?.state = .on } else if self.listView.annotationType == .signSignature { stypeMenu.item(at: 9)?.state = .on } return stypItem } func setAnnotationToolStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Tool Mode", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() stypeMenu.addItem(withTitle: NSLocalizedString("Default Tool", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: 0) stypeMenu.addItem(withTitle: NSLocalizedString("Scroll Tool", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: 1) stypeMenu.addItem(withTitle: NSLocalizedString("Magnify", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: 2) stypeMenu.addItem(withTitle: NSLocalizedString("Select", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: 3) stypeMenu.addItem(withTitle: NSLocalizedString("Zoom to Selected Area", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: 4) stypItem.submenu = stypeMenu if self.toolbarController.toolbarType == .Annatiton { stypeMenu.item(at: 0)?.state = .on } else if self.toolbarController.toolbarType == .Move { stypeMenu.item(at: 1)?.state = .on } else if self.toolbarController.toolbarType == .Magnify { stypeMenu.item(at: 2)?.state = .on } else if self.toolbarController.toolbarType == .Select { stypeMenu.item(at: 3)?.state = .on } else if self.toolbarController.toolbarType == .SelectZoom { stypeMenu.item(at: 4)?.state = .on } return stypItem } func addReadModelStype() -> NSMenuItem { var stypItem = NSMenuItem(title: NSLocalizedString("Read Mode On", comment: ""), action: #selector(openReadModel), target: self) if self.isReadMode { stypItem = NSMenuItem(title: NSLocalizedString("Read Mode Off", comment: ""), action: #selector(closeReadModel), target: self) } return stypItem } func addHighlightLinksStype() -> NSMenuItem { let highlightLink = KMPreferenceManager.shared.highlightLinks var highlightLinkTitle = NSLocalizedString("Highlight Links", comment: "") if highlightLink { highlightLinkTitle = NSLocalizedString("Disable Highlight Links", comment: "") } var highlightLinksItem = NSMenuItem(title: highlightLinkTitle, action: #selector(highlightLinks), target: self) return highlightLinksItem } func addAnnotationForStyleMenu(menu:NSMenu) { if menu == nil { return } let height = NSMenuItem(title: NSLocalizedString("Highlight", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 0) let underline = NSMenuItem(title: NSLocalizedString("Underline", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 1) let strickout = NSMenuItem(title: NSLocalizedString("Strikethrough", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 2) let text = NSMenuItem(title: NSLocalizedString("Text", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 3) let note = NSMenuItem(title: NSLocalizedString("Note", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 4) let rectangle = NSMenuItem(title: NSLocalizedString("Rectangle", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 5) let oval = NSMenuItem(title: NSLocalizedString("Oval", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 6) let line = NSMenuItem(title: NSLocalizedString("Line", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 7) let link = NSMenuItem(title: NSLocalizedString("Add Link", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 8) let outline = NSMenuItem(title: NSLocalizedString("Add Outline", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 9) let aiTranslation = NSMenuItem(title: NSLocalizedString("AI Translation", comment: ""), action: #selector(aiTranslationAction), target: self) // let tts = NSMenuItem(title: NSLocalizedString("TTS", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 10)! menu.insertItem(NSMenuItem.separator(), at: menu.items.count) if listView.currentSelection.selectionType() != .image { menu.insertItem(height, at: menu.items.count) menu.insertItem(underline, at: menu.items.count) menu.insertItem(strickout, at: menu.items.count) menu.insertItem(NSMenuItem.separator(), at: menu.items.count) } if self.isReadMode { } else { if listView.currentSelection.selectionType() != .image && listView.currentSelection.selectionType() != .text { menu.insertItem(text, at: menu.items.count) menu.insertItem(note, at: menu.items.count) } } if self.isReadMode { } else { if listView.currentSelection.selectionType() != .image { menu.insertItem(NSMenuItem.separator(), at: menu.items.count) menu.insertItem(rectangle, at: menu.items.count) menu.insertItem(oval, at: menu.items.count) } } if self.isReadMode { } else { if listView.currentSelection.selectionType() != .image && listView.currentSelection.selectionType() != .text { menu.insertItem(line, at: menu.items.count) } } menu.insertItem(NSMenuItem.separator(), at: menu.items.count) if self.isReadMode { } else { menu.insertItem(link, at: menu.items.count) } if self.isReadMode { } else { if listView.currentSelection.selectionType() != .image { menu.insertItem(outline, at: menu.items.count) } } menu.insertItem(NSMenuItem.separator(), at: menu.items.count) if self.isReadMode { } else { if (listView.currentSelection.selectionType() != .image) { menu.insertItem(aiTranslation, at: menu.items.count) } } menu.insertItem(NSMenuItem.separator(), at: menu.items.count) } func addBookmarkMenu() -> NSMenuItem { if self.listView.document.bookmark(forPageIndex: UInt(self.listView.currentPageIndex)) == nil { let bookMarkItem = NSMenuItem(title: NSLocalizedString("Add Bookmark", comment: ""), action: #selector(menuItemBookMarkClick_add), target: self) return bookMarkItem } else { let bookMarkItem = NSMenuItem(title: NSLocalizedString("Remove Bookmark", comment: ""), action: #selector(menuItemBookMarkClick_add), target: self) return bookMarkItem } } func findStringMenu() -> NSMenuItem { let menuItem = NSMenuItem(title: NSLocalizedString("Find", comment: ""), action: #selector(menuItemAnnotationClick_FindString), target: self) menuItem.keyEquivalent = "f" return menuItem } func printingMenu() -> NSMenuItem { let menuItem = NSMenuItem(title: NSLocalizedString("Print", comment: ""), action: #selector(menuItemAnnotationClick_Print), keyEquivalent: "p") return menuItem } func fontSizes()->NSArray { return ["6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "24", "36", "48", "72", "96", "144", "288"] } //MARK: menuItem Action @objc func menuItemEditingClick_FontColor(sender: NSMenuItem) { let color = listView.editingSelectionFontColor() let panel = NSColorPanel.shared panel.setTarget(self) panel.setAction(#selector(fontColorChangeAction)) panel.orderFront(nil) panel.showsAlpha = false panel.color = color ?? NSColor.black } @objc func fontColorChangeAction(sender: NSColorPanel) { self.listView.setEditingSelectionFontColor(sender.color) } @objc func menuItemEditingClick_FontSize(sender: NSMenuItem) { let fontSize = self.fontSizes().object(at: sender.tag) self.listView.setEditingSelectionFontSize(CGFloat(Int(fontSize as! String)!)) } @objc func addImageText(sender: NSMenuItem) { let event = NSApp.currentEvent let clickLocation = event?.locationInWindow var point = self.listView.convert(clickLocation!, from: NSApp.mainWindow?.contentView) var point2 = self.listView.convert(point, to: self.listView.currentPage()) point2 = CGPoint(x: self.listView.bounds.width - point2.x, y: self.listView.bounds.height - point2.y) point = point2 if sender.tag == 0 { KMPrint("添加文字") let isSelect = self.toolbarController.findItem(KMToolbarAddTextEditPDFItemIdentifier)?.isSelected ?? false if !isSelect { self.toolbarController.selectItem(KMToolbarAddTextEditPDFItemIdentifier) } // self.pdfViewEditingAddTextArea(self.listView, add: CGRectMake(point.x, point.y, 0, 0)) } else if sender.tag == 1 { KMPrint("添加图片") let isSelect = self.toolbarController.findItem(KMToolbarAddImageEditPDFItemIdentifier)?.isSelected ?? false if !isSelect { self.toolbarController.selectItem(KMToolbarAddImageEditPDFItemIdentifier) } // self.pdfViewEditingAddImageArea(self.listView, add: CGRectMake(point.x, point.y, 0, 0)) } else if sender.tag == 2 { KMPrint("粘贴") } } @objc func menuItemEditingClick_CropImage(sender: NSMenuItem) { if self.rightSideViewController.eidtPDFImageProperty != nil { self.rightSideViewController.eidtPDFImageProperty.confirmVCImageAction((Any).self) } else { if self.listView.cropAreas != nil && self.listView.selectImageAreas != nil{ self.listView.cropEditImageArea(self.listView.selectImageAreas, withBounds: self.listView.cropAreas.cropRect) } } } @objc func menuItemEditingClick_CancelCrop(sender: NSMenuItem) { if self.rightSideViewController.eidtPDFImageProperty != nil { self.rightSideViewController.eidtPDFImageProperty?.cancelCutImageAction("") } else { self.listView.exitCrop(with: self.listView.selectImageAreas) self.listView.cropAreas = nil self.listView.isEditImage = false } } @objc func menuItemEditingClick_RestoreCrop(sender: NSMenuItem) { if self.rightSideViewController.eidtPDFImageProperty != nil { self.rightSideViewController.eidtPDFImageProperty?.restoreCutImageAction("") } else { self.listView.resetCrop(with: self.listView.selectImageAreas) } } @objc func menuItemEditingClick_CutImage(sender: NSMenuItem) { if self.listView.selectImageAreas != nil { self.listView.isEditImage = true self.listView.enterCrop(with: self.listView.selectImageAreas) self.rightSideViewController.eidtPDFImageProperty.updateButtonState(hidden: false) } } @objc func menuItemEditingClick_ReplaceImage(sender: NSMenuItem) { if self.listView.selectImageAreas == nil { return } let panel = NSOpenPanel() panel.allowsMultipleSelection = false panel.allowedFileTypes = ["png","jpg"] panel.beginSheetModal(for: NSApp.mainWindow!) { response in if response == .OK { let openPath = panel.url?.path let s = self.listView.replace(self.listView.selectImageAreas, imagePath: openPath!) if s { } } } } @objc func menuItemEditingClick_ExportImage(sender: NSMenuItem) { if self.listView.selectImageAreas == nil { return } let panel = NSSavePanel() // panel.nameFieldStringValue = "[新文件].png" panel.nameFieldStringValue = "\(NSLocalizedString("Untitled", comment: "")).jpg" // 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 if FileManager.default.fileExists(atPath: url!.path) { try?FileManager.default.removeItem(atPath: url!.path) } let result = self.listView.extractImage(with: self.listView.selectImageAreas, toImagePath: url!.path) if result { NSWorkspace.shared.activateFileViewerSelecting([url!]) // if button.state == .on { /// 开启文档 // NSWorkspace.shared.openFile(url!.path) // } else { // // } } } } @objc func menuItemAnnotationClick_toolModel(sender: NSMenuItem) { self.listView.toolMode = .noteToolMode var identifier = KMDocumentAnnotationToolbarItemIdentifier var model : KMToolbarViewType = .None switch sender.tag { case 0: identifier = KMDocumentAnnotationToolbarItemIdentifier model = .Annatiton case 1: identifier = KMToolbarMoveToolModeItemIdentifier model = .Move case 2: identifier = KMToolbarMagnifyToolModeItemIdentifier model = .Magnify case 3: identifier = KMToolbarSelectToolModeItemIdentifier model = .Select case 4: identifier = KMToolbarZoomToSelectionItemIdentifier model = .SelectZoom default: break } let item : KMToolBoxItem = (self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: identifier))! self.toolbarController.mainToolBarView?.delegate?.toolbarViewController?(self.toolbarController.mainToolBarView!, clickMode:model, toolbar: item, []) } @objc func menuItemAnnotationClick_add(sender : NSMenuItem) { var annotationType : CAnnotationType = .unkown switch sender.tag { case 0: annotationType = .highlight case 1: annotationType = .underline case 2: annotationType = .strikeOut case 3: annotationType = .freeText case 4: annotationType = .anchored case 5: annotationType = .square case 6: annotationType = .circle case 7: annotationType = .line case 8: annotationType = .link case 9: // var newOutline : CPDFOutline = CPDFOutline() // newOutline.label = "11111111" // let des = self.listView.currentDestination // if "\(des?.point.x ?? 0)" != "nan" { // newOutline.destination = self.listView.currentDestination // } else { // let destination : CPDFDestination = CPDFDestination(document: self.listView.document, pageIndex: self.listView.currentPageIndex, at: CGPoint(x: 0, y: 0), zoom: self.listView.scaleFactor) // newOutline.destination = destination // } // let current = self.listView.document.outlineRoot().insertChild(at: 0) ?? CPDFOutline() // let parent = current.parent ?? CPDFOutline() // let index = current.index + 1 // parent.insertChild(newOutline, at: index) if self.leftPanelOpen == false || self.leftSideViewController.type.methodType != .Outline { self.leftSideViewController.refreshMethodType(methodType: .Outline) } self.leftSideViewController.outlineViewController.addItemAction() return case 10: annotationType = .unkown default: break } if (annotationType != .link) { self.listView.addAnnotation(with: annotationType, selection: self.listView.currentSelection, page: self.listView.currentSelection.page, bounds: self.listView.currentSelection.bounds) self.listView.currentSelection = nil; return } // link let selection = self.listView.currentSelection self.toolbarController.selectItem(KMToolbarLinkAnnotationItemIdentifier) DispatchQueue.main.async { Task { @MainActor in #if VERSION_DMG if await (KMLightMemberManager.manager.canUseAdvanced() == false) { return } #endif let annotation = self.listView.addAnnotation(with: annotationType, selection: selection, page: selection?.page, bounds: selection!.bounds) self.listView.currentSelection = nil; if (annotation != nil) { self.listView.updateActiveAnnotations([annotation!]) } } } } @objc func aiTranslationAction(sender: NSMenuItem) { let content = self.listView.currentSelection.string() as? String ?? "" let origin = self.listView.currentSelection.bounds.origin self.aiTranslationWindow = KMAITranslationWindowController.init(windowNibName: "KMAITranslationWindowController") self.aiTranslationWindow?.content = content self.view.window!.addChildWindow(self.aiTranslationWindow!.window!, ordered: NSWindow.OrderingMode.above) self.aiTranslationWindow!.window?.center() } @objc func menuItemAnnotationClick_addStype(sender: NSMenuItem) { Task { @MainActor in #if VERSION_DMG if (sender.tag == 7 || sender.tag == 8 || sender.tag == 9) { if await (KMLightMemberManager.manager.canUseAdvanced() == false) { let _ = KMComparativeTableViewController.show(window: self.view.window!) return } } #endif var point = mouseRightMenuEvent?.locationInWindow if (point == nil) { point = NSZeroPoint } let currentPoint: NSPoint = self.listView.convert(point!, from: self.listView.superview) let currentPage = self.listView.page(for: currentPoint, nearest: true) let pagePoint = self.listView.convert(currentPoint, to: currentPage) var annotation: CPDFAnnotation? if self.isReadMode { if (sender.tag == 0 || sender.tag == 7 || sender.tag == 8 || sender.tag == 9) { // Ink & Link & stamp & sign self.listView.toolMode = .noteToolMode } switch sender.tag { case 0: self.listView.annotationType = CAnnotationType.ink case 1: // self.listView.annotationType = CAnnotationType.freeText let defaultSize = self.listView.defaultSize(with: .freeText, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .freeText, selection: nil, page: currentPage, bounds: bounds) if ((annotation) != nil) { self.listView.updateActiveAnnotations([annotation!]) self.listView.edit(annotation) } case 2: // self.listView.annotationType = CAnnotationType.anchored let defaultSize = self.listView.defaultSize(with: .anchored, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .anchored, selection: nil, page: currentPage, bounds: bounds) self.listView.edit(annotation) case 3: // self.listView.annotationType = CAnnotationType.square let defaultSize = self.listView.defaultSize(with: .square, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .square, selection: nil, page: currentPage, bounds: bounds) case 4: // self.listView.annotationType = CAnnotationType.circle let defaultSize = self.listView.defaultSize(with: .circle, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .circle, selection: nil, page: currentPage, bounds: bounds) case 5: // self.listView.annotationType = CAnnotationType.arrow let defaultSize = self.listView.defaultSize(with: .arrow, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .arrow, selection: nil, page: currentPage, bounds: bounds) case 6: // self.listView.annotationType = CAnnotationType.line let defaultSize = self.listView.defaultSize(with: .line, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .line, selection: nil, page: currentPage, bounds: bounds) case 7: self.listView.annotationType = CAnnotationType.link self.openRightPane() case 8: self.listView.annotationType = CAnnotationType.stamp self.openRightPane() case 9: self.listView.annotationType = CAnnotationType.signSignature self.openRightPane() default: break } self.rightSideViewController.isHidden = true self.rightSideViewController.subViewType = .AnnotationProperts } else { if (sender.tag == 7 || sender.tag == 8 || sender.tag == 9) { // Ink & Link & stamp & sign if(self.toolbarController.toolbarType == .None) { self.toolbarController.toolbarType = .Annatiton } self.listView.toolMode = .noteToolMode } switch sender.tag { case 0: self.toolbarController.ignoreCurrentAnnotationTypeChange = true self.rightMouseEventing = true if(self.toolbarController.toolbarType == .None) { self.toolbarController.toolbarType = .Annatiton } self.listView.toolMode = .noteToolMode self.listView.annotationType = CAnnotationType.ink case 1: // self.listView.annotationType = CAnnotationType.freeText let defaultSize = self.listView.defaultSize(with: .freeText, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .freeText, selection: nil, page: currentPage, bounds: bounds) // self.view.window?.makeFirstResponder() if ((annotation) != nil) { // self.listView.updateActiveAnnotations([annotation!]) self.listView.edit(annotation) } case 2: // self.listView.annotationType = CAnnotationType.anchored let defaultSize = self.listView.defaultSize(with: .anchored, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .anchored, selection: nil, page: currentPage, bounds: bounds) self.listView.edit(annotation) case 3: // self.listView.annotationType = CAnnotationType.square let defaultSize = self.listView.defaultSize(with: .square, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .square, selection: nil, page: currentPage, bounds: bounds) case 4: // self.listView.annotationType = CAnnotationType.circle let defaultSize = self.listView.defaultSize(with: .circle, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .circle, selection: nil, page: currentPage, bounds: bounds) case 5: // self.listView.annotationType = CAnnotationType.arrow let defaultSize = self.listView.defaultSize(with: .arrow, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .arrow, selection: nil, page: currentPage, bounds: bounds) case 6: // self.listView.annotationType = CAnnotationType.line let defaultSize = self.listView.defaultSize(with: .line, in: currentPage) let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .line, selection: nil, page: currentPage, bounds: bounds) case 7: self.listView.annotationType = CAnnotationType.link self.openRightPane() case 8: self.listView.annotationType = CAnnotationType.stamp self.openRightPane() case 9: self.listView.annotationType = CAnnotationType.signSignature self.openRightPane() default: break } // self.rightSideViewController.view.isHidden = false self.rightSideViewController.isHidden = false // self.openRightPane() self.rightSideViewController.subViewType = .AnnotationProperts } if (annotation != nil) { self.listView.updateIsRightActiveAnnotations([annotation!]) } } } @objc func menuItemBookMarkClick_add(sender:NSMenuItem) { if self.listView.document.bookmark(forPageIndex: UInt(self.listView.currentPageIndex)) == nil { let index = self.listView.currentPageIndex self.listView.document.addBookmark("\(NSLocalizedString("Page", comment: "")) \(index+1)", forPageIndex: UInt(index)) self.listView.setNeedsDisplayForVisiblePages() } else { self.listView.document.removeBookmark(forPageIndex: UInt(self.listView.currentPageIndex)) self.listView.setNeedsDisplayForVisiblePages() } if self.isReadMode { } else { if self.leftPanelOpen == false || self.leftSideViewController.type.methodType != .BookMark { self.leftSideViewController.refreshMethodType(methodType: .BookMark) } let bookMark = self.listView.document.bookmark(forPageIndex: UInt(self.listView.currentPageIndex)) if bookMark != nil { let item = KMBookMarkItem() item.bookMark = bookMark! item.label = (bookMark?.label)! item.index = UInt(bookMark!.pageIndex) self.leftSideViewController.bookViewController.reloadData() self.leftSideViewController.bookViewController.addBookMarkAndEdit(newBookMark: item) } else { self.leftSideViewController.bookViewController.reloadData() } } } @objc func menuItemAnnotationClick_FindString(sender:NSMenuItem) { self.leftSideViewController.refreshMethodType(methodType: .Search) } @objc func menuItemAnnotationClick_Print(sender:NSMenuItem) { let rect = listView.currentSelectionRect() let page = listView.currentPage() let copyPage : CPDFPage = page!.copy() as! CPDFPage copyPage.setBounds(rect, for: .cropBox) let image : NSImage = copyPage.thumbnail(of:(copyPage.bounds(for: .cropBox)).size) // let pdfDocument : PDFDocument = PDFDocument() // let newpage : PDFPage = PDFPage(image: image)! // pdfDocument.insert(newpage, at: 0) // 执行右键操作后,需要取消框选区域 if self.listView.toolMode == .selectToolMode { objc_sync_enter(self) self.listView.selectionRect = NSZeroRect self.listView.selectionPageIndex = UInt(NSNotFound) objc_sync_exit(self) } if (self.listView.document != nil && !self.listView.document.allowsPrinting) { // 有打印限制 KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [weak self] result ,password in if (result == .cancel) { return } // 解除权限 self?.isSaveKeyChain = false self?.listView.document.unlock(withPassword: password) // 隐藏提示 self?.hiddenSecureLimitTip() // 去打印 KMPrintWindowController.printImage(image: image) } return } KMPrintWindowController.printImage(image: image) } // MARK: Redact 【密文标记】 @objc func redact_menuItemClick_delete(sender: NSMenuItem?) { self.listView.remove(self.listView.activeAnnotation) } @objc func redact_menuItemClick_setProperty(sender: NSMenuItem?) { let windowController = KMRedactPropertyWindowController(windowNibName: "KMRedactBaseWindowController") windowController.annotation = (self.listView.activeAnnotation as! CPDFRedactAnnotation) self.view.window?.beginSheet(windowController.window!) self.currentWindowController = windowController windowController.itemClick = { [weak self] index, value in if (index == 1) { /// 取消 self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil return } let windowController_redact = self?.currentWindowController as! KMRedactPropertyWindowController let annotaton: CPDFRedactAnnotation = self?.listView.activeAnnotation as! CPDFRedactAnnotation annotaton.setBorderColor(windowController_redact.outsideColor) annotaton.setInteriorColor(windowController_redact.fillColor) if (windowController_redact.isOver) { annotaton.setFontColor(windowController_redact.fontColor) annotaton.setAlignment(windowController_redact.aligement) annotaton.setFont(windowController_redact.font) annotaton.setOverlayText(windowController_redact.overText) } self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil } } @objc func redact_menuItemClick_setCurrentPropertyToDefaultValue(sender: NSMenuItem?) { if (self.listView.activeAnnotation == nil || (self.listView.activeAnnotation.isKind(of: CPDFRedactAnnotation.self)) == false) { return } let annotation: CPDFRedactAnnotation = self.listView.activeAnnotation as! CPDFRedactAnnotation let model = CPDFAnnotationModel(annotationType: .redact) model?.setColor(annotation.borderColor()) model?.setInteriorColor(annotation.interiorColor()) let overlayText: String = annotation.overlayText() if (overlayText.isEmpty) { model?.setIsOverlayText(false) } else { model?.setIsOverlayText(true) model?.setOverlayText(overlayText) model?.setFontColor(annotation.fontColor()) model?.setAlignment(annotation.alignment()) model?.setFontName(annotation.font().fontName) model?.setFontSize(annotation.font().pointSize) } } @objc func redact_menuItemClick_MultiPageFlag(sender: NSMenuItem?) { let anno = self.listView.activeAnnotation if (anno == nil || (anno?.isKind(of: CPDFRedactAnnotation.self)) == false) { return } let windowController = KMRedactMutilPageFlagWindowController(windowNibName: "KMRedactBaseWindowController") windowController.pageCount = Int(self.listView.document.pageCount) self.currentWindowController = windowController self.view.window?.beginSheet(windowController.window!) windowController.itemClick = { [weak self] index, value in if (index == 1) { self!.view.window?.endSheet(self!.currentWindowController.window!) self!.currentWindowController = nil return } let windowController_mutilPageFlag = self?.currentWindowController as! KMRedactMutilPageFlagWindowController let pageType = windowController_mutilPageFlag.pageType let pageString = windowController_mutilPageFlag.pageString if (pageType == 4) { /// 自定义页面 let array = KMPageRangeTools.findSelectPage(pageRangeString: pageString, pageCount: Int((self?.listView.document.pageCount)!)) if (array.count == 0) { let alert = NSAlert() alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "") alert.runModal() return } } self!.view.window?.endSheet(self!.currentWindowController.window!) self!.currentWindowController = nil let indexs = KMRedactTools.getPageIndexs(pageType, string: pageString, Int((self?.listView.document.pageCount)!)) if (indexs.count == 0) { return } for i in indexs { let page: CPDFPage = (self?.listView.document.page(at: UInt(i)))! let redactAnno = KMRedactTools.createRedactAnnotation((self?.listView.document)!, anno as! CPDFRedactAnnotation) self?.listView.add(redactAnno, to: page) } } } @objc func redact_menuItemClick_apply(sender: NSMenuItem?) { self.exeRedactConfirm(.redactOne) {} } @objc func redact_menuItemClick_clear(sender: NSMenuItem?) { self.exeRedactConfirm(.eraserOne) {} } @objc func redact_menuItemClick_paste(sender: NSMenuItem?) { } @objc func exportStampImage(sender:NSMenuItem) { if listView.activeAnnotation != nil && ((listView.activeAnnotation is CPDFStampAnnotation) || (listView.activeAnnotation is CPDFSignatureAnnotation)) { var image : NSImage = NSImage() if (listView.activeAnnotation is CPDFStampAnnotation) { image = (listView.activeAnnotation as! CPDFStampAnnotation).stampImage() } else if (listView.activeAnnotation is CPDFSignatureAnnotation) { image = (listView.activeAnnotation as! CPDFSignatureAnnotation).signImage } let data = image.tiffRepresentation if sender.tag == 0 { let imageRep : NSBitmapImageRep = NSBitmapImageRep(data: data!) ?? NSBitmapImageRep() imageRep.size = image.size let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.png, properties: [:])! let savePanel = NSSavePanel() savePanel.allowedFileTypes = ["png"] savePanel.beginSheetModal(for: self.view.window!) { response in if (response != .OK) { return } if NSData(data: imageData).write(to: savePanel.url!, atomically: true) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } } else { let pdfdocument = CPDFDocument() let signatureImagePath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first?.stringByAppendingPathComponent("signatureImage.png") if NSData(data: data!).write(to: URL(fileURLWithPath: signatureImagePath!), atomically: true) { pdfdocument?.insertPage(image.size, withImage: signatureImagePath, at: 0) let savePanel = NSSavePanel() savePanel.allowedFileTypes = ["pdf"] savePanel.beginSheetModal(for: self.view.window!) { response in if (response != .OK) { return } if pdfdocument!.write(to: savePanel.url!) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } } } } } @objc func exportCorpImage(sender:NSMenuItem) { let rect = NSIntegralRect(listView.currentSelectionRect()) let orgPage : CPDFPage = listView.currentSelectionPage() ?? listView.currentPage() let page : CPDFPage = orgPage.copy() as! CPDFPage page.setBounds(rect, for: .cropBox) let image = page.thumbnail(of: rect.size) ?? NSImage() let data = image.tiffRepresentation let imageRep : NSBitmapImageRep = NSBitmapImageRep(data: data!) ?? NSBitmapImageRep() imageRep.size = rect.size let savePanel = NSSavePanel() switch sender.tag { case 0: savePanel.allowedFileTypes = ["png"] let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.png, properties: [:])! savePanel.beginSheetModal(for: self.view.window!) { response in if (response != .OK) { return } if NSData(data: imageData).write(to: savePanel.url!, atomically: true) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } case 1: savePanel.allowedFileTypes = ["jpg"] let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])! savePanel.beginSheetModal(for: self.view.window!) { response in if (response != .OK) { return } if NSData(data: imageData).write(to: savePanel.url!, atomically: true) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } case 2: savePanel.allowedFileTypes = ["pdf"] let pdfdocument = CPDFDocument() let signatureImagePath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first?.stringByAppendingPathComponent("signatureImage.png") let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])! if NSData(data: imageData).write(to: URL(fileURLWithPath: signatureImagePath!), atomically: true) { pdfdocument?.insertPage(image.size, withImage: signatureImagePath, at: 0) savePanel.beginSheetModal(for: self.view.window!) { response in if (response != .OK) { return } if pdfdocument!.write(to: savePanel.url!) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } } default: break } // 执行右键操作后,需要取消框选区域 if self.listView.toolMode == .selectToolMode { objc_sync_enter(self) self.listView.selectionRect = NSZeroRect self.listView.selectionPageIndex = UInt(NSNotFound) objc_sync_exit(self) } } @IBAction func doZoomToAutoSelection(sender:NSMenuItem) { let rect = listView.currentSelectionRect() let page = listView.currentPage() if NSIsEmptyRect(rect) == false && page != nil { let isLegacy = NSScroller.responds(to: NSSelectorFromString("preferredScrollerStyle")) == false || NSScroller.preferredScrollerStyle == .legacy var bounds = listView.bounds var scale = 1.0 if isLegacy { bounds.size.width -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle) bounds.size.height -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle) } if NSWidth(bounds) * NSHeight(rect) > NSWidth(rect) * NSHeight(bounds) { scale = NSHeight(bounds) / NSHeight(rect) } else { scale = NSWidth(bounds) / NSWidth(rect) } listView.setScaleFactor(scale, animated: false) let scrollView = listView.scroll() if isLegacy && scrollView?.hasHorizontalScroller == false || scrollView?.hasVerticalScroller == false { if ((scrollView?.hasVerticalScroller) != nil) { bounds.size.width -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle) } if ((scrollView?.hasHorizontalScroller) != nil) { bounds.size.height -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle) } if NSWidth(bounds) * NSHeight(rect) > NSWidth(rect) * NSHeight(bounds) { scale = NSHeight(bounds) / NSHeight(rect) } else { scale = NSWidth(bounds) / NSWidth(rect) } listView.setScaleFactor(scale, animated: false) } DispatchQueue.main.asyncAfter(deadline: .now() + 0.03) { [self] in let pagePoint = CGPoint(x: rect.origin.x, y: (rect.origin.y + rect.size.height)) listView.go(toTargetPoint: pagePoint, on: page, at: .top) }; } // 执行右键操作后,需要取消框选区域 if self.listView.toolMode == .selectToolMode { objc_sync_enter(self) self.listView.selectionRect = NSZeroRect self.listView.selectionPageIndex = UInt(NSNotFound) objc_sync_exit(self) } } @IBAction func autoCropAll(sender:NSMenuItem) { } private func cropPagesToRects(rects:NSPointerArray) { } @IBAction func defaultAnnotationPorpert(sender:NSMenuItem) { let model : CPDFAnnotationModel = CPDFAnnotationModel(annotationType: CAnnotationType(rawValue: sender.tag)!)! switch sender.tag { case CAnnotationType.highlight.rawValue,CAnnotationType.underline.rawValue,CAnnotationType.strikeOut.rawValue: model.setColor((listView.activeAnnotation as! CPDFMarkupAnnotation).color) model.setOpacity((listView.activeAnnotation as! CPDFMarkupAnnotation).opacity) var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 (listView.activeAnnotation as! CPDFMarkupAnnotation).color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) if sender.tag == CAnnotationType.highlight.rawValue { KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFMarkupAnnotation).opacity], forKey: KMPreference.markupColorHighlightKey) } else if sender.tag == CAnnotationType.underline.rawValue { KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFMarkupAnnotation).opacity], forKey: KMPreference.markupColorUnderlineKey) } else if sender.tag == CAnnotationType.strikeOut.rawValue { KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFMarkupAnnotation).opacity], forKey: KMPreference.markupColorStrikthroughKey) } case CAnnotationType.ink.rawValue: model.setColor((listView.activeAnnotation as! CPDFInkAnnotation).color) model.setOpacity((listView.activeAnnotation as! CPDFInkAnnotation).opacity) model.setLineWidth((listView.activeAnnotation as! CPDFInkAnnotation).lineWidth()) model.setStyle((listView.activeAnnotation as! CPDFInkAnnotation).borderStyle()) var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 (listView.activeAnnotation as! CPDFInkAnnotation).color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFInkAnnotation).opacity], forKey: KMPreference.markupColorPenKey) case CAnnotationType.freeText.rawValue: model.setColor((listView.activeAnnotation as! CPDFFreeTextAnnotation).color) model.setOpacity((listView.activeAnnotation as! CPDFFreeTextAnnotation).opacity) model.setFontColor((listView.activeAnnotation as! CPDFFreeTextAnnotation).fontColor) model.setFontName((listView.activeAnnotation as! CPDFFreeTextAnnotation).font.fontName) model.setFontSize((listView.activeAnnotation as! CPDFFreeTextAnnotation).font.pointSize) model.setAlignment((listView.activeAnnotation as! CPDFFreeTextAnnotation).alignment) var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 (listView.activeAnnotation as! CPDFFreeTextAnnotation).fontColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFFreeTextAnnotation).opacity], forKey: KMPreference.markupColorTextKey) if (KMPreferenceManager.supportFonts.contains((listView.activeAnnotation as! CPDFFreeTextAnnotation).font.fontName)) { UserDefaults.standard.set((listView.activeAnnotation as! CPDFFreeTextAnnotation).font.fontName, forKey: KMPreference.markupFontTextStringKey) UserDefaults.standard.synchronize() } let alignment = (listView.activeAnnotation as! CPDFFreeTextAnnotation).alignment if (alignment == .left || alignment == .center || alignment == .right) { UserDefaults.standard.set(alignment.rawValue, forKey: KMPreference.markupFontTextAligmentKey) UserDefaults.standard.synchronize() } case CAnnotationType.anchored.rawValue: model.setColor((listView.activeAnnotation as! CPDFTextAnnotation).color) model.setAnchoredIconType((listView.activeAnnotation as! CPDFTextAnnotation).iconType()) var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 (listView.activeAnnotation as! CPDFTextAnnotation).color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, alpha], forKey: KMPreference.markupColorNoteKey) case CAnnotationType.square.rawValue: model.setInteriorColor((listView.activeAnnotation as! CPDFSquareAnnotation).interiorColor) model.setColor((listView.activeAnnotation as! CPDFSquareAnnotation).color) model.setOpacity((listView.activeAnnotation as! CPDFSquareAnnotation).opacity) model.setLineWidth((listView.activeAnnotation as! CPDFSquareAnnotation).lineWidth()) var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 (listView.activeAnnotation as! CPDFSquareAnnotation).interiorColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFSquareAnnotation).interiorOpacity], forKey: KMPreference.markupColorRectangleFillKey) (listView.activeAnnotation as! CPDFSquareAnnotation).color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFSquareAnnotation).opacity], forKey: KMPreference.markupColorRectangleBorderKey) case CAnnotationType.circle.rawValue: model.setInteriorColor((listView.activeAnnotation as! CPDFCircleAnnotation).interiorColor) model.setColor((listView.activeAnnotation as! CPDFCircleAnnotation).color) model.setOpacity((listView.activeAnnotation as! CPDFCircleAnnotation).opacity) model.setLineWidth((listView.activeAnnotation as! CPDFCircleAnnotation).lineWidth()) var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 (listView.activeAnnotation as! CPDFCircleAnnotation).interiorColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFCircleAnnotation).interiorOpacity], forKey: KMPreference.markupColorCircleFillKey) (listView.activeAnnotation as! CPDFCircleAnnotation).color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) KMPreferenceManager.shared.setData(data: [red, green, blue, (listView.activeAnnotation as! CPDFCircleAnnotation).opacity], forKey: KMPreference.markupColorCircleBorderKey) default: break } } @objc internal func menuItemClick_HidenorShowNote(sender: NSMenuItem?) { self.showOrHideNotes() } //MARK: action @objc func cropCurrentPage() { var rect = NSIntegralRect(self.listView.currentSelectionRect()) var page: CPDFPage? if ((self.listView.currentSelectionPage()) != nil) { page = self.listView.currentSelectionPage() } else { page = self.listView.currentPage() } if (NSIsEmptyRect(rect)) { rect = KMCropTools.getPageForegroundBox(page!) } let index: UInt = (page?.pageIndex())! cropPage(at: index, in: rect) // 执行右键操作后,需要取消框选区域 if self.listView.toolMode == .selectToolMode { objc_sync_enter(self) self.listView.selectionRect = NSZeroRect self.listView.selectionPageIndex = UInt(NSNotFound) objc_sync_exit(self) } } func cropPage(at index: UInt, in rect: NSRect) { let oldRect = self.listView.document.page(at: index)?.bounds(for: .cropBox) let undoManager = self.listView.undoManager (undoManager?.prepare(withInvocationTarget: self) as? AnyObject)!.cropPage(at: index, in: oldRect!) let page = self.listView.document.page(at: index) let newRect = NSIntersectionRect(rect, (page?.bounds(for: .mediaBox))!) page?.setBounds(newRect, for: .cropBox) /// 刷新预览视图 self.listView.layoutDocumentView() self.listView.displayBox = .cropBox } @objc private func cropAllPage() { var size = NSZeroSize for i in 0 ..< self.listView.document.pageCount { let page = self.listView.document.page(at: i) var rect = KMCropTools.getPageForegroundBox(page!) size.width = fmax(size.width, NSWidth(rect)) size.height = fmax(size.height, NSHeight(rect)) } var rectArray: Array = [] for i in 0 ..< self.listView.document.pageCount { let page = self.listView.document.page(at: i) var rect = KMCropTools.getPageForegroundBox(page!) var bounds: NSRect = (page?.bounds(for: .mediaBox))! if (rect.minX - bounds.minX > bounds.maxX-rect.maxX) { rect.origin.x = rect.maxX-size.width } rect.origin.y = rect.maxY-size.height rect.size = size if (NSWidth(rect) > NSWidth(bounds)) { rect.size.width = NSWidth(bounds) } if (NSHeight(rect) > NSHeight(bounds)) { rect.size.height = NSHeight(bounds) } if (NSMinX(rect) < NSMinX(bounds)) { rect.origin.x = NSMinX(bounds) } else if (NSMaxX(rect) > NSMaxX(bounds)) { rect.origin.x = NSMaxX(bounds) - NSWidth(rect) } if (NSMinY(rect) < NSMinY(bounds)) { rect.origin.y = NSMinY(bounds) } else if (NSMaxY(rect) > NSMaxY(bounds)) { rect.origin.y = NSMaxY(bounds) - NSHeight(rect) } rectArray.append(rect) } cropPages(to: rectArray) } func cropPages(to rects: Array) { let currentPage = self.listView.currentPage() let visibleRect: NSRect = self.listView.convert(self.listView.convert(self.listView.documentView().visibleRect, from: self.listView.documentView()), to: self.listView.currentPage()) var oldRectArray: Array = [] for i in 0 ..< self.listView.document.pageCount { let page = self.listView.document.page(at: i) var rect = NSIntersectionRect(rects[Int(i)], (page?.bounds(for: .mediaBox))!) let oldRect = page?.bounds(for: .cropBox) oldRectArray.append(oldRect!) page?.setBounds(rect, for: .cropBox) } let undoManager = self.listView.undoManager (undoManager?.prepare(withInvocationTarget: self) as AnyObject).cropPages(to: oldRectArray) /// 刷新预览视图 self.listView.layoutDocumentView() self.listView.displayBox = .cropBox self.listView.go(to: currentPage) self.listView.go(to: visibleRect, on: currentPage) } private func cropCustomArea() { self.listView.toolMode = .selectToolMode self.listView.autoScales = true self.listView.autoScales = false var pageHeight: CGFloat = NSHeight(self.listView.currentPage().bounds(for: self.listView.displayBox)) if (self.listView.displaysPageBreaks) { pageHeight += 8 } var scaleFactor: CGFloat = fmax(self.listView.minimumScaleFactor, NSHeight(self.listView.frame)/pageHeight) // if (scaleFactor < self.preView.scaleFactor) { self.listView.scaleFactor = scaleFactor // } let tipView = KMCropTipView() tipView.setString(string: "请框选裁剪区域") tipView.frame = self.topTipBox.contentView!.frame tipView.autoresizingMask = NSView.AutoresizingMask(rawValue: 18) self.addTopTip(tipView) tipView.enterAction = { () in var rect = NSIntegralRect(self.listView.currentSelectionRect()) if (NSIsEmptyRect(rect)) { return } let window = KMCropSettingWindowController(windowNibName: "KMCropSettingWindowController") self.view.window?.beginSheet(window.window!) self.cropSettingWindowController = window window.itemClick = { [self] (index: Int) in if (index == 1) { /// 取消 self.view.window?.endSheet((self.cropSettingWindowController?.window)!) self.cropSettingWindowController = nil return } let pageRangeType = self.cropSettingWindowController.pageRangeIndex let pageCount: Int = Int(self.listView.document.pageCount) var pages: Array = [] if (pageRangeType == 0) { /// 当前页面 pages.append(self.listView.currentPageIndex) } else if (pageRangeType == 1) { /// 全部页面 for i in 0 ..< pageCount { pages.append(i) } } else if (pageRangeType == 2) { /// 奇数页面 var string: String = "" for i in 0 ..< pageCount { if (i % 2 == 1) { continue } pages.append(i) } } else if (pageRangeType == 3) { /// 偶数页面 var string: String = "" for i in 0 ..< pageCount { if (i % 2 == 0) { continue } pages.append(i) } } else { /// 自定义 for i in self.cropSettingWindowController.pageRangePages { pages.append(i) } } if (pages.count < 0) { let alert = NSAlert() alert.messageText = "请选择页面" alert.runModal() return } var pageSize: NSSize = NSZeroSize if (self.cropSettingWindowController.pageSize == "None") { } else { pageSize = KMCropTools.getPageSizeValue(self.cropSettingWindowController.pageSize) } for i in pages { var page: CPDFPage = self.listView.document.page(at: UInt(i)) var rect = NSIntegralRect(self.listView.selectionRect) if (NSIsEmptyRect(rect)) { rect = KMCropTools.getPageForegroundBox(page) } var newRect = NSIntersectionRect(rect, (page.bounds(for: .mediaBox))) page.setBounds(newRect, for: .cropBox) if (pageSize.width == 0 && pageSize.height == 0) { } else { // let tiffData = page.pdfListViewTIFFData(for: rect) let index: UInt = (page.pageIndex()) // let newPage: CPDFPage = nil // self.listView.document.removePage(at: index) // newPage.setBounds(NSMakeRect(0, 0, pageSize.width, pageSize.height), for: .cropBox) // let result = self.preView.document.insertPageObject(newPage, at: index) let result = self.listView.document.insertPage(pageSize, at: index) } } /// 保存到临时路径 let toPath: String = self.listView.document.documentURL.path let documentPath = NSTemporaryDirectory() let tempPath: String = "\(documentPath)/\(toPath.lastPathComponent)" if (FileManager.default.fileExists(atPath: tempPath)) { try?FileManager.default.removeItem(atPath: tempPath) } let result = self.listView.document.write(to: URL(fileURLWithPath: tempPath)) if (result) { if (FileManager.default.fileExists(atPath: toPath)) { try?FileManager.default.removeItem(atPath: toPath) } try?FileManager.default.moveItem(atPath: tempPath, toPath: toPath) } else { try?FileManager.default.removeItem(atPath: tempPath) } DispatchQueue.main.async { self.listView.toolMode = .textToolMode /// 刷新预览视图 self.listView.layoutDocumentView() self.listView.displayBox = .cropBox } self.view.window?.endSheet((self.cropSettingWindowController?.window)!) self.cropSettingWindowController = nil self.addTopTip(nil) } } } @objc private func shareDocument(sender:KMToolbarViewController, limit: Bool = false) { if (limit) { var doucumentURL : URL = self.listView.document.documentURL if doucumentURL != nil { let docDir = NSTemporaryDirectory() let documentName : String = doucumentURL.path.lastPathComponent let path = docDir.stringByAppendingPathComponent(documentName) // let writeSuccess = self.listView.document.write(to: URL(fileURLWithPath: path)) let data = KMTools.saveWatermarkDocument(document: self.listView.document, to: URL(fileURLWithPath: path), secureOptions: self.secureOptions, removePWD: self.removeSecureFlag) let writeSuccess = data != nil if writeSuccess == false { __NSBeep() return; } doucumentURL = URL(fileURLWithPath: path) } let array = [doucumentURL] let picker = NSSharingServicePicker.init(items: array) if sender.shareButton.window != nil { picker.show(relativeTo: sender.shareButton.bounds, of: sender.shareButton, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } return } var doucumentURL : URL = self.listView.document.documentURL if doucumentURL != nil { let docDir = NSTemporaryDirectory() let documentName : String = doucumentURL.path.lastPathComponent let path = docDir.stringByAppendingPathComponent(documentName) let writeSuccess = self.listView.document.write(to: URL(fileURLWithPath: path)) if writeSuccess == false { __NSBeep() return; } doucumentURL = URL(fileURLWithPath: path) } let array = [doucumentURL] let picker = NSSharingServicePicker.init(items: array) if sender.shareButton.window != nil { picker.show(relativeTo: sender.shareButton.bounds, of: sender.shareButton, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } @objc private func shareFlatten(sender:KMToolbarViewController, limit: Bool = false) { if (limit) { let document = self.listView.document ?? CPDFDocument() var path = document!.documentURL.path if path != nil { let docDir = NSTemporaryDirectory() let documentName : String = path.lastPathComponent path = docDir.stringByAppendingPathComponent(documentName) } let pathFolder = path.fileURL.deletingLastPathComponent().path var tfileName = path.deletingPathExtension.lastPathComponent let tStdFileSuffix = "_flatten" tfileName = tfileName + tStdFileSuffix + ".pdf" path = pathFolder + "/" + tfileName let data = KMTools.saveWatermarkDocumentForFlatten(document: document!, to: URL(fileURLWithPath: path)) let success = data != nil if success { let url = URL(fileURLWithPath: path) let picker = NSSharingServicePicker.init(items: [url]) if sender.shareButton.window != nil { picker.show(relativeTo: sender.shareButton.bounds, of: sender.shareButton, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } return } let document = self.listView.document ?? CPDFDocument() var path = document!.documentURL.path if path != nil { let docDir = NSTemporaryDirectory() let documentName : String = path.lastPathComponent path = docDir.stringByAppendingPathComponent(documentName) } let pathFolder = path.fileURL.deletingLastPathComponent().path var tfileName = path.deletingPathExtension.lastPathComponent let tStdFileSuffix = "_flatten" tfileName = tfileName + tStdFileSuffix + ".pdf" path = pathFolder + "/" + tfileName let success : Bool = document!.writeFlatten(to: URL(fileURLWithPath: path)) if success { let url = URL(fileURLWithPath: path) let picker = NSSharingServicePicker.init(items: [url]) if sender.shareButton.window != nil { picker.show(relativeTo: sender.shareButton.bounds, of: sender.shareButton, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } } @objc private func shareOriginalPDF(sender:KMToolbarViewController, limit: Bool = false) { if (limit) { let document = self.listView.document ?? CPDFDocument() var path = document!.documentURL.path if path != nil { let docDir = NSTemporaryDirectory() let documentName : String = path.lastPathComponent path = docDir.stringByAppendingPathComponent(documentName) } // var writeSuccess = document!.write(to: URL(fileURLWithPath: path)) let data = KMTools.saveWatermarkDocument(document: document!, to: URL(fileURLWithPath: path), secureOptions: self.secureOptions, removePWD: self.removeSecureFlag) var writeSuccess = data != nil if writeSuccess == false { __NSBeep() return; } let newDocument = CPDFDocument(url: URL(fileURLWithPath: path))! for i in 0 ... newDocument.pageCount-1 { let page = newDocument.page(at: i) var annotations : [CPDFAnnotation] = [] for annotation in page!.annotations { annotations.append(annotation) } for annotation in annotations { annotation.page.removeAnnotation(annotation) } } writeSuccess = newDocument.write(to:URL(fileURLWithPath: path)) if writeSuccess { let url = URL(fileURLWithPath: path) let picker = NSSharingServicePicker.init(items: [url]) if sender.shareButton.window != nil { picker.show(relativeTo: sender.shareButton.bounds, of: sender.shareButton, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } return } let document = self.listView.document ?? CPDFDocument() var path = document!.documentURL.path if path != nil { let docDir = NSTemporaryDirectory() let documentName : String = path.lastPathComponent path = docDir.stringByAppendingPathComponent(documentName) } var writeSuccess = document!.write(to: URL(fileURLWithPath: path)) if writeSuccess == false { __NSBeep() return; } let newDocument = CPDFDocument(url: URL(fileURLWithPath: path))! for i in 0 ... newDocument.pageCount-1 { let page = newDocument.page(at: i) var annotations : [CPDFAnnotation] = [] for annotation in page!.annotations { annotations.append(annotation) } for annotation in annotations { annotation.page.removeAnnotation(annotation) } } writeSuccess = newDocument.write(to:URL(fileURLWithPath: path)) if writeSuccess { let url = URL(fileURLWithPath: path) let picker = NSSharingServicePicker.init(items: [url]) if sender.shareButton.window != nil { picker.show(relativeTo: sender.shareButton.bounds, of: sender.shareButton, preferredEdge: NSRectEdge.minY) } else { picker.show(relativeTo: NSRect(x: (self.view.window?.contentView?.frame.size.width)!, y: (self.view.window?.contentView?.frame.size.height ?? 0)-8, width: 0, height: 0), of: self.view.window?.contentView ?? NSView(), preferredEdge: NSRectEdge.minY) } } } // 开启/关闭左边栏 @objc func toggleLeftPane() -> Void { // if lastLeftPanWidth >= functionWidth { leftPanelOpen = true applyLeftSideWidth(panelWidth+functionWidth, rightSideWidth: lastRightPanWidth) // } else { // leftPanelOpen = false // applyLeftSideWidth(functionWidth, rightSideWidth: lastRightPanWidth) // } } // 开启左边栏 @objc func openLeftPane() -> Void { leftPanelOpen = true applyLeftSideWidth(panelWidth+functionWidth,rightSideWidth: lastRightPanWidth) } // 关闭左边栏 @objc func closeLeftPane() -> Void { leftPanelOpen = false applyLeftSideWidth(functionWidth, rightSideWidth: lastRightPanWidth) } // 开启/关闭右边栏 @objc func toggleRightPane() -> Void { if lastRightPanWidth > 5 { self.rightPanelIsOpen = false applyLeftSideWidth(lastLeftPanWidth, rightSideWidth: 0) } else { self.rightPanelIsOpen = true applyLeftSideWidth(lastLeftPanWidth, rightSideWidth: defaultRightWidth) } } @objc func openRightPane() -> Void { if (KMPreferenceManager.shared.autoExpandPropertyPanel) { if self.rightPanelIsOpen { return } self.rightPanelIsOpen = true self.toolbarController.selectItem(KMRightControlToolbarItemIdentifier) applyLeftSideWidth(lastLeftPanWidth, rightSideWidth: defaultRightWidth) } } @objc func closeRightPane() -> Void { if (KMPreferenceManager.shared.autoExpandPropertyPanel) { self.rightPanelIsOpen = false self.toolbarController.cancelSelected(KMRightControlToolbarItemIdentifier) applyLeftSideWidth(lastLeftPanWidth, rightSideWidth: 0) } } func rename(_ sender: NSNotification) -> Void { if (self.view.window == nil || self.view.window!.isVisible == false) { return } let tabController = sender.object as? CTTabController if tabController?.title == self.document?.documentURL.lastPathComponent { let outputSavePanel = NSSavePanel() outputSavePanel.title = NSLocalizedString("Rename", comment: "") outputSavePanel.allowedFileTypes = ["pdf"] outputSavePanel.nameFieldStringValue = (self.document?.documentURL.lastPathComponent)! outputSavePanel.directoryURL = self.document?.documentURL.deletingLastPathComponent() let result = outputSavePanel.runModal() if result == .OK { let pdfDocument = CPDFDocument(url: self.document?.documentURL) let fileURL = pdfDocument?.documentURL let fileManager = FileManager.default let newFileURL = fileURL!.deletingLastPathComponent().appendingPathComponent(outputSavePanel.url!.lastPathComponent) var result = true do { try fileManager.moveItem(at: fileURL!, to: newFileURL) } catch { result = false KMPrint("Error renaming file! Threw: \(error.localizedDescription)") } if (result) { tabController?.title = outputSavePanel.url!.lastPathComponent if let newPdfDocument = CPDFDocument(url: newFileURL) { self.isSaveKeyChain = false newPdfDocument.unlock(withPassword: self.document?.password) if (newPdfDocument.pageCount > 0) { self.setDocument = newPdfDocument } } } } else { outputSavePanel.close() } } } func showInFinder(_ sender: Any) -> Void { if sender is NSNotification { let tabController = (sender as! NSNotification).object as? CTTabController if tabController?.title == self.document?.documentURL.lastPathComponent { let file: URL = (self.myDocument?.fileURL)! if FileManager.default.fileExists(atPath: file.path) { NSWorkspace.shared.activateFileViewerSelecting([file]) } } } else { let file: URL = (self.myDocument?.fileURL)! if FileManager.default.fileExists(atPath: file.path) { NSWorkspace.shared.activateFileViewerSelecting([file]) } } } func showOrHideNotes() { self.listView.hideNotes = !self.listView.hideNotes self.toolbarController.isShowAllAnnotations = !self.listView.hideNotes //BOTA 注释列表显示隐藏 self.leftSideViewController.annotationViewController.annotationShowState = self.listView.hideNotes ? .hidden : .none self.leftSideViewController.thumbnailViewController.annotationShowState = self.listView.hideNotes ? .hidden : .none } func closeTab(_ sender: NSNotification) -> Void { let tabController = sender.object as? CTTabController if tabController?.title == self.document?.documentURL.lastPathComponent { print("closeTab") self.leftSideViewController.clearAnnotationFilterData() self.leftSideViewController.clearNotification() } } // MARK: - // MARK: 显示窗口 internal func showCompressWindow(url: URL? = nil) { if let wc = self.currentWindowController as? KMCompressWindowController, let _ = wc.window?.isSheet { KMPrint("压缩窗口已显示") return } let windowController = KMCompressWindowController(windowNibName: "KMCompressWindowController") self.view.window?.beginSheet(windowController.window!) self.currentWindowController = windowController if let _url = url { windowController.documentURL = _url windowController.oriDocumentUrl = self.listView.document.documentURL } else { windowController.documentURL = self.listView.document.documentURL } windowController.password = self.listView.document.password windowController.itemClick = { [weak self] _ in self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil self?.toolbarController.cancelSelected(KMToolbarToolCompressItemIdentifier) } windowController.resultCallback = { [weak self] result, openDocument, fileURL, error in if (result) { self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil self?.toolbarController.cancelSelected(KMToolbarToolCompressItemIdentifier) if (openDocument) { NSDocumentController.shared.openDocument(withContentsOf: fileURL, display: true) { document, result, error in } } else { NSWorkspace.shared.activateFileViewerSelecting([fileURL]) } } else { let alert = NSAlert() alert.messageText = NSLocalizedString("Compress Faild", comment: "") alert.runModal() } } } internal func showConvertWindow(type: KMToolbarType, documentUrl: URL? = nil, identifier: String?) { if let wc = self.currentWindowController as? KMConvertBaseWindowController, let _ = wc.window?.isSheet { KMPrint("转档窗口已显示") return } var windowController: KMConvertBaseWindowController? if (type == .word) { /// Word windowController = KMConvertWordWindowController() } else if (type == .excel) { windowController = KMConvertExcelWindowController() } else if (type == .ppt || type == .rtf || type == .html || type == .conversion_text) { windowController = KMConvertPPTsWindowController() if (type == .ppt) { windowController?.subType = 1 } else if (type == .rtf) { windowController?.subType = 2 } else if (type == .html) { windowController?.subType = 3 } else if (type == .conversion_text) { windowController?.subType = 4 } } else if (type == .csv) { windowController = KMConvertCSVWindowController() } else if (type == .conversion_image) { windowController = KMConvertImageWindowController() } windowController?.subscribeWaterMarkType = type.toSubscribeWaterMarkType() var url: URL? if (documentUrl != nil) { url = documentUrl windowController?.oriDocumentUrl = self.listView.document.documentURL } else { url = self.listView.document.documentURL } let model = KMDocumentModel(url: url!) if (self.listView.document.password != nil) { let _ = model.unlock(self.listView.document.password) } model.currentIndex = self.listView.currentPageIndex windowController?.documentModel = model windowController?.itemClick = { [weak self] index in if (identifier != nil) { self?.toolbarController.cancelSelected(identifier!) } if (self?.currentWindowController == nil) { return } self?.view.window?.endSheet(self!.currentWindowController.window!) self?.currentWindowController = nil } self.view.window?.beginSheet((windowController?.window)!) self.currentWindowController = windowController } internal func showPrintWindow(pageRange: KMPrintPageRange = KMPrintPageRange(type: .allPage, selectPages: [])) { if (self.listView.document != nil && !self.listView.document.allowsPrinting) { // 有打印限制 KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [weak self] result ,password in if (result == .cancel) { return } // 解除权限 self?.listView.document.unlock(withPassword: password) // 隐藏提示 self?.hiddenSecureLimitTip() // 去打印 if let data = self?.saveWatermarkFlag, !data { KMPrintWindowController.openDocument(inputDocument: self!.listView?.document, inputPageRange: pageRange) return } if let _url = KMTools.saveWatermarkDocumentToTemp(document: self!.listView.document, secureOptions: self!.secureOptions, removePWD: self!.removeSecureFlag) { let _document = CPDFDocument(url: _url) KMPrintWindowController.showPrintWindowControll(inputData: _url, inputDocument: self?.listView.document, inputPageRange: pageRange) } else { KMPrintWindowController.openDocument(inputDocument: self?.listView?.document, inputPageRange: pageRange) } } return } if (!self.saveWatermarkFlag) { KMPrintWindowController.openDocument(inputDocument: self.listView?.document, inputPageRange: pageRange) return } if let _url = KMTools.saveWatermarkDocumentToTemp(document: self.listView.document, secureOptions: self.secureOptions, removePWD: self.removeSecureFlag) { let _document = CPDFDocument(url: _url) KMPrintWindowController.showPrintWindowControll(inputData: _url, inputDocument: self.listView.document, inputPageRange: pageRange) } else { KMPrintWindowController.openDocument(inputDocument: self.listView?.document, inputPageRange: pageRange) } } // MARK: - Split View @IBAction func secondaryViewOpenFile(_ sender: NSButton) -> Void { } func singlePageScreen(isSinglePage: Bool, doublePagesScreen isHorizontal: Bool) -> Void { if !isSinglePage && isHorizontal { self.openSecondaryPdfView?.changeBenefit(ofContrastLabelWidth: 208) } if (!isSinglePage && !isHorizontal) { self.openSecondaryPdfView?.changeBenefit(ofContrastLabelWidth: 300) } self.displaySinglePageScreen(isSinglePage: isSinglePage, doublePageScreen: isHorizontal) } func displaySinglePageScreen(isSinglePage: Bool, doublePageScreen isHorizontal: Bool) -> Void { if isSinglePage { pdfSplitView.dividerStyle = .thin pdfSplitView.setPosition(mianSplitView.maxPossiblePositionOfDivider(at: 1), ofDividerAt: 0, animate: true) } else { pdfSplitView.dividerStyle = .paneSplitter pdfSplitView.isVertical = !isHorizontal pdfSplitView.setPosition(500, ofDividerAt: 0, animate: true) if secondaryPdfView.document != nil { // secondaryPdfView.frame = pdfSplitSecondView.frame // pdfSplitSecondView.contentView = secondaryPdfView } else { openSecondaryPdfView = KMSecondaryViewController.init() openSecondaryPdfView?.view.frame = pdfSplitSecondView.frame pdfSplitSecondView.contentView = openSecondaryPdfView?.view openSecondaryPdfView?.delegate = self } } } func lastSplitPDFHeightFloat(_ rect: NSRect) -> Float { if (pdfSplitView.isVertical) { return Float(NSWidth(rect)) } else { return Float(NSHeight(rect)) } } func displaySecondaryPDFView(withUrl url: URL) -> Bool { let document = CPDFDocument.init(url: url) if document != nil { secondaryPdfView.frame = pdfSplitSecondView.frame pdfSplitSecondView.contentView = secondaryPdfView secondaryPdfView.document = nil secondaryPdfView.document = document return true } else { return false } } func updateNextAndPreViousButtonState() { let item = self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: KMDocumentNextPageToolbarItemIdentifier) let toItem = self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: KMDocumentPreviousPageToolbarItemIdentifier) if self.listView.canGoToNextPage() { item?.unEnabled = false } else { item?.unEnabled = true } if self.listView.canGoToPreviousPage() { toItem?.unEnabled = false } else { toItem?.unEnabled = true } } func updateBackAndForwardButtonState() { let item = self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: KMDocumentNextPageToolbarItemIdentifier) let toItem = self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: KMDocumentPreviousPageToolbarItemIdentifier) if self.listView.km_canGoBack() { item?.unEnabled = false } else { item?.unEnabled = true } if self.listView.km_canGoForward() { toItem?.unEnabled = false } else { toItem?.unEnabled = true } } func updateZoomInOutButtonState() { let item : KMToolBoxItem = (self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: KMDocumentZoomOutToolbarItemIdentifier)) ?? KMToolBoxItem() let toItem : KMToolBoxItem = (self.toolbarController.mainToolBarView?.toolbarItemFindItemIdentifiers(value: KMDocumentZoomToolbarItemIdentifier)) ?? KMToolBoxItem() if self.listView.canZoomIn { item.unEnabled = false } else { item.unEnabled = true } if self.listView.canZoomOut { toItem.unEnabled = false } else { toItem.unEnabled = true } } } // MARK: - // MARK: - KMSecondaryViewControllerDelegate extension KMMainViewController: KMSecondaryViewControllerDelegate { func receivedFileUrl(_ url: URL!) { let state = self.displaySecondaryPDFView(withUrl: url) if !state { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() return } } } // MARK: - // MARK: - KMMainToolbarControllerDelegate extension KMMainViewController : KMMainToolbarControllerDelegate { func changeModelAction(mode: CToolMode) { self.listView.toolMode = mode if mode == .editPDFToolMode { self.childToolbarController.updateType(newType: .editPDF) } } func toolbarViewController(_ viewController:KMToolbarViewController, zoomModel selectedTag:Int) { switch selectedTag { case 2: if self.listView.scaleFactor != 1.0 { self.listView.scaleFactor = 1.0 self.listView.autoScales = false } break case 1: let pageHeight = self.listView.currentPage()!.size.height let pdfviewHeight = self.listView.bounds.size.height self.listView.scaleFactor = pdfviewHeight/pageHeight self.listView.autoScales = false break case 0: // self.listView.autoScales = !self.listView.autoScales self.listView.autoScales = true break case 3: self.listView.scaleFactor = 0.1 break case 4: self.listView.scaleFactor = 0.25 break case 5: self.listView.scaleFactor = 0.5 break case 6: self.listView.scaleFactor = 0.75 break case 7: self.listView.scaleFactor = 1.0 break case 8: self.listView.scaleFactor = 1.5 break case 9: self.listView.scaleFactor = 2.0 break case 10: self.listView.scaleFactor = 4.0 break case 11: self.listView.scaleFactor = 8.0 break case 12: self.listView.scaleFactor = 10.0 break default: break } viewController.zoomTextField.stringValue = "\(Int(self.listView.scaleFactor*100))%" } func toolbarViewController(_ viewController: KMToolbarViewController, zoomSting: String) { var scale = CGFloat((NSString(string: zoomSting)).floatValue / 100.0) if scale > 100 { scale = 100 } if (scale <= 0.101) { self.listView.scaleFactor = self.listView.minScaleFactor() } else { self.listView.scaleFactor = scale } viewController.zoomTextField.stringValue = "\(Int(self.listView.scaleFactor*100))%" DispatchQueue.main.async { self.updateZoomInOutButtonState() } } func changePDFViewZoomInAction() { let zoomSting = self.toolbarController.mainToolBarView?.zoomTextField.stringValue ?? "10" var scale = CGFloat((NSString(string: zoomSting)).floatValue / 100.0) switch scale { case 0...0.25: scale += 0.25 case 0.25...3: scale += 0.25 case 3.1...10: scale += 0.4 case 10.1...100: scale += 1 default: scale += 1 } self.listView.scaleFactor = scale self.toolbarController.mainToolBarView?.zoomTextField.stringValue = "\(nearbyint(self.listView.scaleFactor*100))%" // self.listView.zoomIn(nil) } func changePDFViewZoomOutAction() { let zoomSting = self.toolbarController.mainToolBarView?.zoomTextField.stringValue ?? "10" var scale = CGFloat((NSString(string: zoomSting)).floatValue / 100.0) switch scale { case 0...0.25: scale = 0 case 0.25...3: scale -= 0.25 case 3.1...10: scale -= 0.4 case 10.1...100: scale -= 1 default: scale -= 1 } self.listView.scaleFactor = scale self.toolbarController.mainToolBarView?.zoomTextField.stringValue = "\(nearbyint(self.listView.scaleFactor*100))%" // self.listView.zoomOut(nil) // self.updateZoomInOutButtonState() } func changePDFViewGotoNextPageAction() { self.listView.km_goBack(nil) self.updateNextAndPreViousButtonState() } func changePDFViewGoToPreviousPageAction() { self.listView.goToPreviousPage(nil) self.updateNextAndPreViousButtonState() } func changePDFViewGotoBackAction() { self.listView.km_goBack(nil) self.updateBackAndForwardButtonState() } func changePDFViewGoToForwardAction() { self.listView.km_goForward(nil) self.updateBackAndForwardButtonState() } func showPDFViewPrintViewController() { self.trackEvent_print() self.showPrintWindow() } func aiTranslationPDFFileAction() { #if VERSION_DMG #else if !KMLightMemberManager.manager.isLogin() && NSApp.mainWindow != nil { KMLoginWindowController.show(window: NSApp.mainWindow!) return } #endif self.trackEvent_aiTranslate() self._aiTranslationPDFFileAction() // Task { @MainActor in // if await (KMLightMemberManager.manager.canPayFunction() == false) { // let _ = KMSubscribeWaterMarkWindowController.show(window: self.view.window!, type: .aiTranslate) { isSub, _, isClose in // if (isClose) { // return // } // if (isSub) { // self._aiTranslationPDFFileAction() // return // } // } // return // } // // self._aiTranslationPDFFileAction() // } } private func _aiTranslationPDFFileAction() { let isExceedsLimit = self.isPDFPageCountExceedsLimit(filePath: (self.document?.documentURL.path)!) if self.isFileGreaterThan10MB(atPath: (self.document?.documentURL.path)!) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("The uploaded file size cannot exceed 10MB", comment: "") alert.runModal() return } else if isExceedsLimit { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Documents cannot exceed 30 pages", comment: "") alert.runModal() return } let alert = NSAlert() alert.messageText = NSLocalizedString("Processing times may be longer for larger documents. Thank you for your patience.", comment: "") alert.addButton(withTitle: NSLocalizedString("Continue", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) alert.beginSheetModal(for: view.window!) { [unowned self] result in if (result == .alertFirstButtonReturn) { self.aiTranslationConfirWC = KMAITranslationConfirmWindowController.init(windowNibName: NSNib.Name("KMAITranslationConfirmWindowController")) self.aiTranslationConfirWC!.filePath = (self.document?.documentURL.path)! self.view.window?.beginSheet(self.aiTranslationConfirWC!.window!) } else if result == .alertSecondButtonReturn { return } } } func toolbarViewController(_ viewController: KMToolbarViewController, shareAction toolbarItem: KMToolBoxItem) { self.trackEvent_share() } func toolbarViewController(_ viewController: KMToolbarViewController, shareDocument item: NSMenuItem) { if (!self.saveWatermarkFlag) { self.shareDocument(sender: viewController) return } Task { @MainActor in if await (KMLightMemberManager.manager.canPayFunction() == false) { KMSubscribeWaterMarkWindowController.show(window: self.view.window!, isContinue: true) { isSubscribeSuccess, isWaterMarkExport, isClose in if (isClose) { return } if (isSubscribeSuccess) { self.shareDocument(sender: viewController) return } if (isWaterMarkExport) { self.shareDocument(sender: viewController, limit: true) return } } return } self.shareDocument(sender: viewController) } } func toolbarViewController(_ viewController: KMToolbarViewController, shareFlatten item: NSMenuItem) { // if (!self.saveWatermarkFlag) { // self.shareFlatten(sender: viewController) // return // } Task { @MainActor in #if VERSION_DMG if await (KMLightMemberManager.manager.canUseAdvanced() == false) { let _ = KMComparativeTableViewController.show(window: self.view.window!, .shareFlatten) return } #endif if await (KMLightMemberManager.manager.canPayFunction() == false) { KMSubscribeWaterMarkWindowController.show(window: self.view.window!, isContinue: true) { isSubscribeSuccess, isWaterMarkExport, isClose in if (isClose) { return } if (isSubscribeSuccess) { self.shareFlatten(sender: viewController) return } if (isWaterMarkExport) { self.shareFlatten(sender: viewController, limit: true) return } } return } self.shareFlatten(sender: viewController) } } func toolbarViewController(_ viewController: KMToolbarViewController, shareOriginalPDF item: NSMenuItem) { if (!self.saveWatermarkFlag) { self.shareOriginalPDF(sender: viewController) return } Task { @MainActor in if await (KMLightMemberManager.manager.canPayFunction() == false) { let _ = KMSubscribeWaterMarkWindowController.show(window: self.view.window!, isContinue: true) { isSubscribeSuccess, isWaterMarkExport, isClose in if (isClose) { return } if (isSubscribeSuccess) { self.shareOriginalPDF(sender: viewController) return } if (isWaterMarkExport) { self.shareOriginalPDF(sender: viewController, limit: true) return } } return } self.shareOriginalPDF(sender: viewController) } } func toolbarViewController(_ viewController: KMToolbarViewController, scanOCRModel selectedTag: Int) { if(0 == selectedTag) { self.documentAIViewController?.enteredIncreaseAllPage() self.documentAIViewController?.updateToolState(false) } else { // self.documentAIViewController?.recognitionPageString("1", with: .english) // self.documentAIViewController?.recognitionPartModel(with: .english) // self.documentAIViewController?.updateToolState(true) } // 0 : Scan 1:OCR Text } func mainToolDidClicked(_ toolController: KMToolbarController, _ beforeType: KMToolbarViewType, _ type: KMToolbarViewType, _ item: KMToolBoxItem , _ pages: [Int]) { if beforeType == .editPDF { // self.asyncSaveDocument { params in // // } } // 埋点 self.trackEvent(toolType: type) if(type != .Page) { if (hasEnterPageEdit()) { self.exitPageEdit() } } if(type != .ScanOCR) { if ((self.documentAIViewController?.view.superview) != nil) { self.listView.isHidden = false self.documentAIViewController?.creatRecognitionDocument() self.documentAIViewController?.view .removeFromSuperview() self.documentAIViewController = nil; self.listView.layoutDocumentView() } } if (type == .Page) { if (hasEnterPageEdit()) { self.exitPageEdit() } else { self.enterPageEdit(pages) } } else if(type == .ScanOCR) { if((self.documentAIViewController?.view.superview) != nil) { let alert = NSAlert() alert.messageText = NSLocalizedString("If you need to edit again after exit, you need to re-execute OCR recognition, sure you want to exit?", comment: "") alert.addButton(withTitle: "YES") alert.addButton(withTitle: "NO") let result = alert.runModal() if (result == .alertFirstButtonReturn) { /// 取消 self.listView.isHidden = false self.documentAIViewController?.creatRecognitionDocument() self.documentAIViewController?.view .removeFromSuperview() self.documentAIViewController = nil; self.listView.layoutDocumentView() } else { self.toolbarController.toolbarType = .ScanOCR } } else { self.documentAIViewController = KMDocumentAIViewController(pdfView: self.listView) self.PDFContendView.addSubview(self.documentAIViewController?.view ?? KMDocumentAIViewController().view); self.documentAIViewController?.view.frame = self.PDFContendView.bounds self.documentAIViewController?.view.autoresizingMask = NSView.AutoresizingMask([.width,.height]) self.listView.isHidden = true //不影藏的话会出现鼠标事件的崩溃 } } else if type == .editPDF { self.listView.annotationType = .editTextImage } else if type == .Annatiton { self.rightSideViewController.subViewType = .AnnotationProperts } } func clickChildTool(type: KMToolbarType, index: Int) { if (type == .secure) { if (index == 1) { self.trackEvent_setPassword() } else if (index == 2) { self.trackEvent_removePassword() } } else { self.trackEvent(toolBarType: type) } Task { @MainActor in if (type == .compress) { /// 压缩 // #if VERSION_DMG // if await (KMLightMemberManager.manager.canUseAdvanced() == false) { // let _ = KMComparativeTableViewController.show(window: self.view.window!, .compress) // self.toolbarController.cancelSelected(KMToolbarToolCompressItemIdentifier) // return // } // #endif if await (KMLightMemberManager.manager.canPayFunction() == false) { // self.view.window?.contentView?.superview?.beginLoading() let document = self.listView.document let secureOptions = self.secureOptions let removeSecureFlag = self.removeSecureFlag // DispatchQueue.global().async { [unowned self] in guard let _url = KMTools.saveWatermarkDocumentToTemp(document: document!, secureOptions: secureOptions, removePWD: removeSecureFlag) else { // DispatchQueue.main.async { // self.view.window?.contentView?.superview?.endLoading() // } return } // DispatchQueue.main.async { // self.view.window?.contentView?.superview?.endLoading() self.showCompressWindow(url: _url) // } // } return } if (self.needSaveDocument()) { self.saveDocumentWithProgressAlert { [unowned self] params in self.showCompressWindow() } return } self.showCompressWindow() return } if ((KMToolbarType.word.rawValue ... KMToolbarType.conversion_image.rawValue).contains(type.rawValue)) { /// 转档 var identifier: String? if (type == .word) { /// Word identifier = KMToolbarConversionWordItemIdentifier } else if (type == .excel) { identifier = KMToolbarConversionExcelItemIdentifier } else if (type == .ppt) { identifier = KMToolbarConversionPPTItemIdentifier } else if (type == .rtf) { identifier = KMToolbarConversionRTFItemIdentifier } else if (type == .html) { identifier = KMToolbarConversionHTMLItemIdentifier } else if (type == .conversion_text) { identifier = KMToolbarConversionTextItemIdentifier } else if (type == .csv) { identifier = KMToolbarConversionCSVItemIdentifier } else if (type == .conversion_image) { identifier = KMToolbarConversionImageItemIdentifier } #if VERSION_DMG // if await (KMLightMemberManager.manager.canUseAdvanced() == false) { // if (identifier != nil) { // self.toolbarController.cancelSelected(identifier!) // } // let _ = KMComparativeTableViewController.show(window: self.view.window!, .convert) // return // } #endif if await (KMLightMemberManager.manager.canPayFunction() == false) { guard let _url = KMTools.saveWatermarkDocumentToTemp(document: self.listView.document, secureOptions: self.secureOptions, removePWD: self.removeSecureFlag) else { return } self.showConvertWindow(type: type, documentUrl: _url, identifier: identifier) return } if (self.needSaveDocument()) { self.saveDocumentWithProgressAlert { [unowned self] params in self.showConvertWindow(type: type, identifier: identifier) } return } self.showConvertWindow(type: type, identifier: identifier) return } if (type == .merge) { /// 合并 // #if VERSION_DMG // if await (KMLightMemberManager.manager.canUseAdvanced() == false) { // let _ = KMComparativeTableViewController.show(window: self.view.window!, .merge) // // self.toolbarController.cancelSelected(KMToolbarToolMergeItemIdentifier) // return // } // #endif if (self.listView.document.allowsCopying == false || self.listView.document.allowsPrinting == false) { if await (KMLightMemberManager.manager.canPayFunction() == false) { KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [unowned self] result , password in if (result == .cancel) { return } guard let _url = KMTools.saveWatermarkDocumentToTemp(document: self.listView.document, secureOptions: self.secureOptions, removePWD: self.removeSecureFlag) else { return } self.showMergeWindow(url: _url, password) } return } KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [unowned self] result , password in if (result == .cancel) { return } if (self.needSaveDocument()) { self.saveDocumentWithProgressAlert { [unowned self] params in self.showMergeWindow(password) } return } self.showMergeWindow(password) } return } if await (KMLightMemberManager.manager.canPayFunction() == false) { guard let _url = KMTools.saveWatermarkDocumentToTemp(document: self.listView.document, secureOptions: self.secureOptions, removePWD: self.removeSecureFlag) else { return } self.showMergeWindow(url: _url, password) return } if (self.needSaveDocument()) { self.saveDocumentWithProgressAlert { [unowned self] params in self.showMergeWindow(self.listView.document.password) } return } self.showMergeWindow(self.listView.document.password) return } if (type == .crop) { #if VERSION_DMG if await (KMLightMemberManager.manager.canUseAdvanced() == false) { let _ = KMComparativeTableViewController.show(window: self.view.window!, .crop) return } #endif self.recordSaveWatermarkFlag(type: .crop) if (index == 1) { self.cropCurrentPage() return } if (index == 2) { self.cropAllPage() return } //// 自定义裁剪区域 // self.cropCustomArea() } else if (type == .bates || type == .headerAndFooter || type == .background || type == .watermark) { if (index == 0) { var controller: KMWatermarkAdjectivePreViewBaseController! if (type == .bates) { controller = KMBatesPreviewController() } else if (type == .headerAndFooter) { controller = KMHeaderFooterPreviewController() } else if (type == .background) { controller = KMBackgroundController() } else if (type == .watermark) { controller = KMWatermarkViewController() } controller.applyDocument = self.listView.document controller.view.frame = self.view.bounds controller.view.autoresizingMask = [.width, .height] controller.documentURL = self.listView.document.documentURL self.view.addSubview(controller.view) self.addChild(controller) controller.itemClick = { [weak self] index, param in if (index == 0 || index == 1) { /// 取消 和 应用 var controller_watermarkAdjective_preView: KMWatermarkAdjectivePreViewBaseController? for i in 0 ..< self!.children.count { let vc: NSViewController = self!.children[self!.children.count-1-i] if (vc.isKind(of: KMWatermarkAdjectivePreViewBaseController.self) == true) { controller_watermarkAdjective_preView = vc as! KMWatermarkAdjectivePreViewBaseController break } } if (controller_watermarkAdjective_preView == nil) { return } controller_watermarkAdjective_preView!.view.removeFromSuperview() controller_watermarkAdjective_preView?.removeFromParent() // if (index == 1) { self?.listView.document = CPDFDocument(url: self?.listView.document.documentURL) self?.listView.layoutDocumentView() self?.listView.setNeedsDisplayForVisiblePages() // } return } } return } if (index == 1) { /// 取消 self.toolbarController.exitWatermarkAdjective() // self.rightSideViewController.view.isHidden = true self.rightSideViewController.isHidden = true self.rightSideViewController.subViewType = .None self.closeRightPane() return } if (index == 5) { /// 批量 return } if (index == 4) { //// 移除 if (type == .watermark) { let watermarks = self.listView.document.watermarks() if (watermarks == nil || watermarks!.count <= 0) { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("无法在本文件中找到可删除的水印。如果您看到水印,其不是使用PDF Master添加的,因此无法被检测到。", comment: "") alert.addButton(withTitle: NSLocalizedString("确认", comment: "")) alert.addButton(withTitle: NSLocalizedString("取消", comment: "")) alert.runModal() return } let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("确定要删除文件水印吗?", comment: "") alert.addButton(withTitle: NSLocalizedString("删除", comment: "")) alert.addButton(withTitle: NSLocalizedString("取消", comment: "")) let result = alert.runModal() if (result != .alertFirstButtonReturn) { return } } let oType: KMWatermarkAdjectiveType = KMWatermarkAdjectiveTools.KMWatermarkAdjectiveType(from: type) KMWatermarkAdjectiveTools.delete(oType, self.listView, self.listView.document.documentURL.path) { result in DispatchQueue.main.async { self.listView.layoutDocumentView() self.listView.setNeedsDisplayForVisiblePages() } if (result) { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = "成功" alert.runModal() } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "失败" alert.runModal() } } return } if (index == 2) { /// 应用 let model = self.rightSideViewController.model if (type == .bates || type == .headerAndFooter) { if (model == nil || (model?.isKind(of: KMBatesModel.self) == false)) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "没有找到模型" alert.runModal() return } if ((model as! KMBatesModel).hasVaild == false) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "没有找到内容" alert.runModal() return } } KMWatermarkAdjectiveTools.apply(model!, self.listView, self.listView.document.documentURL.path) { result in DispatchQueue.main.async { self.listView.layoutDocumentView() self.listView.setNeedsDisplayForVisiblePages() } if (result) { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = "成功" alert.runModal() } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "失败" alert.runModal() } } return } /// 新增 // self.rightSideViewController.view.isHidden = false self.rightSideViewController.isHidden = false self.rightSideViewController.subViewType = KMWatermarkAdjectiveTools.KMToolBarTypeToRightSubViewType(type) self.openRightPane() } else if (type == .redact) { /// 标记密文 if (index == 1) { /// 取消 if (self.hasAddRedact) { let alert = NSAlert() alert.messageText = NSLocalizedString("You can save a document with unapplied cipher text and edit it again. If you do not save, all changes will be lost.", comment: "") alert.addButton(withTitle: NSLocalizedString("Don’t Save", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result == .alertFirstButtonReturn) { self.listView.toolMode = .moveToolMode self.toolbarController.exitRedact() } return } self.listView.toolMode = .moveToolMode self.toolbarController.exitRedact() return } if (index == 2) { /// 擦除 self.exeRedactConfirm(.eraserAll) {} return } if (index == 3) { /// 应用 self.exeRedactConfirm(.redactAll) {} return } if (index == 4) { /// 文本&图像 self.listView.toolMode = .redactToolMode return } if (index == 5) { /// 页面 let windowController = KMRedactPageRangeWindowController(windowNibName: "KMRedactBaseWindowController") await self.view.window?.beginSheet(windowController.window!) self.currentWindowController = windowController windowController.itemClick = { [weak self] index, value in if (index == 1) { let topBarView = self?.toolbarController.fetchTopBarView() if (topBarView == nil || topBarView?.isKind(of: KMRedactTopToolBar.self) == false) { return } (topBarView as! KMRedactTopToolBar).selectItem(0) self?.view.window?.endSheet((self?.currentWindowController.window)!) self?.currentWindowController = nil return } let windowController_pageRange = self?.currentWindowController as! KMRedactPageRangeWindowController let pageType = windowController_pageRange.pageType let pageString = windowController_pageRange.pageString if (pageType == 5) { /// 自定义页面 let array = KMPageRangeTools.findSelectPage(pageRangeString: pageString, pageCount: Int((self?.listView.document.pageCount)!)) if (array.count == 0) { let alert = NSAlert() alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "") alert.runModal() return } } self!.view.window?.endSheet(self!.currentWindowController.window!) self!.currentWindowController = nil var indexs: IndexSet = [] if (pageType == 1) { /// 当前页面 indexs.insert((self?.listView.currentPageIndex)!) } else { indexs = KMRedactTools.getPageIndexs(pageType-1, string: pageString, Int((self?.listView.document.pageCount)!)) } if (indexs.count == 0) { return } for i in indexs { let page: CPDFPage = (self?.listView.document.page(at: UInt(i)))! let redactAnno = CPDFRedactAnnotation(PDFListViewNoteWith: (self?.listView.document)!) redactAnno.bounds = page.bounds self?.listView.add(redactAnno, to: page) } } return } } else if (type == .secure) { /// 安全 #if VERSION_DMG if await (KMLightMemberManager.manager.canUseAdvanced() == false) { let _ = KMComparativeTableViewController.show(window: self.view.window!, .secure) return } #endif if (index == 1) { /// 设置密码 if (!self.listView.document!.allowsCopying || !self.listView.document!.allowsPrinting) { KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [weak self] result, password in if (result == .cancel) { return } self?.isSaveKeyChain = false self?.listView.document.unlock(withPassword: password) self?.hiddenSecureLimitTip() self?.showSecureWindow((self?.listView.document.documentURL)!) } return } self.showSecureWindow(self.listView.document.documentURL) return } /// 删除安全性设置 if (!self.listView.document!.allowsCopying || !self.listView.document!.allowsPrinting) { KMPasswordInputWindow.openWindow(window: self.view.window!, type: .owner, url: self.listView.document.documentURL) { [weak self] result, password in if (result == .cancel) { return } self?.isSaveKeyChain = false self?.listView.document.unlock(withPassword: password) self?.hiddenSecureLimitTip() self?.recordRemoveSecureFlag() self?.recordSaveWatermarkFlag(type: .removePassword) let tip = KMRemovePasswordResultTipView() tip.result = .success tip.showInView(superView: (self?.listView.superview)!) } return } let alert = NSAlert() alert.messageText = NSLocalizedString("Are you sure you want to remove the security settings for the file?", comment: "") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let response = alert.runModal() if (response != .alertFirstButtonReturn) { return } self.recordRemoveSecureFlag() self.recordSaveWatermarkFlag(type: .removePassword) let tip = KMRemovePasswordResultTipView() tip.result = .success self.hiddenSecureLimitTip() tip.showInView(superView: self.listView.superview!) } } } } // MARK: - // MARK: - Mouse extension KMMainViewController { override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) KMPrint("KMMainViewController mouseDown") self.leftSideViewCancelSelect() self.pageNumberDisplayView.isEdit = false } } //MARK: LeftSideViewController extension KMMainViewController { func leftSideViewCancelSelect() { // switch self.leftSideViewController.type.methodType { // case .Thumbnail: //// self.leftSideViewController.thumbnailViewController.cancelSelect() // break // case .Outline: //// self.leftSideViewController.outlineViewController.cancelSelect() // break // case .BookMark: //// self.leftSideViewController.bookViewController.cancelSelect() // break // case .Search: //// self.leftSideViewController.searchViewController.cancelSelect() // break // case .Annotation: //// self.leftSideViewController.annotationViewController.cancelSelect() // break // default: if self.listView.isEditing() { if self.listView.editingAreas() != nil && self.listView.editingAreas().count != 0 { let areas = self.listView.editingAreas().first if areas is CPDFEditTextArea { self.listView.clearEditingSelectCharItem() self.listView.updateEditing([]) KMPrint("取消选中") } } } KMPrint("其他") // } } } extension KMMainViewController: KMReadModelViewDelegate { func firstPageButtonDidChange(view: KMReadModelView, sender: Any) { self.listView.goToFirstPage(nil) } func beforePageButtonDidChange(view: KMReadModelView, sender: Any) { self.listView.goToPreviousPage(nil) } func afterPageButtonDidChange(view: KMReadModelView, sender: Any) { self.listView.goToNextPage(nil) } func lastPageButtonDidChange(view: KMReadModelView, sender: Any) { self.listView.goToLastPage(nil) } func currentPageButtonDidChange(view: KMReadModelView, sender: Any, pageIndex: Int) { self.listView.go(toPageIndex: max(pageIndex - 1, 0), animated: true) } func scaleDidChange(view: KMReadModelView, sender: Any, type: KMReadModelViewScaleType) { var scale: Double = 1.0 switch type { case .fitWidth: self.listView.autoScales = !self.listView.autoScales scale = self.listView.scaleFactor break case .actualSize: if self.listView.scaleFactor != 1.0 { self.listView.scaleFactor = 1.0 self.listView.autoScales = false } scale = self.listView.scaleFactor break case .autoSize: self.listView.autoScales = true self.listView.autoScales = false scale = self.listView.scaleFactor break case ._10: scale = 0.1 break case ._25: scale = 0.25 break case ._50: scale = 0.5 break case ._100: scale = 1.0 break case ._150: scale = 1.5 break case ._200: scale = 2.0 break case ._400: scale = 4.0 break case ._800: scale = 8.0 break default: break } self.listView.scaleFactor = scale self.toolbarController.mainViewController?.childToolbarController.zoomTextField.stringValue = "\(Int(self.listView.scaleFactor*100))%" } func cancelReadModel(view: KMReadModelView, sender: Any) { if self.isReadMode { self.closeReadModel() } } func readModelViewWidthChange(view: KMReadModelView, width: CGFloat) { // if self.readModelViewWidthConstraint.constant != width { self.readModelViewWidthConstraint.constant = width // } } } extension KMMainViewController: KMPageNumberDisplayViewDelegate { func gotoPageIndex(view: KMPageNumberDisplayView, pageIndex: Int) { self.listView.go(toPageIndex: pageIndex, animated: true) } func updateWidth(view: KMPageNumberDisplayView, width: CGFloat) { if self.tipCurrentPageBoxWidthConstraint.constant != width { self.tipCurrentPageBoxWidthConstraint.constant = width } } func commitEditingIfNeed() { let isEdited = self.listView?.isEdited() ?? false if isEdited || self.isPDFTextImageEdited { self.listView.commitEditing() } } } // MARK: - Analytics (埋点) extension KMMainViewController { func trackEvent(toolType type: KMToolbarViewType) -> Void { if (type == .Annatiton) { KMAnalytics.trackEvent(eventName: "Btn_Tbr_Annotation", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .editPDF) { KMAnalytics.trackEvent(eventName: "Btn_Tbr_EditPDF", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .Page) { KMAnalytics.trackEvent(eventName: "Btn_Tbr_PageEdit", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .Conversion) { KMAnalytics.trackEvent(eventName: "Btn_Tbr_Converter", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .Tool) { KMAnalytics.trackEvent(eventName: "Btn_Tbr_Tools", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } } func trackEvent_aiTranslate() -> Void { KMAnalytics.trackEvent(eventName: "Btn_Tbr_AITranslate", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } func trackEvent_print() -> Void { KMAnalytics.trackEvent(eventName: "Btn_Tbr_Print", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } func trackEvent_share() -> Void { KMAnalytics.trackEvent(eventName: "Btn_Tbr_Share", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } func trackEvent_upgrade() -> Void { KMAnalytics.trackEvent(eventName: "Btn_Tbr_Upgrade", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.tbr, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.tbr_Btn], platform: .AppCenter, appTarget: .all) } func trackEvent(annotationType type: CAnnotationType) -> Void { if (type == .highlight) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Highlight", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .underline) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Underline", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .strikeOut) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Strikethrough", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .ink) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Draw", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .freeText) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Text", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .anchored) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Note", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .square) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Shape", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .link) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Link", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .stamp) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Stamp", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .signSignature) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Sign", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .addText) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_AddText", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_editPDF, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .addImage) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_AddImage", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_editPDF, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else { } } func trackEvent(toolMode mode: CToolMode) -> Void { if (mode == .selectToolMode) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_ContentSelection", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (mode == .moveToolMode) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Scroll", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_annotation, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } } func trackEvent(toolBarType type: KMToolbarType) -> Void { if (type == .word) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toWord", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .excel) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toExcel", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .ppt) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toPPT", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .rtf) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toRTF", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .csv) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toCSV", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .html) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toHTML", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .conversion_text) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toText", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .conversion_image) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_toImage", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Converter, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .compress) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Compress", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Tools, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .merge) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Merge", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Tools, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } else if (type == .secure) { } else if (type == .crop) { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_Crop", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Tools, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } } func trackEvent_setPassword() -> Void { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_SetPassword", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Tools, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } func trackEvent_removePassword() -> Void { KMAnalytics.trackEvent(eventName: "Btn_SubTbr_RemovePassword", parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.subTbr_Tools, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.subTbr_Btn], platform: .AppCenter, appTarget: .all) } }