// // KMMainViewController+Action.swift // PDF Reader Pro // // Created by wanjun on 2022/12/15. // import Foundation extension KMMainViewController { func search(searchString: String, isCase: Bool, display: Bool = true, needShowAll: Bool = false) { let isEditing = self.listView.isEditing() ?? false if isEditing { if searchString.isEmpty { self.listView.setHighlightedSelection(nil, animated: false) self.leftSideViewController.searchResults = [] if display { if self.leftSideViewController.findPaneState == .singular { self.leftSideViewController.displayFindViewAnimating(true) } else { self.leftSideViewController.displayGroupedFindViewAnimating(true) } } return } let isWholeWord = self.leftSideViewController.mwcFlags.wholeWordSearch == 1 var opt = CPDFSearchOptions() if isCase == false { opt.insert(.caseSensitive) } if isWholeWord { opt.insert(.matchWholeWord) } let datas = self.srHanddler.pdfView?.document.findEditAllPageString(searchString, with: opt) ?? [] if let sel = datas.first?.first { self.srHanddler.showSelection(sel) } self.searchResults.removeAll() var _selections: [CPDFSelection] = [] for selections in datas { 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) _selections.append(selection) selection.setColor(NSColor(red: 236/255.0, green: 241/255.0, blue: 83/255.0, alpha: 0.5)) } } if needShowAll { self.listView.setHighlightedSelections(_selections) } if _selections.isEmpty { self.listView.setHighlightedSelection(nil, animated: false) } self.listView.setNeedsDisplayAnnotationViewForVisiblePages() self.leftSideViewController.searchResults = self.searchResults if display { if self.leftSideViewController.findPaneState == .singular { self.leftSideViewController.displayFindViewAnimating(true) } else { self.leftSideViewController.displayGroupedFindViewAnimating(true) } } return } let document = self.listView.document if let data = document?.isFinding, data { document?.cancelFindString() } if searchString == "" { self.searchResults = [] self.leftSideViewController.searchResults = self.searchResults self.listView.setHighlightedSelections([]) self.listView.setHighlightedSelection(nil, animated: false) self.listView.setNeedsDisplayAnnotationViewForVisiblePages() } else { mwcFlags.wholeWordSearch = isCase == true ? 1 : 0 var findArray : [[CPDFSelection]] if isCase { if self.leftSideViewController.mwcFlags.wholeWordSearch == 1 { findArray = self.listView.document.findString(searchString, with: .matchWholeWord) ?? [] } else { findArray = self.listView.document.findString(searchString) ?? [] } } else { if self.leftSideViewController.mwcFlags.wholeWordSearch == 1 { findArray = self.listView.document.findString(searchString, with: [.caseSensitive, .matchWholeWord]) ?? [] } else { findArray = self.listView.document.findString(searchString, with: .caseSensitive) ?? [] } } self.searchResults.removeAll() var _selections: [CPDFSelection] = [] 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) _selections.append(selection) selection.setColor(NSColor(red: 236/255.0, green: 241/255.0, blue: 83/255.0, alpha: 0.5)) } } if needShowAll { self.listView.setHighlightedSelections(_selections) } if _selections.isEmpty { self.listView.setHighlightedSelection(nil, animated: false) } self.listView.setNeedsDisplayAnnotationViewForVisiblePages() self.leftSideViewController.searchResults = self.searchResults } if display { if self.leftSideViewController.findPaneState == .singular { self.leftSideViewController.displayFindViewAnimating(true) } else { self.leftSideViewController.displayGroupedFindViewAnimating(true) } } } func removeSignatures(signatures:[CPDFSignature]) { for signature in signatures { self.listView.document.removeSignature(signature) } for i in 0.. 0 { mSignatures.append(sign) } } } //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 , 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 { let 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 { let addTextItem = NSMenuItem(title: NSLocalizedString("Add Text", comment: ""), action: #selector(addImageText), target: self, tag: 0) return addTextItem } func addImage() -> NSMenuItem { let 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) let menu = NSMenu() let item1 = menu.insertItem(withTitle: NSLocalizedString("PNG", comment: ""), action:#selector(exportStampImage), target: self, tag:0, at: 0) let item2 = menu.insertItem(withTitle: NSLocalizedString("JPG", comment: ""), action:#selector(menuItemEditingClick_ExportImage), target: self, tag:1, at: 1) let item3 = menu.insertItem(withTitle: NSLocalizedString("PDF", comment: ""), action:#selector(exportStampImage), target: self, tag:2, at: 2) exportItem.submenu = menu return exportItem } func exportImageStampItem()->NSMenuItem { let exportItem = NSMenuItem(title: NSLocalizedString("Export", comment: ""), action: #selector(menuItemEditingClick_ExportImage), target: self) let menu = NSMenu() let item1 = menu.insertItem(withTitle: NSLocalizedString("PNG", comment: ""), action:#selector(exportStampImage), target: self, tag:0, at: 0) let item2 = 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() 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("Annotate", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() if listView.currentSelection != nil && listView.currentSelection.selectionType() == .text { _ = stypeMenu.addItem(withTitle: NSLocalizedString("Highlight", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 0) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Underline", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 1) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Strikethrough", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 2) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Squiggly", comment: ""), action: #selector(menuItemAnnotationClick_add), target: self, tag: 2) stypeMenu.addItem(NSMenuItem.separator()) } _ = stypeMenu.addItem(withTitle: NSLocalizedString("Text Note", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 1) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Anchored Note", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 2) stypeMenu.addItem(NSMenuItem.separator()) _ = 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 viewManager.isPDFReadMode { } else { stypeMenu.addItem(NSMenuItem.separator()) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Stamp", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 8) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Image", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 10) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Signature", comment: ""), action: #selector(menuItemAnnotationClick_addStype), target: self, tag: 9) } stypItem.submenu = stypeMenu if self.listView.annotationType == .ink { stypeMenu.item(withTitle: NSLocalizedString("Freehand", comment: ""))?.state = .on } else if self.listView.annotationType == .freeText { stypeMenu.item(withTitle: NSLocalizedString("Text Note", comment: ""))?.state = .on } else if self.listView.annotationType == .anchored { stypeMenu.item(withTitle: NSLocalizedString("Anchored Note", comment: ""))?.state = .on } else if self.listView.annotationType == .square { stypeMenu.item(withTitle: NSLocalizedString("Rectangle", comment: ""))?.state = .on } else if self.listView.annotationType == .circle { stypeMenu.item(withTitle: NSLocalizedString("Circle", comment: ""))?.state = .on } else if self.listView.annotationType == .arrow { stypeMenu.item(withTitle: NSLocalizedString("Arrow", comment: ""))?.state = .on } else if self.listView.annotationType == .line { stypeMenu.item(withTitle: NSLocalizedString("Line", comment: ""))?.state = .on } else if self.listView.annotationType == .link { stypeMenu.item(at: 7)?.state = .on } else if self.listView.annotationType == .stamp { stypeMenu.item(withTitle: NSLocalizedString("Stamp", comment: ""))?.state = .on } else if self.listView.annotationType == .signSignature { stypeMenu.item(withTitle: NSLocalizedString("Signature", comment: ""))?.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("Text", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: CToolMode.textToolMode.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Scroll", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: CToolMode.moveToolMode.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Magnify", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: CToolMode.magnifyToolMode.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Select", comment: ""), action: #selector(menuItemAnnotationClick_toolModel), target: self, tag: CToolMode.selectToolMode.rawValue) stypeMenu.insertItem(NSMenuItem.separator(), at: 4) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Highlight", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.highlight.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Underline", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.underline.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Strikethrough", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.strikeOut.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Squiggly", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.squiggly.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Freehand", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.ink.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Text Note", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.freeText.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Anchored Note", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.anchored.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Rectangle", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.square.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Circle", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.circle.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Arrow", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.arrow.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Line", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.line.rawValue) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Link", comment: ""), action: #selector(changeAnnotationMode_itemAction), target: self, tag: CAnnotationType.link.rawValue) stypItem.submenu = stypeMenu return stypItem } func addReadModelStype() -> NSMenuItem { var stypItem = NSMenuItem(title: NSLocalizedString("Read Mode On", comment: ""), action: #selector(openPDFReadMode), target: self) if viewManager.isPDFReadMode { stypItem = NSMenuItem(title: NSLocalizedString("Read Mode Off", comment: ""), action: #selector(exitPDFReadMode), target: self) } return stypItem } func addOutlineStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Add Outline Item", comment: ""), action: #selector(addOutLineItemAction), target: self) return stypItem } func setTTSStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("TTS", comment: ""), action: #selector(showTTSView), target: self) return stypItem } func setShareStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Share", comment: ""), action: nil, target: self) var string = "" if listView.activeAnnotation != nil { string = self.listView.activeAnnotation?.contents ?? "" } if string.count < 1{ string = self.listView.currentSelection?.string() ?? "" } stypItem.submenu = NSSharingServicePicker.menu(forSharingItems: [string], subjectContext: "", withTarget: self, selector: #selector(shareFromService), serviceDelegate: nil) return stypItem } func numberOfChars(_ str: String) -> (num: Int, indexN: Int) { var number = 0 var indexN = 0 guard str.count > 0 else {return (0, 0)} for i in 0...str.count - 1 { let c: unichar = (str as NSString).character(at: i) if (c >= 0x4E00) { number += 2 }else { number += 1 } if number > 56{ indexN = i number = 100 break } } return (number, indexN) } func setLookUpStype() -> NSMenuItem { guard let str = listView.currentSelection?.string() else { return NSMenuItem.separator() }//String(format: "Look Up %@", listView.currentSelection?.string() ?? "") let dic = numberOfChars(str) var newStr = str if dic.num == 100{ newStr = str.prefix(dic.indexN) + "..." } newStr = NSLocalizedString("Look Up ", comment: "") + "\"" + newStr + "\"" let stypItem = NSMenuItem(title: newStr, action: #selector(lookUpAction), target: self) return stypItem } func setSearchBaiduStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Search with Baidu", comment: ""), action: #selector(searchBaiduAction), target: self) return stypItem } func setCutStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Cut", comment: ""), action: #selector(cutAction), target: self) return stypItem } func setDeleteStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Delete", comment: ""), action: #selector(deleteAction), target: self) return stypItem } func setColorsStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Colors", comment: ""), action: #selector(ColorsItemAction), target: self) return stypItem } func setLinesStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Lines", comment: ""), action: #selector(LinesItemAction), target: self) return stypItem } func setEditNoteStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Edit Note", comment: ""), action: #selector(EditNoteItemAction), target: self) return stypItem } func setRotateStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Rotate", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() let item1 = stypeMenu.addItem(withTitle: NSLocalizedString("Rotate Left", comment: ""), action: #selector(rotateLeftAction), target: self, tag: 0) let item2 = stypeMenu.addItem(withTitle: NSLocalizedString("Rotate Right", comment: ""), action: #selector(rotateRightAction), target: self, tag: 1) stypItem.submenu = stypeMenu return stypItem } func setNextPageStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Next Page", comment: ""), action: #selector(NextPageAction), target: self) stypItem.isEnabled = false if listView.canGoToNextPage() { stypItem.isEnabled = true } return stypItem } func setPreviousPageStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Previous Page", comment: ""), action: #selector(PreviousPageAction), target: self) stypItem.isEnabled = false if listView.canGoToPreviousPage() { stypItem.isEnabled = true } return stypItem } func setTranslateStype() -> NSMenuItem { let str = listView.currentSelection?.string() ?? ""//String(format: "Translate %@", listView.currentSelection?.string() ?? "") let dic = numberOfChars(str) var newStr = str if dic.num == 100{ newStr = str.prefix(dic.indexN) + "..." } newStr = NSLocalizedString("Translate", comment: "") + " \"" + newStr + "\"" let stypItem = NSMenuItem(title: newStr, action: #selector(TranslateItemAction), target: self) return stypItem } func setAutoScrollStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Auto Scroll", comment: ""), action: #selector(AutoScrollItemAction), target: self) stypItem.state = self.listView.isAutoFlow() ? .on : .off return stypItem } func setSnapshotStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Snapshot", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() let item1 = stypeMenu.addItem(withTitle: NSLocalizedString("Auto", comment: ""), action: #selector(takeSnapshot), target: self, tag: 0) let item2 = stypeMenu.addItem(withTitle: NSLocalizedString("Select Area", comment: ""), action: #selector(takeSnapshotSelectContent), target: self, tag: 1) stypItem.submenu = stypeMenu return stypItem } func setServicesStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Services", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() let item1 = stypeMenu.addItem(withTitle: NSLocalizedString("Add to Music as a Spoken Track", comment: ""), action: #selector(AddtoMusicasASpokenTrack), target: self, tag: 0) let item2 = stypeMenu.addItem(withTitle: NSLocalizedString("Convert Text to Simplified Chinese", comment: ""), action: #selector(ConvertTextToSimplifiedChinese), target: self, tag: 1) let item3 = stypeMenu.addItem(withTitle: NSLocalizedString("Convert Text to Traditional Chinese", comment: ""), action: #selector(ConvertTextToTraditionalChinese), target: self, tag: 2) let item4 = stypeMenu.addItem(withTitle: NSLocalizedString("Open", comment: ""), action: #selector(OpenItemAction), target: self, tag: 3) let item5 = stypeMenu.addItem(withTitle: NSLocalizedString("Search With Baidu", comment: ""), action: #selector(searchBaiduAction), target: self, tag: 4) let item6 = stypeMenu.addItem(withTitle: NSLocalizedString("Show in Finder", comment: ""), action: #selector(showInFinder), target: self, tag: 4) let item7 = stypeMenu.addItem(withTitle: NSLocalizedString("Show Info in Finder", comment: ""), action: #selector(showInfoInFinder), target: self, tag: 5) stypItem.submenu = stypeMenu return stypItem } func setCropStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("Crop", comment: ""), action: nil, target: self) let stypeMenu = NSMenu() if NSIsEmptyRect(listView.selectionRect){ _ = stypeMenu.addItem(withTitle: NSLocalizedString("Select Area", comment: ""), action: #selector(selectToolModel), target: self, tag: 4) _ = stypeMenu.addItem(withTitle: NSLocalizedString("Crop Options...", comment: ""), action: #selector(customCropModel), target: self, tag: 5) } stypItem.submenu = stypeMenu return stypItem } func setAITranslateStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("AI Translate", comment: ""), action: #selector(AITranslateItemAction), target: self) stypItem.state = self.listView.isAutoFlow() ? .on : .off return stypItem } func setAIProofreadStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("AI Proofread", comment: ""), action: #selector(AIProofreadItemAction), target: self) stypItem.state = self.listView.isAutoFlow() ? .on : .off return stypItem } func setAIRewriteStype() -> NSMenuItem { let stypItem = NSMenuItem(title: NSLocalizedString("AI Rewrite", comment: ""), action: #selector(AIRewriteItemAction), target: self) stypItem.state = self.listView.isAutoFlow() ? .on : .off return stypItem } func addHighlightLinksStype() -> NSMenuItem { let highlightLink = KMPreferenceManager.shared.highlightLinks var highlightLinkTitle = NSLocalizedString("Highlight Links", comment: "") if highlightLink { highlightLinkTitle = NSLocalizedString("Disable Highlight Links", comment: "") } let highlightLinksItem = NSMenuItem(title: highlightLinkTitle, action: #selector(highlightLinks), target: self) return highlightLinksItem } func addAnnotationForStyleMenu(_ item: NSMenuItem?) { if item == nil { return } let menu = NSMenu() item?.submenu = menu 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 wavyLine = NSMenuItem(title: NSLocalizedString("Squiggly", 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) 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(wavyLine, at: menu.items.count) menu.insertItem(NSMenuItem.separator(), at: menu.items.count) } if viewManager.isPDFReadMode { } 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 viewManager.isPDFReadMode { } 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 viewManager.isPDFReadMode { } 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 viewManager.isPDFReadMode { } else { menu.insertItem(link, at: menu.items.count) } if viewManager.isPDFReadMode { } else { if listView.currentSelection.selectionType() != .image { menu.insertItem(outline, at: menu.items.count) } } menu.insertItem(NSMenuItem.separator(), at: menu.items.count) if viewManager.isPDFReadMode { } else { if (listView.currentSelection.selectionType() != .image) { } } 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"] } func handleRightMouseDown(theEvent: NSEvent) -> Bool { if interactionMode == .presentation { listView.goToPreviousPage(nil) return true } return false } func useNativeFullScreen() -> Bool { var isFull = false let sel = NSSelectorFromString("toggleFullscreen:") if NSWindow.instancesRespond(to: sel) && UserDefaults.standard.bool(forKey: "SKUseLegacyFullScreenKey"){ isFull = true } return isFull } func forceSubwindowsOnTop(_ flag: Bool) { } //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("添加文字") } else if sender.tag == 1 { } else if sender.tag == 2 { KMPrint("粘贴") } } @objc func menuItemEditingClick_CropImage(sender: NSMenuItem) { 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) { self.listView.exitCrop(with: self.listView.selectImageAreas) self.listView.cropAreas = nil self.listView.isEditImage = false } @objc func menuItemEditingClick_RestoreCrop(sender: NSMenuItem) { self.listView.resetCrop(with: self.listView.selectImageAreas) } @objc func menuItemEditingClick_CutImage(sender: NSMenuItem) { } @objc func menuItemEditingClick_ReplaceImage(sender: NSMenuItem) { if self.listView.selectImageAreas == nil { return } FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageEdit", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageEdit_Replace"]) 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 = "\(NSLocalizedString("Untitled", comment: "")).jpg" 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!]) } } } @objc func AddtoMusicasASpokenTrack(sender: NSMenuItem) { } @objc func ConvertTextToSimplifiedChinese(sender: NSMenuItem) { } @objc func ConvertTextToTraditionalChinese(sender: NSMenuItem) { } @objc func OpenItemAction(sender: NSMenuItem) { } @objc func customCropModel(sender: NSMenuItem) { } @objc func rotateRightAction(sender: NSMenuItem) { } @objc func rotateLeftAction(sender: NSMenuItem) { } @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 } } @objc func changeAnnotationMode_itemAction(sender : NSMenuItem) { var itemId: String? if sender.tag == CAnnotationType.highlight.rawValue { itemId = KMToolbarHighlightAnnotationItemIdentifier } else if sender.tag == CAnnotationType.underline.rawValue { itemId = KMToolbarUnderlineAnnotationItemIdentifier } else if sender.tag == CAnnotationType.strikeOut.rawValue { itemId = KMToolbarStrikeOutAnnotationItemIdentifier } else if sender.tag == CAnnotationType.squiggly.rawValue { itemId = KMToolbarSquigglyAnnotationItemIdentifier } else if sender.tag == CAnnotationType.ink.rawValue { itemId = KMToolbarInkAnnotationItemIdentifier } else if sender.tag == CAnnotationType.freeText.rawValue { itemId = KMToolbarFreeTextAnnotationItemIdentifier } else if sender.tag == CAnnotationType.anchored.rawValue { itemId = KMToolbarAnchoredAnnotationItemIdentifier } else if sender.tag == CAnnotationType.square.rawValue { itemId = KMToolbarSquareAnnotationItemIdentifier } else if sender.tag == CAnnotationType.circle.rawValue { itemId = KMToolbarCircleAnnotationItemIdentifier } else if sender.tag == CAnnotationType.arrow.rawValue { itemId = KMToolbarArrowAnnotationItemIdentifier } else if sender.tag == CAnnotationType.line.rawValue { itemId = KMToolbarLineAnnotationItemIdentifier } else if sender.tag == CAnnotationType.link.rawValue { itemId = KMToolbarLinkAnnotationItemIdentifier } } @objc func menuItemAnnotationClick_add(sender : NSMenuItem) { var annotationType : CAnnotationType = .unkown switch sender.tag { case 0: annotationType = .highlight case 1: annotationType = .underline case 2: if sender.title == NSLocalizedString("Squiggly", comment: "") { annotationType = .squiggly } else { 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: if self.model.leftPanelOpen == false || self.leftSideViewController.type.methodType != .Outline { self.leftSideViewController.refreshMethodType(methodType: .Outline) } 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 DispatchQueue.main.async { Task { @MainActor in 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 menuItemAnnotationClick_addStype(sender: NSMenuItem) { Task { @MainActor in let idx = sender.tag if idx == 10 { if IAPProductsManager.default().isAvailableAllFunction() == false { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) return } } 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) var pagePoint = self.listView.convert(currentPoint, to: currentPage) var annotation: CPDFAnnotation? if viewManager.isPDFReadMode { 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: 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: 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: 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: 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: 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: 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 toggleOpenRightSide() case 8: self.listView.annotationType = CAnnotationType.stamp toggleOpenRightSide() case 9: self.listView.annotationType = CAnnotationType.signSignature toggleOpenRightSide() default: break } } else { if (sender.tag == 7 || sender.tag == 8 || sender.tag == 9) { // Ink & Link & stamp & sign self.listView.toolMode = .noteToolMode } switch sender.tag { case 0: self.listView.toolMode = .noteToolMode self.listView.annotationType = CAnnotationType.ink case 1: let defaultSize = self.listView.defaultSize(with: .freeText, in: currentPage) if (pagePoint.x - defaultSize.width > 0){ pagePoint.x -= defaultSize.width; }else{ pagePoint.x = 0; } let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .freeText, selection: nil, page: currentPage, bounds: bounds) if ((annotation) != nil) { self.listView.edit(annotation) } case 2: 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: let defaultSize = self.listView.defaultSize(with: .square, in: currentPage) if (pagePoint.x - defaultSize.width > 0){ pagePoint.x -= defaultSize.width; }else{ pagePoint.x = 0; } let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize) annotation = self.listView.addAnnotation(with: .square, selection: nil, page: currentPage, bounds: bounds) case 4: 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: 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: 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 toggleOpenRightSide() case 8: self.listView.annotationType = CAnnotationType.stamp toggleOpenRightSide() case 9: self.listView.annotationType = CAnnotationType.signSignature toggleOpenRightSide() case 10: self.addImgAnnotationToView(center: pagePoint) default: break } if annotation != nil{ self.listView.activeAnnotations.removeAllObjects() var newAnnonations : [CPDFAnnotation] = [] newAnnonations.append(annotation!) self.listView.updateActiveAnnotations(newAnnonations) } } } } func addImgAnnotationToView(center: NSPoint) { let accessoryCtr = KMImageAccessoryController() let openPanel = NSOpenPanel() openPanel.allowedFileTypes = KMImageAccessoryController.supportedImageTypes() openPanel.allowsMultipleSelection = false openPanel.accessoryView = accessoryCtr.view openPanel.isAccessoryViewDisclosed = true openPanel.beginSheetModal(for: self.view.window!) { result in if result == .OK { let fileURL = openPanel.urls.first let filePath = fileURL!.path if filePath.pathExtension == "pdf" { let pdf = CPDFDocument(url: fileURL) if pdf!.isEncrypted { NSSound.beep() return } } let img = NSImage(contentsOfFile: filePath) let isRemoveBGColor = accessoryCtr.selectedButton.state == .on self.listView.addImageAnnotation(img, center: center, isRemoveBGColor: isRemoveBGColor) } } } @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() } self.setDocumentEditedState(window: self.view.window) if viewManager.isPDFReadMode { } else { self.leftSideViewController.showBookmarkTab() } } @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) // 执行右键操作后,需要取消框选区域 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?.model.isSaveKeyChain = false self?.listView.document.unlock(withPassword: password) // 隐藏提示 self?.hiddenSecureLimitTip() // 去打印 KMPrintWindowController.printImage(image: image) } return } KMPrintWindowController.printImage(image: image) } // MARK: - Measure @objc func menuItemActionMeasureProperty(sender: NSMenuItem) { guard let anno = sender.representedObject as? CPDFAnnotation else { return } if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.hideFloatingWindow() } else if perimeterMeasureInfoWindowController?.window?.isVisible == true { perimeterMeasureInfoWindowController?.hideFloatingWindow() } else if areaMeasureInfoWindowController?.window?.isVisible == true { areaMeasureInfoWindowController?.hideFloatingWindow() } self.listView.updateActiveAnnotations([anno]) self.pdfListViewChangeatioActiveAnnotations(self.listView, forActiveAnnotations: [anno], isRightMenu: false) self.listView.setNeedsDisplayForVisiblePages() } @objc func menuItemActionMeasureEditNote(sender: NSMenuItem) { guard let anno = sender.representedObject as? CPDFAnnotation else { return } self.listView.edit(anno) } @objc func menuItemActionMeasureSetting(sender: NSMenuItem) { guard let anno = sender.representedObject as? CPDFAnnotation else { return } self.listView.updateActiveAnnotations([anno]) self.listView.setNeedsDisplayForVisiblePages() if let data = anno as? CPDFLineAnnotation, data.isMeasure { self.showMeasureDistanceSettingWindow(measureInfo: data.measureInfo) } else if let data = anno as? CPDFPolylineAnnotation { self.showMeasurePerimeterSettingWindow(measureInfo: data.measureInfo) } else if let data = anno as? CPDFPolygonAnnotation { self.showMeasureAreaSettingWindow(measureInfo: data.measureInfo) } } @objc func menuItemActionMeasureDelete(sender: NSMenuItem) { guard let anno = sender.representedObject as? CPDFAnnotation else { return } self.listView.remove(anno) } func showMeasureDistanceSettingWindow(measureInfo: CPDFDistanceMeasureInfo?, hideInfoWindow: Bool = true) { guard let mInfo = measureInfo else { return } let winC = CDistanceSettingWindowController(distanceMeasureInfo: mInfo) if hideInfoWindow { self.distanceMeasureInfoWindowController?.hideFloatingWindow() } winC.delegate = self winC.startModal("") } func showMeasurePerimeterSettingWindow(measureInfo: CPDFPerimeterMeasureInfo?, hideInfoWindow: Bool = true) { guard let mInfo = measureInfo else { return } let winC = CDistanceSettingWindowController(perimeterMeasureInfo: mInfo) if hideInfoWindow { self.perimeterMeasureInfoWindowController?.hideFloatingWindow() } winC.delegate = self winC.startModal("") } func showMeasureAreaSettingWindow(measureInfo: CPDFAreaMeasureInfo?, hideInfoWindow: Bool = true) { guard let mInfo = measureInfo else { return } let winC = CAreaSettingWindowController(measureInfo: mInfo) if hideInfoWindow { self.areaMeasureInfoWindowController?.hideFloatingWindow() } winC.delegate = self winC.startModal("") } func splitView(withTag tag: Int) { if tag == 0 { self.listView.viewSplitMode = KMPDFViewSplitMode.horizontal self.singlePageScreen(isSinglePage: false, doublePagesScreen: false) } else if tag == 1 { self.listView.viewSplitMode = KMPDFViewSplitMode.vertical self.singlePageScreen(isSinglePage: false, doublePagesScreen: true) } else if tag == 2 { self.listView.viewSplitMode = KMPDFViewSplitMode.disable self.singlePageScreen(isSinglePage: true, doublePagesScreen: false) } self.listView.needsDisplay = true } // MARK: - 幻灯片 func fadeInFullScreenWindow(with backgroundColor: NSColor, level: Int) { let view: NSView = self.view.window!.firstResponder as! NSView if view.isDescendant(of: pdfSplitView){ self.view.window?.makeFirstResponder(nil) } self.mainWindow = self.view.window let fullScreenWindow = KMFullScreenWindow(screen: (self.mainWindow?.screen ?? NSScreen.main)!, bgColor: backgroundColor, level: NSWindow.Level.popUpMenu.rawValue, isMain: true) fullScreenWindow.interactionParent = self.view.window self.mainWindow?.delegate = nil fullScreenWindow.fadeInBlocking() self.browserWindowController?.window = fullScreenWindow fullScreenWindow.makeKey() let sel = NSSelectorFromString("setAnimationBehavior:") if self.mainWindow?.responds(to: sel) ?? false{ self.mainWindow?.animationBehavior = .none } self.mainWindow?.orderOut(nil) if self.mainWindow?.responds(to: sel) ?? false{ self.mainWindow?.animationBehavior = .default } fullScreenWindow.level = NSWindow.Level(rawValue: level) fullScreenWindow.orderFront(nil) } func fadeInFullScreenView(_ view: NSView, inset: CGFloat) { guard let fullScreenWindow = self.browserWindowController?.window as? KMFullScreenWindow else { return } let fadeWindow = KMFullScreenWindow(screen: fullScreenWindow.screen!, bgColor: fullScreenWindow.backgroundColor, level: fullScreenWindow.level.rawValue, isMain: false) fadeWindow.order(.above, relativeTo: fullScreenWindow.windowNumber) view.frame = NSInsetRect(fullScreenWindow.contentView?.bounds ?? .zero, inset, 0) fullScreenWindow.contentView?.addSubview(view) self.listView.layoutDocumentView() self.listView.requiresDisplay() fullScreenWindow.makeFirstResponder(self.listView) fullScreenWindow.recalculateKeyViewLoop() fullScreenWindow.delegate = self.browserWindowController fullScreenWindow.display() fadeWindow.fadeOut() } // 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 ?? 0) 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) ?? 0)) 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) ?? 0)) 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)) || (self.listView.selectImageAreas != nil) { 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 } else { image = self.listView.selectImageAreas.thumbnailImage(with: CGSize(width: 1920, height: 1920)) ?? NSImage() } 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?.km_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 guard let data = data else { return } 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) } } 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 toggleLeftPane() -> Void { self.model.leftPanelOpen = true applyLeftSideWidth(self.model.panelWidth+functionWidth, rightSideWidth: self.model.lastRightPanWidth) } // 开启左边栏 @objc func openLeftPane() -> Void { self.model.leftPanelOpen = true applyLeftSideWidth(self.model.panelWidth+functionWidth, rightSideWidth: self.model.lastRightPanWidth) } // 关闭左边栏 @objc func closeLeftPane() -> Void { self.model.leftPanelOpen = false applyLeftSideWidth(functionWidth, rightSideWidth: self.model.lastRightPanWidth) } // 开启/关闭右边栏 @objc func toggleRightPane() -> Void { } 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.deletingPathExtension().lastPathComponent { if let doc = self.myDocument, doc.isDocumentEdited { Task { let resp = await KMAlertTool.runModel(message: NSLocalizedString("File Updated", comment: ""), buttons: [NSLocalizedString("Save", comment: ""), NSLocalizedString("Cancel", comment: "")]) if resp != .alertFirstButtonReturn { // 取消 return } doc.updateChangeCount(.changeCleared) self.document?.write(to: doc.fileURL) Task { @MainActor in self._renameForSavePanel(tabController) } } return } self._renameForSavePanel(tabController) } } func savePdfAlertView() { if AutoSaveManager.manager.isSaving || AutoSaveManager.manager.isSaveNoti{ return } AutoSaveManager.manager.isSaveNoti = true var num = 0 if self.listView.document != nil{ num = Int(self.listView.document.pageCount) } if Thread.current.isMainThread { self.beginProgressSheet(withMessage: NSLocalizedString("Saving PDF", comment: "") + "...", maxValue: UInt(num)) } else { DispatchQueue.main.async { self.beginProgressSheet(withMessage: NSLocalizedString("Saving PDF", comment: "") + "...", maxValue: UInt(num)) } } } func savePdfFinishAlertView() { if !AutoSaveManager.manager.isSaveNoti{ return } AutoSaveManager.manager.isSaveNoti = false if Thread.current.isMainThread { self.dismissProgressSheet() } else { DispatchQueue.main.async { self.dismissProgressSheet() } } } private func _renameForSavePanel(_ tabC: CTTabController?) { let outputSavePanel = NSSavePanel() outputSavePanel.title = NSLocalizedString("Rename", comment: "") outputSavePanel.allowedFileTypes = ["pdf"] outputSavePanel.nameFieldStringValue = (self.document?.documentURL.lastPathComponent)! outputSavePanel.directoryURL = self.document?.documentURL.deletingLastPathComponent() let resp = outputSavePanel.runModal() if resp == .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) { tabC?.title = outputSavePanel.url!.lastPathComponent if let newPdfDocument = CPDFDocument(url: newFileURL) { self.model.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 let path = self.document?.documentURL.deletingPathExtension().lastPathComponent if tabController?.title == path { if let file = self.myDocument?.fileURL { if FileManager.default.fileExists(atPath: file.path) { NSWorkspace.shared.activateFileViewerSelecting([file]) } } } } else { guard let url = self.myDocument?.fileURL else { return } let file: URL = url if FileManager.default.fileExists(atPath: file.path) { NSWorkspace.shared.activateFileViewerSelecting([file]) } } } func showOrHideNotes() { self.listView.hideNotes = !self.listView.hideNotes for note in self.listView.notes as? [CPDFAnnotation] ?? [] { if note.isForm() { note.setAnnotationShouldDisplay(true) note.setHidden(false) } } self.listView.setNeedsDisplayAnnotationViewForVisiblePages() self.leftSideViewController.note_reloadDataIfNeed() } func closeTab(_ sender: NSNotification) -> Void { } @IBAction func toggleSplitPDF(_ sender: Any) { if let menuItem = sender as? NSMenuItem { splitView(withTag: menuItem.tag) } } func changeLineAttribute(_ sender: Any?) { var inspector = sender as? KMLineInspector if inspector == nil { inspector = KMLineInspector.shared } let action = inspector?.currentLineChangeAction ?? .no for annotation in self.listView.activeAnnotations { guard let anno = annotation as? CPDFAnnotation else { continue } if anno.hasBorder() { switch (action) { case .lineWidth: anno.setLineWidth(inspector?.lineWidth ?? 0) break case .style: anno.setBorderStyle(CPDFBorderStyle(rawValue: inspector?.style ?? 0) ?? .solid) break case .dashPattern: anno.setDashPattern(inspector?.dashPattern ?? []) break case .startLineStyle: if anno.isLine() { (anno as? CPDFLineAnnotation)?.startLineStyle = CPDFLineStyle(rawValue: inspector?.startLineStyle ?? 0) ?? .none } break case .endLineStyle: if anno.isLine() { (anno as? CPDFLineAnnotation)?.endLineStyle = CPDFLineStyle(rawValue: inspector?.endLineStyle ?? 0) ?? .none } break case .no: break } } } } // MARK: - // MARK: 显示窗口 internal func showCompressWindow(url: URL? = nil) { self.compressWIndowControllerNew = KMCompressWIndowControllerNew(windowNibName: "KMCompressWIndowControllerNew") self.view.window?.beginSheet(self.compressWIndowControllerNew!.window!) self.compressWIndowControllerNew?.password = self.listView.document?.password ?? "" self.compressWIndowControllerNew?.documentURL = self.listView.document.documentURL self.compressWIndowControllerNew?.itemClick = { [unowned self] in self.view.window?.endSheet((self.compressWIndowControllerNew?.window)!) } self.compressWIndowControllerNew?.batchAction = { [unowned self] view, filePaths in self.view.window?.endSheet((self.compressWIndowControllerNew?.window)!) let batchWindowController = KMBatchOperateWindowController.sharedWindowController let batchOperateFile = KMBatchOperateFile(filePath: filePaths.first!.path, type: .Compress) batchWindowController.switchToOperateType(KMBatchOperationType.Compress, files: [batchOperateFile]) batchWindowController.window?.makeKeyAndOrderFront("") } self.compressWIndowControllerNew?.resultCallback = { [unowned self] result, openDocument, fileURL, error in self.view.window?.endSheet((self.compressWIndowControllerNew?.window)!) if (result) { 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 convertT: KMConvertType = .Word var windowController: KMConvertBaseWindowController? if (type == .word) { /// Word convertT = .Word windowController = KMConvertWordWindowController() } else if (type == .excel) { convertT = .Excel } else if (type == .ppt || type == .rtf || type == .html || type == .conversion_text) { if (type == .ppt) { convertT = .PPT } else if (type == .rtf) { convertT = .RTF } else if (type == .html) { convertT = .HTML } else if (type == .conversion_text) { convertT = .Text } } else if (type == .csv) { convertT = .CSV } else if (type == .conversion_image) { windowController = KMConvertImageWindowController() convertT = .JPEG } else if type == .json { convertT = .Json } 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!) windowController?.documentModel = model self.km_safe_beginSheet(windowC: windowController) } //MARK: 转档 - func showAllConvertWindow(convertT: KMConvertType) { self.ConvertTrackEvent(type: convertT) let convertWC = KMConvertWindowController(documemtV: self.document!, currentPage: self.listView.currentPage(), convertT: convertT) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) { [self] in var type: KMConvertWithPDFType = .WordAdvance switch convertT { case .Word: break case .Excel: type = .Excel case .PPT: type = .PowerPoint case .RTF: type = .RTF case .CSV: type = .CSV case .HTML: type = .HTML case .Text: type = .Text case .JPEG: type = .JPEG case .PNG: type = .PNG case .GIF: type = .GIF case .JPG: type = .JPG case .TIFF: type = .TIFF case .TGA: type = .TGA case .BMP: type = .BMP case .JP2: type = .JPEG2000 case .AdvancedWord: break case .Json: type = .Json break default: break } let batchWindowController = KMBatchOperateWindowController.sharedWindowController var needShowHint = false if KMConvertOperationQueue.sharedQueue.operations.count > 0 { needShowHint = true } else { var needContinue = false if KMBatchOperateManager.defaultManager.files?.count ?? 0 > 0 { let arr: [String] = converFilesToPath(files: KMBatchOperateManager.defaultManager.files!) let ss = self.document?.documentURL.path if arr.contains(ss!) { needContinue = false }else { needContinue = true } }else { needContinue = true } if needContinue { let ss = self.document?.documentURL.path let file = KMBatchOperateFile(filePath: ss!, type: .Convert) file.password = document?.password ?? "" KMBatchOperateManager.defaultManager.files?.append(file) } batchWindowController.switchToOperateType(.Convert, files: KMBatchOperateManager.defaultManager.files!) batchWindowController.switchToConvertType(convertType: type) } batchWindowController.window?.makeKeyAndOrderFront(nil) if needShowHint { batchWindowController.showIsConvertingHint() } else { } } } self.km_beginSheet(windowC: convertWC) } func ConvertTrackEvent(type: KMConvertType) { var eventStr: String = "Btn_SubTbr_Converter_ToWord" switch type { case .Word: eventStr = "Btn_SubTbr_Converter_ToWord" break case .Excel: eventStr = "Btn_SubTbr_Converter_ToExcel" case .PPT: eventStr = "Btn_SubTbr_Converter_ToPPT" case .RTF: eventStr = "Btn_SubTbr_Converter_ToRTF" case .CSV: eventStr = "Btn_SubTbr_Converter_ToCSV" case .HTML: eventStr = "Btn_SubTbr_Converter_ToHTML" case .Text: eventStr = "Btn_SubTbr_Converter_ToText" case .JPEG: eventStr = "Btn_SubTbr_Converter_ToImage" case .PNG: eventStr = "Btn_SubTbr_Converter_ToImage" case .GIF: eventStr = "Btn_SubTbr_Converter_ToImage" case .JPG: eventStr = "Btn_SubTbr_Converter_ToImage" case .TIFF: eventStr = "Btn_SubTbr_Converter_ToImage" case .TGA: eventStr = "Btn_SubTbr_Converter_ToImage" case .BMP: eventStr = "Btn_SubTbr_Converter_ToImage" case .JP2: eventStr = "Btn_SubTbr_Converter_ToImage" case .AdvancedWord: eventStr = "Btn_SubTbr_Converter_ToWord" break default: break } FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Converter", withProperties: ["SubTbr_Btn": eventStr]) } //MARK: 转档 - OCR func showOCRWindow() { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.showWindow(nil) return } let com = KMOCRPDFWindowController(cpdfDocument: self.listView.document!, pwd: self.listView.document?.password ?? "") com.currentIndexPage = self.listView.currentPageIndex self.km_beginSheet(windowC: com) } //MARK: 导出图片 func extractImageAction(num: Int) { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_ExtractImage_BuyNow" winC?.showWindow(nil) return } if !(self.listView.document.allowsPrinting || self.listView.document.allowsCopying) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() return } let document = self.listView.document var fileURL = document?.documentURL if num == 1 { let pageCount = document?.pageCount ?? 0 let indeSet = NSMutableIndexSet() indeSet.add(in: NSRange(location: 0, length: Int(pageCount))) if indeSet.count == 0 { return } let lastPathName = fileURL?.deletingPathExtension().lastPathComponent ?? "" let tFileName = (String(format: "%@_Extract Images", lastPathName)) let outputSavePanel = NSSavePanel() outputSavePanel.title = NSLocalizedString("Save as PDF", comment: "") outputSavePanel.allowsOtherFileTypes = true outputSavePanel.isExtensionHidden = true outputSavePanel.canCreateDirectories = true outputSavePanel.nameFieldStringValue = tFileName outputSavePanel.beginSheetModal(for: self.view.window!, completionHandler: { (result) in if result == NSApplication.ModalResponse.OK { DispatchQueue.main.async { self.beginProgressSheet(withMessage: NSLocalizedString("Extracting all pictures...", comment: "") + "...", maxValue: 0) let tDestFile = outputSavePanel.url!.path let uniquePath = KMExtractImageWindowController.createDestFolder(path: tDestFile, isUnique: false) let pdfconverter = PDFConvertObject() pdfconverter.extractResourcesFromPDF(at: fileURL?.path ?? "", pdfPassword: document?.password, selectIndexSet: indeSet as IndexSet, destDocPath: uniquePath, moreOptions: nil) self.dismissProgressSheet() let fileManager = FileManager.default if fileManager.fileExists(atPath: tDestFile) { let workspace = NSWorkspace.shared let url = URL(fileURLWithPath: tDestFile) workspace.activateFileViewerSelecting([url]) } } } }) return } if fileURL != nil { self.myDocument?.save(nil) } else { let myDocument = self.myDocument let str = String(format: "%@.pdf", myDocument?.displayName ?? "") let writeSuccess = document!.write(to: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!)) if writeSuccess { var documentTemp = CPDFDocument(url: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!)) fileURL = document?.documentURL } else { NSSound.beep() return } } extract = KMExtractImageWindowController(windowNibName: "KMExtractImageWindowController") extract?.docPath = fileURL?.path ?? "" extract?.password = document?.password ?? "" extract?.currentPage = self.listView.currentPageIndex self.km_beginSheet(windowC: extract!) extract?.selectCurrentPageBtn() } //MARK: 创建文字图章示例实际上不会在这里使用 func showCreateStamp() { let stampCreaterWindowController = KMStampCreaterWindowController() stampCreaterWindowController.window?.backgroundColor = .clear self.km_beginSheet(windowC: stampCreaterWindowController) stampCreaterWindowController.beginSheetModal(for: self.view.window) { [weak self] result in if result == 1 { } } } //MARK: 添加签名示例实际上不会在这里使用 func showAddSignature() { let signatureWindowController = KMSignatureWindowController(windowNibName: "KMSignatureWindowController") self.view.window?.beginSheet(signatureWindowController.window!, completionHandler: { returnCode in }) } func beginProgressSheet(withMessage message: String, maxValue: UInt) { let progress = SKProgressController() progress.window?.backgroundColor = NSColor.km_init(hex: "#36383B") progress.window?.contentView?.wantsLayer = true progress.window?.contentView?.layer?.backgroundColor = NSColor.km_init(hex: "#36383B").cgColor progress.progressField.textColor = NSColor.white progress.message = NSLocalizedString("Converting...", comment: "") progressC = progress progressC?.message = message if maxValue > 0 { progressC?.indeterminate = false progressC?.maxValue = Double(maxValue) progressC?.progressBar.doubleValue = 0.3 } else { progressC?.indeterminate = true } self.view.km_beginSheet(windowC: progressC!) } func dismissProgressSheet() { progressC?.stopAnimation() self.view.km_endSheet() progressC = nil } func converFilesToPath(files: Array) -> [String] { let newArr = NSMutableArray() for item in files { newArr.add(item.filePath) } return newArr as! [String] } internal func showPrintWindow(pageRange: KMPrintPageRange = KMPrintPageRange(type: .allPage, selectPages: [])) { self.saveDocument() 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() // 去打印 KMPrintWindowController.openDocument(inputDocument: self?.listView.document, inputPageRange: pageRange) } return } KMPrintWindowController.openDocument(inputDocument: self.listView.document, inputPageRange: pageRange) } // MARK: - 图片注释 @IBAction func imageAnnotation(_ sender: Any) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Tools_Image"]) changeAnnotationMode(sender) guard IAPProductsManager.default().isAvailableAllFunction() else { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) return } let accessoryCtr = KMImageAccessoryController() let openPanel = NSOpenPanel() openPanel.allowedFileTypes = KMImageAccessoryController.supportedImageTypes() openPanel.allowsMultipleSelection = false openPanel.accessoryView = accessoryCtr.view openPanel.canSelectHiddenExtension = true openPanel.beginSheetModal(for: NSApp.mainWindow!) { [self] (result) in if result == .OK { guard let url = openPanel.url else { return } let filePath = url.path if filePath.pathExtension.lowercased() == "pdf" { if let pdf = PDFDocument(url: url), pdf.isEncrypted { NSSound.beep() return } } guard let image = NSImage(contentsOfFile: url.path) else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: NSLocalizedString("The file \"%@\" could not be opened.", comment: ""), url.lastPathComponent) alert.informativeText = NSLocalizedString("It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", comment: "") alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in if response == .alertFirstButtonReturn { // Handle cancel button clicked } } return } let isDamageImage: Bool = self.isDamageImage(image, imagePath: url.path) if isDamageImage { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: NSLocalizedString("The file \"%@\" could not be opened.", comment: ""), url.lastPathComponent) alert.informativeText = NSLocalizedString("It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", comment: "") alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in if response == .alertFirstButtonReturn { // Handle cancel button clicked } } return } let isRemoveBGColor = accessoryCtr.selectedButton.state == .on listView.addAnnotation(with: image, isRemoveBGColor: isRemoveBGColor) if (self.listView.activeAnnotation != nil) && (self.listView.activeAnnotation.type == "Image") { } } } } @IBAction func tableAnnotation(_ sender: Any) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Tools_Table"]) changeAnnotationMode(sender) guard IAPProductsManager.default().isAvailableAllFunction() else { let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_Table_BuyNow" winC?.showWindow(nil) return } listView.addAnnotationWithTable() toggleOpenRightSide() } func isDamageImage(_ image: NSImage, imagePath path: String) -> Bool { let addImageAnnotation = (NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last! as NSString).appendingPathComponent(Bundle.main.bundleIdentifier!) if !FileManager.default.fileExists(atPath: addImageAnnotation) { try? FileManager.default.createDirectory(atPath: addImageAnnotation, withIntermediateDirectories: false, attributes: nil) } if let data = image.tiffRepresentation, let imageRep = NSBitmapImageRep(data: data) { imageRep.size = image.size var imageData: Data? if path.lowercased() == "png" { imageData = imageRep.representation(using: .png, properties: [:]) } else { imageData = imageRep.representation(using: .jpeg, properties: [:]) } if let imageData = imageData { let rPath = (addImageAnnotation as NSString).appendingPathComponent((self.tagString() as NSString).appendingPathExtension("png")!) if !((try? imageData.write(to: URL(fileURLWithPath: rPath), options: .atomicWrite)) != nil) { return true } else { return false } } } return false } func tagString() -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyMMddHHmmss" return "\(dateFormatter.string(from: Date()))\(Int.random(in: 0..<10000))" } // MARK: - Split View @IBAction func secondaryViewOpenFile(_ sender: NSButton) -> Void { } func singlePageScreen(isSinglePage: Bool, doublePagesScreen isHorizontal: Bool) -> Void { } func updateBackAndForwardButtonState() { } } // MARK: - // MARK: - KMToolbarViewControllerDelegate extension KMMainViewController : KMToolbarViewControllerDelegate { func changeModelAction(mode: CToolMode) { self.listView.toolMode = mode if mode == .editPDFToolMode { } } 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 = 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 = 16.0 break case 13: self.listView.scaleFactor = 32.0 break case 14: self.listView.scaleFactor = 64.0 break case 15: self.listView.scaleFactor = 100.0 break default: break } viewController.zoomTextField.stringValue = "\(Int(self.listView.scaleFactor*100))%" if self.digitalSignController?.pdfView != nil { self.digitalSignController?.pdfView.scaleFactor = self.listView.scaleFactor } if self.redactController?.redactPdfView != nil { self.redactController?.redactPdfView.scaleFactor = self.listView.scaleFactor } } 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 } if self.digitalSignController?.pdfView != nil { self.digitalSignController?.pdfView.scaleFactor = self.listView.scaleFactor } if self.redactController?.redactPdfView != nil { self.redactController?.redactPdfView.scaleFactor = self.listView.scaleFactor } viewController.zoomTextField.stringValue = "\(Int(self.listView.scaleFactor*100))%" } func changePDFViewZoomInAction() { } func changePDFViewZoomOutAction() { } func changePDFViewGotoNextPageAction() { self.listView.km_goBack(nil) if (self.listView.canGoToNextPage()) { self.listView.goToNextPage(nil) } } func changePDFViewGoToPreviousPageAction() { if (self.listView.canGoToPreviousPage()) { self.listView.goToPreviousPage(nil) } } func changePDFViewGotoBackAction() { self.listView.km_goBack(nil) self.updateBackAndForwardButtonState() } func changePDFViewGoToForwardAction() { self.listView.km_goForward(nil) self.updateBackAndForwardButtonState() } func aiTranslationPDFFileAction() { self.trackEvent_aiTranslate() self._aiTranslationPDFFileAction() } private func _aiTranslationPDFFileAction() { let isExceedsLimit = self.isPDFPageCountExceedsLimit(filePath: (self.document?.documentURL.path)!) if KMTools.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!) { [weak self] result in if (result == .alertFirstButtonReturn) { } else if result == .alertSecondButtonReturn { return } } } func toolbarViewController(_ viewController: KMToolbarViewController, shareAction toolbarItem: KMToolbarItemView) { self.trackEvent_share() } func toolbarViewController(_ viewController: KMToolbarViewController, scanOCRModel selectedTag: Int) { if(0 == selectedTag) { } else { } } func mainToolDidClicked(_ toolController: KMToolbarController, _ beforeType: KMToolbarViewType, _ type: KMToolbarViewType, _ item: KMToolbarItemView , _ pages: [Int]) { if beforeType == .editPDF { } if(type != .Page) { if (hasEnterPageEdit()) { self.exitPageEdit() } } if type != .redact { if self.hasEnterRedact() { self.exitRedact() } } if item.itemIdentifier != KMDocumentDigitalSignToolbarItemIdentifier { if self.hasShowDigitalSign() { self.exitDigitalSign() } } if item.itemIdentifier != KMDocumentViewDisplayToolbarItemIdentifier { } if(type != .Form) { self.removeFromAlertView() } if (type == .Page) { if (hasEnterPageEdit()) { self.exitPageEdit() } else { self.enterPageEdit(pages) } } else if type == .editPDF { } else if type == .Annatiton { } else if type == .redact { if self.needSaveDocument() { self.saveDocumentWithProgressAlert { [unowned self] params in self.enterRedact() } return } let isEdited = self.listView.isEdited() let isPDFTextImageEdited = self.model.isPDFTextImageEdited if isEdited || isPDFTextImageEdited { self.enterRedact() } else { self.enterRedact() } } else if type == .Tool { if KMGuideInfoWindowController.availableShow(.pdfCompareGuide) { self.loadOpenFileFunctionGuide(.pdfCompareGuide) } else if KMGuideInfoWindowController.availableShow(.measureGuide) { self.loadOpenFileFunctionGuide(.measureGuide) } } else if type == . Conversion { self.loadOpenFileFunctionGuide(.convertGuide) }else if type == .Form { self.showFormAlertView() }else if type == .Select { toggleCloseRightSide() } } 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 !self.documentAllowsEdit() { return } if (self.needSaveDocument()) { self.saveDocumentWithProgressAlert { [unowned self] params in self.showCompressWindow() } return } self.showCompressWindow() return } if ((KMToolbarType.word.rawValue ... KMToolbarType.json.rawValue).contains(type.rawValue)) { /// 转档 if type == .conversion_imageToPDF { Task { let _ = await NSApplication.ShowImageToPDFWindow(urls: []) } return } 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 (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) { /// 合并 FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Merge"]) if !self.documentAllowsEdit() { 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 == .bates || type == .headerAndFooter) { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() if type == .headerAndFooter { if index == 1 { winC?.kEventName = "Reading_AddHeaderFooter_BuyNow" } else if index == 2 { winC?.kEventName = "Reading_RemoveHeaderFooter_BuyNow" } } else if type == .bates { if index == 1 { winC?.kEventName = "Reading_AddBates_BuyNow" } else if index == 2 { winC?.kEventName = "Reading_RemoveBates_BuyNow" } } winC?.showWindow(nil) return } if !self.documentAllowsEdit() { return } if (index == 1) { var windowController: KMBaseWindowController = KMBaseWindowController() if (type == .bates) { } else if (type == .headerAndFooter) { } else if (type == .background) { } else if (type == .watermark) { } windowController.pdfDocument = self.listView.document windowController.cancelAction = { [unowned self] controller in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil } self.currentWindowController = windowController await self.view.window?.beginSheet(windowController.window!) return } if (index == 1) { /// 取消 /// toggleCloseRightSide() return } else if index == 3 { let fpath = self.document?.documentURL?.path ?? "" if type == .bates { self.showBatchWindow(type: .AddBates, filepaths: [fpath]) } else { self.showBatchWindow(type: .AddHeaderFooter, filepaths: [fpath]) } } else if index == 4 { let fpath = self.document?.documentURL?.path ?? "" if type == .bates { self.showBatchWindow(type: .RemoveBates, filepaths: [fpath]) } else { self.showBatchWindow(type: .RemoveHeaderFooter, filepaths: [fpath]) } } else if (index == 2) { //// 移除 if type == .headerAndFooter { let savePanelAccessoryViewController = KMSavePanelAccessoryController() let savePanel = NSSavePanel() savePanel.nameFieldStringValue = self.document?.documentURL.deletingPathExtension().lastPathComponent ?? "" savePanel.allowedFileTypes = ["pdf"] savePanel.accessoryView = savePanelAccessoryViewController.view savePanel.beginSheetModal(for: NSWindow.currentWindow()) { [unowned self] result in if result.rawValue == NSApplication.ModalResponse.OK.rawValue { } } } else if type == .bates { let savePanelAccessoryViewController = KMSavePanelAccessoryController() let savePanel = NSSavePanel() savePanel.nameFieldStringValue = self.document?.documentURL.deletingPathExtension().lastPathComponent ?? "" savePanel.allowedFileTypes = ["pdf"] savePanel.accessoryView = savePanelAccessoryViewController.view savePanel.beginSheetModal(for: NSWindow.currentWindow()) { [unowned self] result in if result.rawValue == NSApplication.ModalResponse.OK.rawValue { } } } } else if (index == 2) { /// 应用 } else if index == 5 { self.toggleOpenRightSide() } } else if (type == .redact) { /// 标记密文 if !IAPProductsManager.default().isAvailableAllFunction(){ KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) return } if (index == 1) { /// 取消 if (self.model.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 } return } self.listView.toolMode = .moveToolMode 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) { 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) ?? 0)) 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) ?? 0)) } 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 (index == 1) { /// 设置密码 if (!self.listView.document!.allowsCopying || !self.listView.document!.allowsPrinting) { if !self.documentAllowsEdit() { return } } self.showSecureWindow(self.listView.document.documentURL) return } else if index == 2 { if !self.document!.allowsCopying || !self.document!.allowsPrinting { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Warning", comment: "") alert.informativeText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.addButton(withTitle: NSLocalizedString("Remove Security", comment: "")) alert.beginSheetModal(for: NSWindow.currentWindow()) { returnCode in if returnCode == .alertSecondButtonReturn { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) { [unowned self] in KMBaseWindowController.checkPassword(url: self.document!.documentURL!, type: .owner) { [unowned self] success, resultPassword in if success { self.document?.unlock(withPassword: resultPassword) self.clickChildTool(type: .secure, index: 2) } } } } } } else { let controller = KMRemovePasswordWindowController(windowNibName: "KMRemovePasswordWindowController") controller.pdfDocument = self.document self.currentWindowController = controller controller.batchAction = { [unowned self] controller, files in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil let baseWindowController = KMBatchOperateBaseWindowController(windowNibName: "KMBatchOperateBaseWindowController") if #available(macOS 10.13, *) { baseWindowController.window?.makeKeyAndOrderFront(nil) } else { baseWindowController.showWindow(nil) } let arr = NSMutableArray() let file = KMBatchOperateFile(filePath: self.listView.document!.documentURL!.path, type: .RemovePassword) file.password = document?.password ?? "" arr.add(file) baseWindowController.switchToOperateType(.RemovePassword, files: arr as! [KMBatchOperateFile]) } controller.cancelAction = { [unowned self] controller in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil } controller.doneAction = { [unowned self] controller in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil KMBaseWindowController.checkPassword(url: self.document!.documentURL!, type: .owner, password: self.document?.password ?? "") { [unowned self] success, resultPassword in if success { let savePanel = NSSavePanel() savePanel.nameFieldStringValue = self.listView.document.documentURL.deletingPathExtension().lastPathComponent + "_RemovePassword" savePanel.allowedFileTypes = ["pdf"] savePanel.beginSheetModal(for: NSApp.mainWindow!) {[unowned self] result in guard result == .OK else { return } /// 删除安全性设置 if (!self.listView.document!.allowsCopying || !self.listView.document!.allowsPrinting) { self.model.isSaveKeyChain = false self.listView.document.unlock(withPassword: resultPassword) } let document = CPDFDocument.init(url: self.listView.document.documentURL) guard let document = document else { return } document.unlock(withPassword: resultPassword) let success = document.writeDecrypt(to: savePanel.url) if success { self.hiddenSecureLimitTip() let tip = KMRemovePasswordResultTipView() tip.result = .success tip.showInView(superView: (self.listView.superview)!) NSWorkspace.shared.activateFileViewerSelecting([savePanel.url!]) } else { self.hiddenSecureLimitTip() let tip = KMRemovePasswordResultTipView() tip.result = .failure tip.showInView(superView: (self.listView.superview)!) } } } } } await NSWindow.currentWindow().beginSheet(controller.window!) } return } } else if type == .comparison { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Compare"]) if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_Compare_BuyNow" winC?.showWindow(nil) return } let controller = KMCompareWindowController(windowNibName: "KMCompareWindowController") self.currentWindowController = controller controller.password = self.document?.password ?? "" controller.filePath = (self.document?.documentURL.path)! controller.cancelAction = { [unowned self] controller in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil } controller.contentComplete = { [unowned self] controller, pdfCompareContent, result, oldDocument, document in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil self.openContentCompareVC(with: pdfCompareContent, results: result, oldDocument: oldDocument, document: document) } controller.coveringComplete = { [unowned self] controller, document in self.view.window?.endSheet((self.currentWindowController.window)!) self.currentWindowController = nil self.openCoveringCompareVC(with: document) } if index == 1 { controller.fileType = .content } else { controller.fileType = .coverting } await NSWindow.currentWindow().beginSheet(controller.window!) } else if type == .watermark { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() if index == 1 { winC?.kEventName = "Reading_AddWatermark_BuyNow" } else if index == 2 { winC?.kEventName = "Reading_RemoveWatermark_BuyNow" } winC?.showWindow(nil) return } if !self.documentAllowsEdit() { return } if index == 1 { } else if index == 2 { let watermarks = self.listView.document.watermarks() if (watermarks == nil || watermarks!.count <= 0) { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Could not find a removable watermark in this document. If you see a watermark, it was not added with PDF Reader Pro and therefore cannot be detected.", comment: "") alert.addButton(withTitle: NSLocalizedString("Confirm", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) alert.runModal() return } let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Are you sure you want to remove the watermark?", comment: "") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) let result = alert.runModal() if (result != .alertFirstButtonReturn) { return } let savePanelAccessoryViewController = KMSavePanelAccessoryController() let savePanel = NSSavePanel() savePanel.nameFieldStringValue = self.listView.document.documentURL.deletingPathExtension().lastPathComponent savePanel.allowedFileTypes = ["pdf"] savePanel.accessoryView = savePanelAccessoryViewController.view savePanel.beginSheetModal(for: NSApp.mainWindow!) { result in guard result == .OK else { return } } } else if index == 3 { let fpath = self.document?.documentURL?.path ?? "" self.showBatchWindow(type: .AddWatermark, filepaths: [fpath]) } else if index == 4 { let fpath = self.document?.documentURL?.path ?? "" self.showBatchWindow(type: .RemoveWatermark, filepaths: [fpath]) } else if index == 5 { toggleOpenRightSide() return } } else if type == .background { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() if index == 1 { winC?.kEventName = "Reading_AddBackground_BuyNow" } else if index == 2 { winC?.kEventName = "Reading_RemoveBackground_BuyNow" } winC?.showWindow(nil) return } if !self.documentAllowsEdit() { return } if index == 1 { } else if index == 2 { guard let document = self.document else { return } if !document.allowsPrinting || !document.allowsCopying { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() return } guard let documentURL = document.documentURL else { return } let savePanelAccessoryViewController = KMSavePanelAccessoryController() let savePanel = NSSavePanel() savePanel.nameFieldStringValue = documentURL.deletingPathExtension().lastPathComponent savePanel.allowedFileTypes = ["pdf"] savePanel.accessoryView = savePanelAccessoryViewController.view savePanel.beginSheetModal(for: NSApp.mainWindow!) { result in guard result == .OK else { return } } } else if index == 3 { let fpath = self.document?.documentURL?.path ?? "" self.showBatchWindow(type: .AddBackground, filepaths: [fpath]) } else if index == 4 { let fpath = self.document?.documentURL?.path ?? "" self.showBatchWindow(type: .RemoveBackground, filepaths: [fpath]) } else if index == 5 { toggleOpenRightSide() return } } else if type == .measure { if !IAPProductsManager.default().isAvailableAllFunction(){ let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_Measure_BuyNow" winC?.showWindow(nil) return } if !self.documentAllowsEdit() { return } self.listView.toolMode = .measureToolMode if distanceMeasureInfoWindowController?.window?.isVisible == true { distanceMeasureInfoWindowController?.hideFloatingWindow() } else if perimeterMeasureInfoWindowController?.window?.isVisible == true { perimeterMeasureInfoWindowController?.hideFloatingWindow() } else if areaMeasureInfoWindowController?.window?.isVisible == true { areaMeasureInfoWindowController?.hideFloatingWindow() } if distanceMeasureInfoWindowController == nil { let measureInfo = CPDFDistanceMeasureInfo() distanceMeasureInfoWindowController = CDistanceMeasureInfoWindowController() distanceMeasureInfoWindowController?.measureInfo = measureInfo distanceMeasureInfoWindowController?.delegate = self } if perimeterMeasureInfoWindowController == nil { let measureInfo = CPDFPerimeterMeasureInfo() perimeterMeasureInfoWindowController = CPerimeterMeasureInfoWindowController() perimeterMeasureInfoWindowController?.measureInfo = measureInfo perimeterMeasureInfoWindowController?.delegate = self } if areaMeasureInfoWindowController == nil { let measureInfo = CPDFAreaMeasureInfo() areaMeasureInfoWindowController = CAreaMeasureInfoWindowController() areaMeasureInfoWindowController?.measureInfo = measureInfo areaMeasureInfoWindowController?.delegate = self } if index == 1 { self.listView.annotationType = .line let winW: CGFloat = 300 let rightW: CGFloat = 270 var winFrame = self.view.window?.frame ?? .zero winFrame.origin.x += (winFrame.size.width-winW-rightW) distanceMeasureInfoWindowController?.window?.setFrameOrigin(winFrame.origin) distanceMeasureInfoWindowController?.showWindow(nil) distanceMeasureInfoWindowController?.lengthLabel.stringValue = "" distanceMeasureInfoWindowController?.angleLabel.stringValue = "" distanceMeasureInfoWindowController?.xLabel.stringValue = "" distanceMeasureInfoWindowController?.yLabel.stringValue = "" _ = CustomAlertView.alertView(message: "ESC to exit continuous measuring mode.", fromView: self.view, withStyle: .black) self.trackEvent(toolMode: .measureToolMode) } else if index == 2 { self.listView.annotationType = .polyLine let winW: CGFloat = 300 let rightW: CGFloat = 270 var winFrame = self.view.window?.frame ?? .zero winFrame.origin.x += (winFrame.size.width-winW-rightW) perimeterMeasureInfoWindowController?.window?.setFrameOrigin(winFrame.origin) perimeterMeasureInfoWindowController?.showWindow(nil) perimeterMeasureInfoWindowController?.lengthLabel.stringValue = "" perimeterMeasureInfoWindowController?.angleLabel.stringValue = "" _ = CustomAlertView.alertView(message: "Double-click to finish drawing. Press ESC to exit continuous measuring mode.", fromView: self.view, withStyle: .black) self.trackEvent(toolMode: .measureToolMode) } else if index == 3 { self.listView.annotationType = .polyGon let winW: CGFloat = 300 let rightW: CGFloat = 270 var winFrame = self.view.window?.frame ?? .zero winFrame.origin.x += (winFrame.size.width-winW-rightW) areaMeasureInfoWindowController?.window?.setFrameOrigin(winFrame.origin) areaMeasureInfoWindowController?.showWindow(nil) areaMeasureInfoWindowController?.areaLabel.stringValue = "" areaMeasureInfoWindowController?.angleLabel.stringValue = "" _ = CustomAlertView.alertView(message: "Double-click to finish drawing. Press ESC to exit continuous measuring mode.", fromView: self.view, withStyle: .black) self.trackEvent(toolMode: .measureToolMode) } else if index == 4 { self.listView.annotationType = .square let winW: CGFloat = 300 let rightW: CGFloat = 270 var winFrame = self.view.window?.frame ?? .zero winFrame.origin.x += (winFrame.size.width-winW-rightW) areaMeasureInfoWindowController?.window?.setFrameOrigin(winFrame.origin) areaMeasureInfoWindowController?.showWindow(nil) areaMeasureInfoWindowController?.areaLabel.stringValue = "" areaMeasureInfoWindowController?.angleLabel.stringValue = "" _ = CustomAlertView.alertView(message: "ESC to exit continuous measuring mode.", fromView: self.view, withStyle: .black) self.trackEvent(toolMode: .measureToolMode) } else { if let isVisible = distanceMeasureInfoWindowController!.window?.isVisible, isVisible { distanceMeasureInfoWindowController?.hideFloatingWindow() } else if let isVisible = perimeterMeasureInfoWindowController!.window?.isVisible, isVisible { perimeterMeasureInfoWindowController?.hideFloatingWindow() } else if let isVisible = areaMeasureInfoWindowController!.window?.isVisible, isVisible { areaMeasureInfoWindowController?.hideFloatingWindow() } } toggleOpenRightSide() } } } func showBatchWindow(type: KMBatchOperationType, filepaths: [String]?) { let batchWindowController = KMBatchOperateWindowController.sharedWindowController var array: [KMBatchOperateFile] = [] for fpath in filepaths ?? [] { let batchOperateFile = KMBatchOperateFile(filePath: fpath, type: type) array.append(batchOperateFile) } batchWindowController.switchToOperateType(type, files: array) batchWindowController.window?.makeKeyAndOrderFront("") } func toolbarViewController(_ viewController: KMToolbarViewController, itemDidClick toolbarItem: KMToolbarItemView) { self.toolbarItemClickForExitMode(toolbarItem) if let itemID = toolbarItem.itemIdentifier { if isMainToolItem(itemID) { if toolbarItem.itemIdentifier == KMDocumentHomeToolbarItemIdentifier { openNewWindowAlertWindow() } else if toolbarItem.itemIdentifier == KMDocumentPreviousPageToolbarItemIdentifier { self.changePDFViewGoToPreviousPageAction() } else if toolbarItem.itemIdentifier == KMDocumentViewDisplayToolbarItemIdentifier { let isSelected = toolbarItem.isSelected toolbarItem.isSelected = !isSelected if toolbarItem.isSelected { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageDisplay", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageDisplay_ViewSetting"]) toggleOpenRightSide() }else{ toggleCloseRightSide() } if toolbarItem.isSelected { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn": "Btn_Tbr_PageDisplay"]) } } else if toolbarItem.itemIdentifier == KMLeftControlToolbarItemIdentifier { toolbarItem.isSelected = !toolbarItem.isSelected self.leftSideViewController.showPanelView(show: toolbarItem.isSelected) } else if toolbarItem.itemIdentifier == KMRightControlToolbarItemIdentifier { if (self.listView.activeAnnotation != nil) && (self.listView.activeAnnotation.type == "Image") { } toolbarItem.isSelected = !toolbarItem.isSelected self.toggleRightPane() } else if itemID == KMDocumentRedactToolbarItemIdentifier { self.listView.toolMode = .redactToolMode self.enterRedact() } else if itemID == KMDocumentScanOCRToolbarItemIdentifier { showOCRWindow() } else if itemID == KMDocumentAIToolsToolbarItemIdentifier { self.showAITypeChooseView(aiConfigType: .none) } else if itemID == KMDocumentDigitalSignToolbarItemIdentifier { if self.canEnterDigitalSign() == false { Task { _ = await KMAlertTool.runModel(message: NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "")) } return } toolbarItem.isSelected = !toolbarItem.isSelected if toolbarItem.isSelected { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn": "Btn_Tbr_DigitalSignature"]) } self.enterDigitalSign() } else if itemID == KMDocumentPrintToolbarItemIdentifier { self.showPrintWindow() } else if itemID == KMDocumentPresentationToolbarItemIdentifier { self.togglePresentation(nil) } else if itemID == KMDocumentSignToolbarItemIdentifier { let isSelected = toolbarItem.isSelected toolbarItem.isSelected = !isSelected } } else { if toolbarItem.itemIdentifier == KMToolbarAnnotationSettingItemIdentifier { toolbarItem.isSelected = false let windowC = KMToolbarCustomWindowController() windowC.resetCallback = { [weak self] in } self.km_beginSheet(windowC: windowC) { [weak self] resp, obj in if resp == .OK { } } } else if toolbarItem.itemIdentifier == KMToolbarComparisonItemIdentifier { Swift.debugPrint("KMToolbarComparisonItemIdentifier ...") } else if toolbarItem.itemIdentifier == KMDocumentPrintToolbarItemIdentifier { self.trackEvent_print() self.showPrintWindow() } else if toolbarItem.itemIdentifier == KMToolbarToolProfileIdentifier { Swift.debugPrint("KMToolbarToolProfileIdentifier ...") FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Fill&Sign", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Fill&Sign_Profile"]) let windowC = KMProfileInfoWindowController(windowNibName: "KMProfileInfoWindowController") windowC.callBack = { [weak self] string in if (string.isEmpty == false) { self?.listView.addTextField(subType: .profile, string: string) } self?.km_endSheet() } self.km_beginSheet(windowC: windowC) } else if toolbarItem.itemIdentifier == KMToolbarViewSettingIdentifier { toolbarItem.isSelected = !toolbarItem.isSelected self.listView.annotationType = .unkown if toolbarItem.isSelected { toggleOpenRightSide() }else{ toggleCloseRightSide() } } else if toolbarItem.itemIdentifier == KMToolbarSnapshotIdentifier { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageDisplay", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageDisplay_Snapshot"]) self.listView.takeSnapshot(nil) } else if toolbarItem.itemIdentifier == KMToolbarTTSIdentifier { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageDisplay", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageDisplay_TTS"]) self.listView.annotationType = .unkown self.showTTSWindow() } else if toolbarItem.itemIdentifier == KMToolbarConversionOCRIdentifier { self.showOCRWindow() } else if toolbarItem.itemIdentifier == KMAnnotationImageToolbarItemIdentifier { toolbarItem.isSelected = false self.imageAnnotation(toolbarItem) } else if toolbarItem.itemIdentifier == KMAnnotationTableToolbarItemIdentifier { self.tableAnnotation(toolbarItem) } else if toolbarItem.itemIdentifier == KMToolbarPageEditInsetItemIdentifier { // 插入 self.leftSideViewController.insertPDF(nil) } else if toolbarItem.itemIdentifier == KMToolbarPageEditSplitItemIdentifier { // 拆分 let windowC = SplitWindowController(document: self.listView.document) self.km_beginSheet(windowC: windowC) } else if itemID == KMSignDigitalSignToolbarItemIdentifier { if self.canEnterDigitalSign() == false { Task { _ = await KMAlertTool.runModel(message: NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "")) } return } toolbarItem.isSelected = !toolbarItem.isSelected if toolbarItem.isSelected { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn": "Btn_Tbr_DigitalSignature"]) } self.enterDigitalSign() } else if itemID == KMToolbarMeasureItemIdentifier { if toolbarItem.isSelected { toolbarItem.isSelected = false self.listView.toolMode = .textToolMode self.listView.annotationType = .unkown } } } } } func openNewWindowAlertWindow() { var needShowChooseWindow = false //#if VERSION_FREE if (!IAPProductsManager.default().isAvailableAllFunction()) { needShowChooseWindow = true } //#endif if needShowChooseWindow { let preferenceNoteShow = UserDefaults.standard.bool(forKey: KMTabbingHintShowFlag) if preferenceNoteShow { menuItemAction_newTagPageToNewWindow("") } else { if !KMDataManager.default.isTabbingWin{ KMDataManager.default.isTabbingWin = true let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController() tabbingWin.selectCallBack = {[weak self] continueOrNot in KMDataManager.default.isTabbingWin = false if continueOrNot { self?.reopenDocument(forPaths: []) } else { } } self.km_beginSheet(windowC: tabbingWin) } } }else{ handleTabbingLogic() } } func reopenDocument(forPaths paths: [String]) -> Void { let browser = KMBrowser.init() as KMBrowser browser.windowController = KMBrowserWindowController.init(browser: browser) browser.addHomeTabContents() browser.windowController.showWindow(self) } func handleTabbingLogic() { self.browserWindowController?.browser?.selectTabContents(at: 0, userGesture: true) } func showTTSWindow() { var lastPDFView: CPDFView? let ttsView = KMTTSWindowController.share if (ttsView.window?.isVisible ?? false) { lastPDFView = ttsView.pdfView if lastPDFView?.document?.documentURL?.path == self.listView.document?.documentURL?.path { lastPDFView = nil ttsView.window?.orderOut(nil) } else { ttsView.pdfView = self.listView ttsView.showWindow(nil) } } else { ttsView.pdfView = self.listView ttsView.showWindow(nil) } ttsView.closeWindowCallback = { (isCloseWindow: Bool) in if isCloseWindow { } } if let currentSelection = self.listView.currentSelection { if let data = currentSelection.selectionsByLine, data.isEmpty == false { ttsView.startSpeakingPDFSelection(currentSelection) } } if let lastPDFView = lastPDFView { lastPDFView.setHighlightedSelections([]) ttsView.stopSpeaking() } } func toolbarViewController(_ viewController: KMToolbarViewController, menuItemDidClick toolbarItem: KMToolbarItemView, index: Int, info: Any?) { self.toolbarItemClickForExitMode(toolbarItem) let itemId = toolbarItem.itemIdentifier if (toolbarItem.itemIdentifier == KMToolbarToolWatermarkItemIdentifier) { self.clickChildTool(type: .watermark, index: index) FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Watermark"]) } else if (toolbarItem.itemIdentifier == KMToolbarToolBackgroundItemIdentifier) { self.clickChildTool(type: .background, index: index) FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Background"]) } else if (toolbarItem.itemIdentifier == KMToolbarToolHeaderFooterItemIdentifier) { self.clickChildTool(type: .headerAndFooter, index: index) FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Header&Footer"]) } else if (toolbarItem.itemIdentifier == KMToolbarToolBatesItemIdentifier) { self.clickChildTool(type: .bates, index: index) FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_BatesNumber"]) } else if (toolbarItem.itemIdentifier == KMToolbarMeasureItemIdentifier) { self.clickChildTool(type: .measure, index: index) } else if (toolbarItem.itemIdentifier == KMToolbarComparisonItemIdentifier) { self.clickChildTool(type: .comparison, index: index) } else if (toolbarItem.itemIdentifier == KMToolbarToolFormAlignIdentifier) { } else if (toolbarItem.itemIdentifier == KMToolbarConversionImageItemIdentifier) { convertToImg(index: index) FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Converter", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Converter_ToImage"]) } else if (toolbarItem.itemIdentifier == KMToolbarConversionExportImageItemIdentifier) { extractImageAction(num: index) } else if (toolbarItem.itemIdentifier == KMToolbarConversionCreatePDFItemIdentifier) { self.createPdf(index: index) } else if (toolbarItem.itemIdentifier == KMToolbarCropIdentifier) { } else if (toolbarItem.itemIdentifier == KMToolbarToolSecureItemIdentifier) { self.clickChildTool(type: .secure, index: index) FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Security"]) } else if toolbarItem.itemIdentifier == KMDocumentSearchToolbarItemIdentifier { if index == 11 { self.view.window?.makeFirstResponder(nil) let winC = KMSearchReplaceWindowController(with: self.listView, type: .search) self.currentWindowController = winC winC.replaceCallback = { [weak self] in let toolMode = self?.listView.toolMode ?? .none let isEditing = self?.listView.isEditing() ?? false if toolMode == .editPDFToolMode && isEditing { } else { // 进入内容编辑模式 } } let point = toolbarItem.convert(toolbarItem.frame.origin, to: nil) let x = point.x + (toolbarItem.window?.frame.origin.x ?? 0) - 200 let y = point.y + (toolbarItem.window?.frame.origin.y ?? 0) - 248 - 16 let winFramePoint = NSPoint(x: x, y: y) winC.window?.setFrameOrigin(winFramePoint) winC.startModal(nil) } else if index == 12 { if IAPProductsManager.default().isAvailableAllFunction() == false { let winC = KMPurchaseCompareWindowController.sharedInstance() winC?.kEventName = "Reading_ReplaceText_BuyNow" winC?.showWindow(nil) return } self.view.window?.makeFirstResponder(nil) let toolMode = self.listView.toolMode ?? .none let isEditing = self.listView.isEditing() ?? false if toolMode == .editPDFToolMode && isEditing { } else { // 进入内容编辑模式 } self.trackEvent_replace() let winC = KMSearchReplaceWindowController(with: self.listView, type: .replace) self.currentWindowController = winC winC.replaceCallback = { [weak self] in let toolMode = self?.listView.toolMode ?? .none let isEditing = self?.listView.isEditing() ?? false if toolMode == .editPDFToolMode && isEditing { } else { // 进入内容编辑模式 } } let point = toolbarItem.convert(toolbarItem.frame.origin, to: nil) let x = point.x + (toolbarItem.window?.frame.origin.x ?? 0) - 200 let y = point.y + (toolbarItem.window?.frame.origin.y ?? 0) - 388 let winFramePoint = NSPoint(x: x, y: y) winC.window?.setFrameOrigin(winFramePoint) winC.startModal(nil) } else { } } else if toolbarItem.itemIdentifier == KMRightControlToolbarItemIdentifier { toolbarItem.isSelected = !toolbarItem.isSelected self.toggleRightPane() } else if toolbarItem.itemIdentifier == KMDocumentViewDisplayToolbarItemIdentifier { } else if toolbarItem.itemIdentifier == KMToolbarConversionOCRIdentifier { self.showOCRWindow() } else if toolbarItem.itemIdentifier == KMToolbarAIItemIdentifier { if index == 1 { self.showAITypeChooseView(aiConfigType: .summarize) } else if index == 2 { self.showAITypeChooseView(aiConfigType: .reWriting) } else if index == 3 { self.showAITypeChooseView(aiConfigType: .proofreading) } else if index == 4 { self.showAITypeChooseView(aiConfigType: .translate) } } else if toolbarItem.itemIdentifier == KMDocumentScanOCRToolbarItemIdentifier { self.showOCRWindow() } else if toolbarItem.itemIdentifier == KMDocumentEditToolbarItemIdentifier { } else if toolbarItem.itemIdentifier == KMDocumentFillSginToolbarItemIdentifier { } else if toolbarItem.itemIdentifier == KMDocumentFormToolbarItemIdentifier { } else if itemId == KMDocumentDigitalSignToolbarItemIdentifier { if self.canEnterDigitalSign() == false { Task { _ = await KMAlertTool.runModel(message: NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "")) } return } toolbarItem.isSelected = !toolbarItem.isSelected if toolbarItem.isSelected { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn": "Btn_Tbr_DigitalSignature"]) } self.enterDigitalSign() } else if itemId == KMSignDigitalSignToolbarItemIdentifier { if self.canEnterDigitalSign() == false { Task { _ = await KMAlertTool.runModel(message: NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "")) } return } toolbarItem.isSelected = !toolbarItem.isSelected if toolbarItem.isSelected { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn": "Btn_Tbr_DigitalSignature"]) } self.enterDigitalSign() } else if itemId == KMDocumentAIToolsToolbarItemIdentifier { self.showAITypeChooseView(aiConfigType: .none) } else if itemId == KMToolbarToolCompressItemIdentifier { self.clickChildTool(type: .compress, index: 0) } else if itemId == KMToolbarPageEditSplitItemIdentifier { // 拆分 let windowC = SplitWindowController(document: self.listView.document) self.km_beginSheet(windowC: windowC) } else if itemId == KMToolbarToolMergeItemIdentifier { self.clickChildTool(type: .merge, index: 0) } else if itemId == KMToolbarPageEditInsetItemIdentifier { self.leftSideViewController.insertPDF(nil) } else if itemId == KMToolbarShowToolbarItemIdentifier { self.showOrHideNotes() } else if itemId == KMAnnotationTableToolbarItemIdentifier { self.tableAnnotation(toolbarItem) } else if itemId == KMToolbarConversionTextItemIdentifier { self.clickChildTool(type: .conversion_text, index: 0) } else if itemId == KMToolbarConversionHTMLItemIdentifier { self.clickChildTool(type: .html, index: 0) } else if itemId == KMToolbarConversionCSVItemIdentifier { self.clickChildTool(type: .csv, index: 0) } else if itemId == KMToolbarConversionRTFItemIdentifier { self.clickChildTool(type: .rtf, index: 0) } else if itemId == KMToolbarConversionPPTItemIdentifier { self.clickChildTool(type: .ppt, index: 0) } else if itemId == KMToolbarConversionExcelItemIdentifier { self.clickChildTool(type: .excel, index: 0) } else if itemId == KMToolbarConversionWordItemIdentifier { self.clickChildTool(type: .word, index: 0) } else if itemId == KMToolbarConversionOtherItemIdentifier { if index == KMPDFConvertType.text.rawValue { self.clickChildTool(type: .conversion_text, index: 0) } else if index == KMPDFConvertType.rtf.rawValue { self.clickChildTool(type: .rtf, index: 0) } else if index == KMPDFConvertType.html.rawValue { self.clickChildTool(type: .html, index: 0) } else if index == KMPDFConvertType.csv.rawValue { self.clickChildTool(type: .csv, index: 0) } else if index == KMPDFConvertType.json.rawValue { self.clickChildTool(type: .json, index: 0) } } } func convertToImg(index: Int) { var convertT: KMConvertType = .JPEG switch index { case 7: convertT = .JPEG case 8: convertT = .JPG case 9: convertT = .PNG case 10: convertT = .GIF case 11: convertT = .TIFF case 12: convertT = .TGA case 13: convertT = .BMP default: convertT = .JPEG } showAllConvertWindow(convertT: convertT) } func toolbarViewController(_ viewController: KMToolbarViewController, searchAction searchString: String, forward: Bool) { let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveSearchKey) self.search(searchString: searchString, isCase: caseInsensitive, display: false) var row = max(searchIndex - 1, 0) if forward { row = searchIndex + 1 } if row >= 0 && row < self.searchResults.count && self.searchResults.count != 0 { let model = self.searchResults[row] if model.selection != nil { self.listView.setHighlightedSelections([]) self.listView.go(to: model.selection, animated: true) self.listView.setHighlightedSelection(model.selection, animated: true) self.listView.setNeedsDisplayAnnotationViewForVisiblePages() searchIndex = row } } self.leftSideViewController.showSearchMode(searchString) } func toolbarViewController(_ viewController: KMToolbarViewController, findSearchAction searchString: String, forward: Bool) { let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveSearchKey) self.search(searchString: searchString, isCase: !caseInsensitive, display: false) var row = max(searchIndex - 1, 0) if forward { row = searchIndex + 1 } if row >= 0 && row < self.searchResults.count && self.searchResults.count != 0 { let model = self.searchResults[row] if model.selection != nil { self.listView.setHighlightedSelections([]) self.listView.go(to: model.selection, animated: true) self.listView.setHighlightedSelection(model.selection, animated: true) self.listView.setNeedsDisplayAnnotationViewForVisiblePages() searchIndex = row } } } func toolbarViewController(_ viewController: KMToolbarViewController, findSearchAllAction searchString: String, forward: Bool) { let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveSearchKey) self.search(searchString: searchString, isCase: !caseInsensitive, display: false, needShowAll: true) self.leftSideViewController.showSearchMode(searchString) } func toolbarViewController(_ viewController: KMToolbarViewController, viewItemDidClick toolbarItem: KMToolbarItemView, index: Int, info: Any?) { let itemId = toolbarItem.itemIdentifier if itemId == KMDocumentFirstLastToolbarItemIdentifier { if index == 1 { if self.listView.canGoToFirstPage() { self.listView.goToFirstPage(nil) } } else if index == 2 { if self.listView.canGoToLastPage() { self.listView.goToLastPage(nil) } } } else if itemId == KMDocumentPageInputToolbarItemIdentifier { var valid = false if let number = Int(info as? String ?? "") { let cnt = self.listView.document?.pageCount ?? 0 if number > 0 && number <= cnt { self.listView.go(toPageIndex: number-1, animated: false) valid = true } } if valid == false { Task {@MainActor in _ = await KMAlertTool.runModel(message: NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")) } } } } } // MARK: CDistanceMeasureInfoWindowControllerDelegate extension KMMainViewController : CDistanceMeasureInfoWindowControllerDelegate { func distanceMeasureInfoWindowControllerSetting(_ distanceMeasureInfoWindowController: CDistanceMeasureInfoWindowController) { let distanceSettingWC = CDistanceSettingWindowController(distanceMeasureInfo: self.distanceMeasureInfoWindowController!.measureInfo) self.distanceMeasureInfoWindowController?.hideFloatingWindow() distanceSettingWC.delegate = self distanceSettingWC.startModal("") } func cancelMeasureInfoWindowControllerSetting(_ distanceMeasureInfoWindowController: CDistanceMeasureInfoWindowController) { } } // MARK: CPerimeterMeasureInfoWindowControllerDelegate extension KMMainViewController : CPerimeterMeasureInfoWindowControllerDelegate { func perimeterMeasureInfoWindowControllerSetting(_ perimeterMeasureInfoWindowController: CPerimeterMeasureInfoWindowController) { let distanceSettingWC = CDistanceSettingWindowController(perimeterMeasureInfo: self.perimeterMeasureInfoWindowController!.measureInfo) self.distanceMeasureInfoWindowController?.hideFloatingWindow() distanceSettingWC.delegate = self distanceSettingWC.startModal("") } } // MARK: CAreaMeasureInfoWindowControllerDelegate extension KMMainViewController : CAreaMeasureInfoWindowControllerDelegate { func areaMeasureInfoWindowControllerSetting(_ areaMeasureInfoWindowController: CAreaMeasureInfoWindowController) { let areaSettingWC = CAreaSettingWindowController(measureInfo: self.areaMeasureInfoWindowController!.measureInfo) self.areaMeasureInfoWindowController?.hideFloatingWindow() areaSettingWC.delegate = self areaSettingWC.startModal("") } } // MARK: CDistanceSettingWindowControllerDelegate extension KMMainViewController : CDistanceSettingWindowControllerDelegate { func distanceSettingWindowController(_ distanceSettingWindowController: CDistanceSettingWindowController, distanceMeasureInfo: CPDFDistanceMeasureInfo?) { if distanceMeasureInfo != nil { if self.listView.activeAnnotations.count > 0 { if self.listView.activeAnnotation.isKind(of: CPDFLineAnnotation.self) { (self.listView.activeAnnotation as! CPDFLineAnnotation).measureInfo = distanceMeasureInfo self.listView.setNeedsDisplayAnnotationViewFor(self.listView.activeAnnotation.page) } self.distanceMeasureInfoWindowController?.reloadData(with: (self.listView.activeAnnotation as! CPDFLineAnnotation).measureInfo!) } else { distanceMeasureInfo?.leadLength = 0 self.listView.distanceMeasureInfo = distanceMeasureInfo self.distanceMeasureInfoWindowController?.reloadData(with: self.listView.distanceMeasureInfo) self.distanceMeasureInfoWindowController?.lengthLabel.stringValue = "" self.distanceMeasureInfoWindowController?.angleLabel.stringValue = "" self.distanceMeasureInfoWindowController?.xLabel.stringValue = "" self.distanceMeasureInfoWindowController?.yLabel.stringValue = "" } if let data = self.listView.activeAnnotation { self.leftSideViewController.refreshUIForAnnoAttributeDidChange(data, attributes: nil) } } self.distanceMeasureInfoWindowController?.showWindow(self) } func distanceSettingWindowController(_ distanceSettingWindowController: CDistanceSettingWindowController, perimeterMeasureInfo: CPDFPerimeterMeasureInfo?) { if perimeterMeasureInfo != nil { if self.listView.activeAnnotations.count > 0 { if self.listView.activeAnnotation.isKind(of: CPDFPolylineAnnotation.self) { (self.listView.activeAnnotation as! CPDFPolylineAnnotation).measureInfo = perimeterMeasureInfo self.listView.setNeedsDisplayAnnotationViewFor(self.listView.activeAnnotation.page) } self.perimeterMeasureInfoWindowController?.reloadData(with: (self.listView.activeAnnotation as! CPDFPolylineAnnotation).measureInfo!) } else { self.listView.perimeterMeasureInfo = perimeterMeasureInfo self.perimeterMeasureInfoWindowController?.reloadData(with: self.listView.perimeterMeasureInfo) self.perimeterMeasureInfoWindowController?.lengthLabel.stringValue = "" self.perimeterMeasureInfoWindowController?.angleLabel.stringValue = "" } if let data = self.listView.activeAnnotation { self.leftSideViewController.refreshUIForAnnoAttributeDidChange(data, attributes: nil) } } self.perimeterMeasureInfoWindowController?.showWindow(self) } } // MARK: CAreaSettingWindowControllerDelegate extension KMMainViewController : CAreaSettingWindowControllerDelegate { func areaSettingWindowController(_ areaSettingWindowController: CAreaSettingWindowController, measureInfo: CPDFAreaMeasureInfo?) { if self.listView.annotationType == .square && self.listView.toolMode == .measureToolMode { if measureInfo != nil { if self.listView.activeAnnotations.count > 0 { if self.listView.activeAnnotation.isKind(of: CPDFPolygonAnnotation.self) { (self.listView.activeAnnotation as! CPDFPolygonAnnotation).measureInfo = measureInfo self.listView.setNeedsDisplayAnnotationViewFor(self.listView.activeAnnotation.page) } self.areaMeasureInfoWindowController?.reloadData((self.listView.activeAnnotation as! CPDFPolygonAnnotation).measureInfo!) } else { self.listView.squareAreaMeasureInfo = measureInfo self.areaMeasureInfoWindowController?.reloadData(self.listView.squareAreaMeasureInfo) self.areaMeasureInfoWindowController?.areaLabel.stringValue = "" self.areaMeasureInfoWindowController?.angleLabel.stringValue = "" } } self.areaMeasureInfoWindowController?.showWindow(self) } else if self.listView.annotationType == .polyGon && self.listView.toolMode == .measureToolMode { if measureInfo != nil { if self.listView.activeAnnotations.count > 0 { if self.listView.activeAnnotation.isKind(of: CPDFPolygonAnnotation.self) { (self.listView.activeAnnotation as! CPDFPolygonAnnotation).measureInfo = measureInfo self.listView.setNeedsDisplayAnnotationViewFor(self.listView.activeAnnotation.page) } self.areaMeasureInfoWindowController?.reloadData((self.listView.activeAnnotation as! CPDFPolygonAnnotation).measureInfo!) } else { self.listView.polygonAreaMeasureInfo = measureInfo self.areaMeasureInfoWindowController?.reloadData(self.listView.polygonAreaMeasureInfo) self.areaMeasureInfoWindowController?.areaLabel.stringValue = "" self.areaMeasureInfoWindowController?.angleLabel.stringValue = "" } } self.areaMeasureInfoWindowController?.showWindow(self) } else { if measureInfo != nil { if self.listView.activeAnnotations.count > 0 { if self.listView.activeAnnotation.isKind(of: CPDFPolygonAnnotation.self) { (self.listView.activeAnnotation as! CPDFPolygonAnnotation).measureInfo = measureInfo self.listView.setNeedsDisplayAnnotationViewFor(self.listView.activeAnnotation.page) } self.areaMeasureInfoWindowController?.reloadData((self.listView.activeAnnotation as! CPDFPolygonAnnotation).measureInfo!) } } self.areaMeasureInfoWindowController?.showWindow(self) } if measureInfo != nil { if let data = self.listView.activeAnnotation { self.leftSideViewController.refreshUIForAnnoAttributeDidChange(data, attributes: nil) } } } } //MARK: LeftSideViewController extension KMMainViewController { func leftSideViewCancelSelect() { if self.listView.isEditing() == true { 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("取消选中") } } } } } // MARK: - Analytics (埋点) extension KMMainViewController { func trackEvent(toolType type: KMToolbarViewType) -> Void { if (type == .Annatiton) { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn" : "Btn_Tbr_Tools"]) } else if (type == .editPDF) { } else if (type == .Page) { FMTrackEventManager.defaultManager.trackEvent(event: "Tbr", withProperties: ["Tbr_Btn" : "Btn_Tbr_PageEdit"]) } else if (type == .Conversion) { } else if (type == .Tool) { } } 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) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Highlight"]) } else if (type == .underline) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Underline"]) } else if (type == .strikeOut) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Strikethrough"]) } else if (type == .ink) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Freehand"]) } else if (type == .freeText) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_TextBox"]) } else if (type == .anchored) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_AnchoredNote"]) } else if (type == .square) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Rectangle"]) } else if (type == .link) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Link"]) } else if (type == .stamp) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Stamp"]) } else if (type == .signSignature) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Signature"]) } else if (type == .circle) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Oval"]) } else if (type == .arrow) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Arrow"]) } else if (type == .line) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Line"]) } 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) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Image"]) } else if (type == .textField) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_TextField"]) } else if (type == .checkBox) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_CheckBox"]) } else if (type == .radioButton) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_RadioButton"]) } else if (type == .listMenu) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_ListBox"]) } else if (type == .comboBox) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_ComboBox"]) } else if (type == .actionButton) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_Button"]) } else if (type == .actionButton) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_Button"]) } else if (type == .signature) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Form", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Form_Signature"]) } else if (type == .squiggly) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Squiglly"]) } else if (type == .eraser) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Tools_Erasder"]) } } 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) } else if mode == .measureToolMode { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn" : "Btn_SubTbr_Editor_Measure"]) } } func trackEvent(toolBarType type: KMToolbarType) -> Void { if (type == .word) { } else if (type == .excel) { } else if (type == .ppt) { } else if (type == .rtf) { } else if (type == .csv) { } else if (type == .html) { } else if (type == .conversion_text) { } else if (type == .conversion_image) { } else if (type == .compress) { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Editor", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Editor_Compress"]) } else if (type == .merge) { } else if (type == .secure) { } else if (type == .crop) { } else if type == .json { FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Converter", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Converter_ToOthers_ToJson"]) } } 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) } func trackEvent_replace() -> Void { self.trackEvent(eventName: "Tbr", params: ["Tbr_Btn" : "Btn_Tbr_ReplaceText"], platform: .AppCenter) } } extension KMMainViewController { //文件对比 func openContentCompareVC(with pdfCompareContent: CPDFCompareContent?, results: [CPDFCompareResults], oldDocument: CPDFDocument, document: CPDFDocument) { self.isCompareModel = true let compareContentView = KMCompareContentView() compareContentView.oldDocument = oldDocument compareContentView.document = document compareContentView.compareResults = results compareContentView.saveHandle = { [unowned self] view in DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) { [unowned self] in let saveController = KMCompareSaveWindow(windowNibName: "KMCompareSaveWindow") self.currentWindowController = saveController saveController.cancelHandle = { [unowned self] controller in self.view.window!.endSheet(controller.window!) self.currentWindowController = nil } saveController.saveHandle = { [unowned self] controller, saveType in let folderPath = controller.fileSaveFolderPath if folderPath != nil { if !FileManager.default.fileExists(atPath: folderPath) { try? FileManager.default.createDirectory(atPath: folderPath, withIntermediateDirectories: true, attributes: nil) } #if VERSION_DMG #else let url = URL(fileURLWithPath: folderPath) let fileAccess = AppSandboxFileAccess() fileAccess?.persistPermissionURL(url) if let bookmarkData = try?url.bookmarkData(options: [.withSecurityScope]) { fileAccess?.bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, for: url) let urlString = url.path let _url = URL(fileURLWithPath: urlString) fileAccess?.bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, for: _url) } #endif var savePath: String switch saveType { case 0: let filePath = oldDocument.documentURL.path let fileName = filePath.deletingPathExtension.lastPathComponent savePath = "\(folderPath)/\(fileName)_compare\(filePath.extension)" savePath = self.getValidFilePath(savePath) oldDocument.write(to: URL(fileURLWithPath: savePath)) NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: savePath)]) case 1: let filePath = document.documentURL.path let fileName = filePath.deletingPathExtension.lastPathComponent savePath = "\(folderPath)/\(fileName)_compare\(filePath.extension)" savePath = self.getValidFilePath(savePath) document.write(to: URL(fileURLWithPath: savePath)) NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: savePath)]) case 2: let filePath = oldDocument.documentURL.path let fileName = filePath.deletingPathExtension.lastPathComponent savePath = "\(folderPath)/MergedCompareFile\(filePath.extension)" savePath = self.getValidFilePath(savePath) pdfCompareContent!.saveAsComparisonDocument(withFilePath: savePath) NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: savePath)]) default: break } } self.view.window!.endSheet(controller.window!) self.currentWindowController = nil } NSWindow.currentWindow().beginSheet(saveController.window!) } } compareContentView.closeHandle = { [unowned self] view in self.isCompareModel = false view.removeFromSuperview() } compareContentView.autoresizingMask = [.width,.height] } func openCoveringCompareVC(with pdfDocument: CPDFDocument) { self.isCompareModel = true let coveringView = KMCompareCoveringView() coveringView.pdfDocument = pdfDocument coveringView.closeHandle = { [unowned self] view in self.isCompareModel = false view.removeFromSuperview() } coveringView.saveHandle = { [unowned self] view in let savePanel = NSSavePanel() savePanel.nameFieldStringValue = "untitled" savePanel.allowedFileTypes = ["pdf"] savePanel.beginSheetModal(for: NSWindow.currentWindow()) { result in if result == .OK { pdfDocument.write(to: savePanel.url!) NSWorkspace.shared.activateFileViewerSelecting([savePanel.url!]) } } } coveringView.autoresizingMask = [.width,.height] } func getValidFilePath(_ oldPath: String) -> String { let fileManager = FileManager.default do { let fileAttributes = try fileManager.attributesOfItem(atPath: oldPath) guard let fileType = fileAttributes[FileAttributeKey.type] as? String else { return oldPath } var i = 1 var newPath = oldPath while fileManager.fileExists(atPath: newPath) { if fileType == FileAttributeType.typeDirectory.rawValue { newPath = oldPath + "(\(i))" } else { let fileExtension = (oldPath as NSString).pathExtension newPath = ((oldPath as NSString).deletingPathExtension as NSString).appendingFormat("(\(i)).\(fileExtension)" as NSString) as String } i += 1 } return newPath } catch { print("Error getting file attributes: \(error)") return oldPath } } } extension KMMainViewController { func documentAllowsEdit() -> Bool { if (self.listView.document.allowsCopying == false || self.listView.document.allowsPrinting == false) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() return false } else { return true } } func changeFont(_ sender: NSFontManager) { KMPrint("changeFont ...") if ((self.listView.activeAnnotation?.isKind(of: CPDFFreeTextAnnotation.self)) != nil) { let annotation: CPDFFreeTextAnnotation = self.listView.activeAnnotation as! CPDFFreeTextAnnotation var font = NSFont(name: annotation.fontName() ?? "Helvetica", size: (annotation.fontSize()) ) font = sender.convert(font!) annotation.fontSize = font?.pointSize ?? 12 self.listView.commitEditAnnotationFreeText(annotation) self.listView.setNeedsDisplay(annotation) } } func currentSetup() -> [String: Any] { var setup: [String: Any] = [:] var point = NSZeroPoint if listView == nil { return setup } let pageIndex = listView.currentPageIndexAndPoint(&point, rotated: nil) setup[kWindowFrameKey] = NSStringFromRect(mainWindow?.frame ?? NSZeroRect) setup[KMMainModel.Key.kLeftSidePaneWidth] = self.model.lastLeftPanWidth setup[KMMainModel.Key.kRightSidePaneWidth] = self.model.lastRightPanWidth setup[KMMainModel.Key.pageIndex] = pageIndex return setup } // MARK: - Recommond活动 func loadRecommondPopWindow() { if IAPProductsManager.default().isAvailableAllFunction() { return } if let info = KMAdvertisementManager.manager.info.popWindowContent?.content?.first { if recommondPopWindowVC == nil { recommondPopWindowVC = KMRecommondPopWindow.default() } recommondPopWindowVC?.recommondInfo = info guard let windowFrame = self.view.window?.frame, let popWindowFrame = recommondPopWindowVC?.window?.frame else { return } let x = windowFrame.minX + (windowFrame.size.width - popWindowFrame.size.width) / 2.0 let y = windowFrame.minY + (windowFrame.size.height - popWindowFrame.size.height) / 2.0 recommondPopWindowVC?.window?.setFrame(NSRect(x: x, y: y, width: popWindowFrame.size.width, height: popWindowFrame.size.height), display: true) recommondPopWindowVC?.window?.orderFront((Any).self) recommondPopWindowVC?.window?.becomeMain() UserDefaults.standard.set("Show", forKey: info.version ?? "") UserDefaults.standard.synchronize() } } @objc func didAddContentViewNotification(_ sender: Notification) { guard let win = sender.object as? NSWindow, win.isEqual(to: self.view.window) else { return } if self.interactionMode == .presentation { } } @objc func purchaseStateUpdateNoti() { if IAPProductsManager.default().isAvailableAllFunction() { } } //!!!: - CPDFFreeTextAnnotation 空注释时会删除,删除时sdk内部删除的,只能接受通知来刷选UI【正常的注释删除会走两遍】 @objc func didRemoveAnnotationNotification(_ sender: Notification) { guard let anno = sender.object as? CPDFAnnotation else { return } if anno.page?.document != self.listView.document { return } self.leftSideViewController.annoList_refreshUIForDeleteAnnotations(annos: [anno], page: anno.page) } // MARK: Split View func changePDFDocument(isChange: Bool, replaceBlock: @escaping (String) -> Void) { let openPanel = NSOpenPanel() openPanel.allowedFileTypes = ["pdf", "PDF"] openPanel.allowsMultipleSelection = false guard let mainWindow = NSApp.mainWindow else { return } openPanel.beginSheetModal(for: mainWindow) { [weak self] response in if response == NSApplication.ModalResponse.OK { guard let url = openPanel.url else { return } if let document = CPDFDocument(url: url) { replaceBlock(document.documentURL?.path ?? "") } else { 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() } } } } }