KMMainViewController+Action.swift 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. //
  2. // KMMainViewController+Action.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2022/12/15.
  6. //
  7. import Foundation
  8. extension KMMainViewController {
  9. func search(searchString: String, isCase: Bool, display: Bool = true, needShowAll: Bool = false) {
  10. }
  11. func removeSignatures(signatures:[CPDFSignature]) {
  12. for signature in signatures {
  13. self.listView.document.removeSignature(signature)
  14. }
  15. for i in 0..<self.listView.document.pageCount {
  16. guard let page = self.listView.document.page(at: i) else {
  17. continue
  18. }
  19. let annotations : [CPDFAnnotation] = page.annotations
  20. for j in 0..<annotations.count {
  21. let annotation = annotations[j]
  22. if annotation is CPDFSignatureWidgetAnnotation {
  23. (annotation as! CPDFSignatureWidgetAnnotation).updateAppearanceStream()
  24. }
  25. }
  26. }
  27. self.listView.setNeedsDisplayForVisiblePages()
  28. let tSignatures : [CPDFSignature] = self.listView.document.signatures()
  29. var mSignatures : [CPDFSignature] = []
  30. for sign in tSignatures {
  31. if sign.signers.count > 0 {
  32. mSignatures.append(sign)
  33. }
  34. }
  35. }
  36. func numberOfChars(_ str: String) -> (num: Int, indexN: Int) {
  37. var number = 0
  38. var indexN = 0
  39. guard str.count > 0 else {return (0, 0)}
  40. for i in 0...str.count - 1 {
  41. let c: unichar = (str as NSString).character(at: i)
  42. if (c >= 0x4E00) {
  43. number += 2
  44. }else {
  45. number += 1
  46. }
  47. if number > 56{
  48. indexN = i
  49. number = 100
  50. break
  51. }
  52. }
  53. return (number, indexN)
  54. }
  55. func fontSizes()->NSArray {
  56. return ["6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "24", "36", "48", "72", "96", "144", "288"]
  57. }
  58. func handleRightMouseDown(theEvent: NSEvent) -> Bool {
  59. if interactionMode == .presentation {
  60. listView.goToPreviousPage(nil)
  61. return true
  62. }
  63. return false
  64. }
  65. func useNativeFullScreen() -> Bool {
  66. var isFull = false
  67. let sel = NSSelectorFromString("toggleFullscreen:")
  68. if NSWindow.instancesRespond(to: sel) && UserDefaults.standard.bool(forKey: "SKUseLegacyFullScreenKey"){
  69. isFull = true
  70. }
  71. return isFull
  72. }
  73. func forceSubwindowsOnTop(_ flag: Bool) {
  74. }
  75. //MARK: menuItem Action
  76. @objc func menuItemEditingClick_FontColor(sender: NSMenuItem) {
  77. let color = listView.editingSelectionFontColor()
  78. let panel = NSColorPanel.shared
  79. panel.setTarget(self)
  80. panel.setAction(#selector(fontColorChangeAction))
  81. panel.orderFront(nil)
  82. panel.showsAlpha = false
  83. panel.color = color ?? NSColor.black
  84. }
  85. @objc func fontColorChangeAction(sender: NSColorPanel) {
  86. self.listView.setEditingSelectionFontColor(sender.color)
  87. }
  88. @objc func menuItemEditingClick_FontSize(sender: NSMenuItem) {
  89. let fontSize = self.fontSizes().object(at: sender.tag)
  90. self.listView.setEditingSelectionFontSize(CGFloat(Int(fontSize as! String)!))
  91. }
  92. @objc func addImageText(sender: NSMenuItem) {
  93. let event = NSApp.currentEvent
  94. let clickLocation = event?.locationInWindow
  95. var point = self.listView.convert(clickLocation!, from: NSApp.mainWindow?.contentView)
  96. var point2 = self.listView.convert(point, to: self.listView.currentPage())
  97. point2 = CGPoint(x: self.listView.bounds.width - point2.x, y: self.listView.bounds.height - point2.y)
  98. point = point2
  99. if sender.tag == 0 {
  100. KMPrint("添加文字")
  101. } else if sender.tag == 1 {
  102. } else if sender.tag == 2 {
  103. KMPrint("粘贴")
  104. }
  105. }
  106. @objc func menuItemEditingClick_CropImage(sender: NSMenuItem) {
  107. if self.listView.cropAreas != nil && self.listView.selectImageAreas != nil{
  108. self.listView.cropEditImageArea(self.listView.selectImageAreas, withBounds: self.listView.cropAreas.cropRect)
  109. }
  110. }
  111. @objc func menuItemAnnotationClick_toolModel(sender: NSMenuItem) {
  112. }
  113. @objc func changeAnnotationMode_itemAction(sender : NSMenuItem) {
  114. }
  115. @objc func menuItemAnnotationClick_add(sender : NSMenuItem) {
  116. var annotationType : CAnnotationType = .unkown
  117. switch sender.tag {
  118. case 0:
  119. annotationType = .highlight
  120. case 1:
  121. annotationType = .underline
  122. case 2:
  123. if sender.title == NSLocalizedString("Squiggly", comment: "") {
  124. annotationType = .squiggly
  125. } else {
  126. annotationType = .strikeOut
  127. }
  128. case 3:
  129. annotationType = .freeText
  130. case 4:
  131. annotationType = .anchored
  132. case 5:
  133. annotationType = .square
  134. case 6:
  135. annotationType = .circle
  136. case 7:
  137. annotationType = .line
  138. case 8:
  139. annotationType = .link
  140. case 9:
  141. return
  142. case 10:
  143. annotationType = .unkown
  144. default:
  145. break
  146. }
  147. if (annotationType != .link) {
  148. self.listView.addAnnotation(with: annotationType, selection: self.listView.currentSelection, page: self.listView.currentSelection.page, bounds: self.listView.currentSelection.bounds)
  149. self.listView.currentSelection = nil;
  150. return
  151. }
  152. // link
  153. let selection = self.listView.currentSelection
  154. DispatchQueue.main.async {
  155. Task { @MainActor in
  156. let annotation = self.listView.addAnnotation(with: annotationType, selection: selection, page: selection?.page, bounds: selection!.bounds)
  157. self.listView.currentSelection = nil;
  158. if (annotation != nil) {
  159. self.listView.updateActiveAnnotations([annotation!])
  160. }
  161. }
  162. }
  163. }
  164. @objc func menuItemAnnotationClick_addStype(sender: NSMenuItem) {
  165. Task { @MainActor in
  166. let idx = sender.tag
  167. if idx == 10 {
  168. if IAPProductsManager.default().isAvailableAllFunction() == false {
  169. KMPurchaseCompareWindowController.sharedInstance().showWindow(nil)
  170. return
  171. }
  172. }
  173. var point = mouseRightMenuEvent?.locationInWindow
  174. if (point == nil) {
  175. point = NSZeroPoint
  176. }
  177. let currentPoint: NSPoint = self.listView.convert(point!, from: self.listView.superview)
  178. let currentPage = self.listView.page(for: currentPoint, nearest: true)
  179. var pagePoint = self.listView.convert(currentPoint, to: currentPage)
  180. var annotation: CPDFAnnotation?
  181. if viewManager.isPDFReadMode {
  182. if (sender.tag == 0 || sender.tag == 7 || sender.tag == 8 || sender.tag == 9) { // Ink & Link & stamp & sign
  183. self.listView.toolMode = .CNoteToolMode
  184. }
  185. switch sender.tag {
  186. case 0:
  187. self.listView.annotationType = CAnnotationType.ink
  188. case 1:
  189. let defaultSize = self.listView.defaultSize(with: .freeText, in: currentPage)
  190. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  191. annotation = self.listView.addAnnotation(with: .freeText, selection: nil, page: currentPage, bounds: bounds)
  192. if ((annotation) != nil) {
  193. self.listView.updateActiveAnnotations([annotation!])
  194. self.listView.edit(annotation)
  195. }
  196. case 2:
  197. let defaultSize = self.listView.defaultSize(with: .anchored, in: currentPage)
  198. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  199. annotation = self.listView.addAnnotation(with: .anchored, selection: nil, page: currentPage, bounds: bounds)
  200. self.listView.edit(annotation)
  201. case 3:
  202. let defaultSize = self.listView.defaultSize(with: .square, in: currentPage)
  203. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  204. annotation = self.listView.addAnnotation(with: .square, selection: nil, page: currentPage, bounds: bounds)
  205. case 4:
  206. let defaultSize = self.listView.defaultSize(with: .circle, in: currentPage)
  207. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  208. annotation = self.listView.addAnnotation(with: .circle, selection: nil, page: currentPage, bounds: bounds)
  209. case 5:
  210. let defaultSize = self.listView.defaultSize(with: .arrow, in: currentPage)
  211. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  212. annotation = self.listView.addAnnotation(with: .arrow, selection: nil, page: currentPage, bounds: bounds)
  213. case 6:
  214. let defaultSize = self.listView.defaultSize(with: .line, in: currentPage)
  215. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  216. annotation = self.listView.addAnnotation(with: .line, selection: nil, page: currentPage, bounds: bounds)
  217. case 7:
  218. self.listView.annotationType = CAnnotationType.link
  219. toggleOpenRightSide()
  220. case 8:
  221. self.listView.annotationType = CAnnotationType.stamp
  222. toggleOpenRightSide()
  223. case 9:
  224. self.listView.annotationType = CAnnotationType.signSignature
  225. toggleOpenRightSide()
  226. default:
  227. break
  228. }
  229. } else {
  230. if (sender.tag == 7 || sender.tag == 8 || sender.tag == 9) { // Ink & Link & stamp & sign
  231. self.listView.toolMode = .CNoteToolMode
  232. }
  233. switch sender.tag {
  234. case 0:
  235. self.listView.toolMode = .CNoteToolMode
  236. self.listView.annotationType = CAnnotationType.ink
  237. case 1:
  238. let defaultSize = self.listView.defaultSize(with: .freeText, in: currentPage)
  239. if (pagePoint.x - defaultSize.width > 0){
  240. pagePoint.x -= defaultSize.width;
  241. }else{
  242. pagePoint.x = 0;
  243. }
  244. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  245. annotation = self.listView.addAnnotation(with: .freeText, selection: nil, page: currentPage, bounds: bounds)
  246. if ((annotation) != nil) {
  247. self.listView.edit(annotation)
  248. }
  249. case 2:
  250. let defaultSize = self.listView.defaultSize(with: .anchored, in: currentPage)
  251. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  252. annotation = self.listView.addAnnotation(with: .anchored, selection: nil, page: currentPage, bounds: bounds)
  253. self.listView.edit(annotation)
  254. case 3:
  255. let defaultSize = self.listView.defaultSize(with: .square, in: currentPage)
  256. if (pagePoint.x - defaultSize.width > 0){
  257. pagePoint.x -= defaultSize.width;
  258. }else{
  259. pagePoint.x = 0;
  260. }
  261. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  262. annotation = self.listView.addAnnotation(with: .square, selection: nil, page: currentPage, bounds: bounds)
  263. case 4:
  264. let defaultSize = self.listView.defaultSize(with: .circle, in: currentPage)
  265. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  266. annotation = self.listView.addAnnotation(with: .circle, selection: nil, page: currentPage, bounds: bounds)
  267. case 5:
  268. let defaultSize = self.listView.defaultSize(with: .arrow, in: currentPage)
  269. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  270. annotation = self.listView.addAnnotation(with: .arrow, selection: nil, page: currentPage, bounds: bounds)
  271. case 6:
  272. let defaultSize = self.listView.defaultSize(with: .line, in: currentPage)
  273. let bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize)
  274. annotation = self.listView.addAnnotation(with: .line, selection: nil, page: currentPage, bounds: bounds)
  275. case 7:
  276. self.listView.annotationType = CAnnotationType.link
  277. toggleOpenRightSide()
  278. case 8:
  279. self.listView.annotationType = CAnnotationType.stamp
  280. toggleOpenRightSide()
  281. case 9:
  282. self.listView.annotationType = CAnnotationType.signSignature
  283. toggleOpenRightSide()
  284. case 10:
  285. self.addImgAnnotationToView(center: pagePoint)
  286. default:
  287. break
  288. }
  289. if annotation != nil{
  290. self.listView.activeAnnotations.removeAllObjects()
  291. var newAnnonations : [CPDFAnnotation] = []
  292. newAnnonations.append(annotation!)
  293. self.listView.updateActiveAnnotations(newAnnonations)
  294. }
  295. }
  296. }
  297. }
  298. func addImgAnnotationToView(center: NSPoint) {
  299. let accessoryCtr = KMImageAccessoryController()
  300. let openPanel = NSOpenPanel()
  301. openPanel.allowedFileTypes = KMImageAccessoryController.supportedImageTypes()
  302. openPanel.allowsMultipleSelection = false
  303. openPanel.accessoryView = accessoryCtr.view
  304. openPanel.isAccessoryViewDisclosed = true
  305. openPanel.beginSheetModal(for: self.view.window!) { result in
  306. if result == .OK {
  307. let fileURL = openPanel.urls.first
  308. let filePath = fileURL!.path
  309. if filePath.pathExtension == "pdf" {
  310. let pdf = CPDFDocument(url: fileURL)
  311. if pdf!.isEncrypted {
  312. NSSound.beep()
  313. return
  314. }
  315. }
  316. let img = NSImage(contentsOfFile: filePath)
  317. let isRemoveBGColor = accessoryCtr.selectedButton.state == .on
  318. self.listView.addImageAnnotation(img, center: center, isRemoveBGColor: isRemoveBGColor)
  319. }
  320. }
  321. }
  322. // MARK: - Measure
  323. @objc func menuItemActionMeasureProperty(sender: NSMenuItem) {
  324. guard let anno = sender.representedObject as? CPDFAnnotation else {
  325. return
  326. }
  327. if distanceMeasureInfoWindowController?.window?.isVisible == true {
  328. distanceMeasureInfoWindowController?.hideFloatingWindow()
  329. } else if perimeterMeasureInfoWindowController?.window?.isVisible == true {
  330. perimeterMeasureInfoWindowController?.hideFloatingWindow()
  331. } else if areaMeasureInfoWindowController?.window?.isVisible == true {
  332. areaMeasureInfoWindowController?.hideFloatingWindow()
  333. }
  334. self.listView.updateActiveAnnotations([anno])
  335. self.pdfListViewChangeatioActiveAnnotations(self.listView, forActiveAnnotations: [anno], isRightMenu: false)
  336. self.listView.setNeedsDisplayForVisiblePages()
  337. }
  338. @objc func menuItemActionMeasureEditNote(sender: NSMenuItem) {
  339. guard let anno = sender.representedObject as? CPDFAnnotation else {
  340. return
  341. }
  342. self.listView.edit(anno)
  343. }
  344. @objc func menuItemActionMeasureSetting(sender: NSMenuItem) {
  345. guard let anno = sender.representedObject as? CPDFAnnotation else {
  346. return
  347. }
  348. self.listView.updateActiveAnnotations([anno])
  349. self.listView.setNeedsDisplayForVisiblePages()
  350. if let data = anno as? CPDFLineAnnotation, data.isMeasure {
  351. self.showMeasureDistanceSettingWindow(measureInfo: data.measureInfo)
  352. } else if let data = anno as? CPDFPolylineAnnotation {
  353. self.showMeasurePerimeterSettingWindow(measureInfo: data.measureInfo)
  354. } else if let data = anno as? CPDFPolygonAnnotation {
  355. self.showMeasureAreaSettingWindow(measureInfo: data.measureInfo)
  356. }
  357. }
  358. @objc func menuItemActionMeasureDelete(sender: NSMenuItem) {
  359. guard let anno = sender.representedObject as? CPDFAnnotation else {
  360. return
  361. }
  362. self.listView.remove(anno)
  363. }
  364. func showMeasureDistanceSettingWindow(measureInfo: CPDFDistanceMeasureInfo?, hideInfoWindow: Bool = true) {
  365. guard let mInfo = measureInfo else {
  366. return
  367. }
  368. }
  369. func showMeasurePerimeterSettingWindow(measureInfo: CPDFPerimeterMeasureInfo?, hideInfoWindow: Bool = true) {
  370. guard let mInfo = measureInfo else {
  371. return
  372. }
  373. }
  374. func showMeasureAreaSettingWindow(measureInfo: CPDFAreaMeasureInfo?, hideInfoWindow: Bool = true) {
  375. guard let mInfo = measureInfo else {
  376. return
  377. }
  378. }
  379. // MARK: - 幻灯片
  380. func fadeInFullScreenWindow(with backgroundColor: NSColor, level: Int) {
  381. let view: NSView = self.view.window!.firstResponder as! NSView
  382. if view.isDescendant(of: pdfSplitView){
  383. self.view.window?.makeFirstResponder(nil)
  384. }
  385. self.mainWindow = self.view.window
  386. let fullScreenWindow = KMFullScreenWindow(screen: (self.mainWindow?.screen ?? NSScreen.main)!, bgColor: backgroundColor, level: NSWindow.Level.popUpMenu.rawValue, isMain: true)
  387. fullScreenWindow.interactionParent = self.view.window
  388. self.mainWindow?.delegate = nil
  389. fullScreenWindow.fadeInBlocking()
  390. self.browserWindowController?.window = fullScreenWindow
  391. fullScreenWindow.makeKey()
  392. let sel = NSSelectorFromString("setAnimationBehavior:")
  393. if self.mainWindow?.responds(to: sel) ?? false{
  394. self.mainWindow?.animationBehavior = .none
  395. }
  396. self.mainWindow?.orderOut(nil)
  397. if self.mainWindow?.responds(to: sel) ?? false{
  398. self.mainWindow?.animationBehavior = .default
  399. }
  400. fullScreenWindow.level = NSWindow.Level(rawValue: level)
  401. fullScreenWindow.orderFront(nil)
  402. }
  403. func fadeInFullScreenView(_ view: NSView, inset: CGFloat) {
  404. guard let fullScreenWindow = self.browserWindowController?.window as? KMFullScreenWindow else {
  405. return
  406. }
  407. let fadeWindow = KMFullScreenWindow(screen: fullScreenWindow.screen!, bgColor: fullScreenWindow.backgroundColor, level: fullScreenWindow.level.rawValue, isMain: false)
  408. fadeWindow.order(.above, relativeTo: fullScreenWindow.windowNumber)
  409. view.frame = NSInsetRect(fullScreenWindow.contentView?.bounds ?? .zero, inset, 0)
  410. fullScreenWindow.contentView?.addSubview(view)
  411. self.listView.layoutDocumentView()
  412. self.listView.requiresDisplay()
  413. fullScreenWindow.makeFirstResponder(self.listView)
  414. fullScreenWindow.recalculateKeyViewLoop()
  415. fullScreenWindow.delegate = self.browserWindowController
  416. fullScreenWindow.display()
  417. fadeWindow.fadeOut()
  418. }
  419. @IBAction func doZoomToAutoSelection(sender:NSMenuItem) {
  420. let rect = listView.currentSelectionRect()
  421. let page = listView.currentPage()
  422. if NSIsEmptyRect(rect) == false && page != nil {
  423. let isLegacy = NSScroller.responds(to: NSSelectorFromString("preferredScrollerStyle")) == false || NSScroller.preferredScrollerStyle == .legacy
  424. var bounds = listView.bounds
  425. var scale = 1.0
  426. if isLegacy {
  427. bounds.size.width -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle)
  428. bounds.size.height -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle)
  429. }
  430. if NSWidth(bounds) * NSHeight(rect) > NSWidth(rect) * NSHeight(bounds) {
  431. scale = NSHeight(bounds) / NSHeight(rect)
  432. } else {
  433. scale = NSWidth(bounds) / NSWidth(rect)
  434. }
  435. listView.setScaleFactor(scale, animated: false)
  436. let scrollView = listView.scroll()
  437. if isLegacy && scrollView?.hasHorizontalScroller == false || scrollView?.hasVerticalScroller == false {
  438. if ((scrollView?.hasVerticalScroller) != nil) {
  439. bounds.size.width -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle)
  440. }
  441. if ((scrollView?.hasHorizontalScroller) != nil) {
  442. bounds.size.height -= NSScroller.scrollerWidth(for: .regular, scrollerStyle: listView.documentView().scrollerStyle)
  443. }
  444. if NSWidth(bounds) * NSHeight(rect) > NSWidth(rect) * NSHeight(bounds) {
  445. scale = NSHeight(bounds) / NSHeight(rect)
  446. } else {
  447. scale = NSWidth(bounds) / NSWidth(rect)
  448. }
  449. listView.setScaleFactor(scale, animated: false)
  450. }
  451. DispatchQueue.main.asyncAfter(deadline: .now() + 0.03) { [self] in
  452. let pagePoint = CGPoint(x: rect.origin.x, y: (rect.origin.y + rect.size.height))
  453. listView.go(toTargetPoint: pagePoint, on: page, at: .top)
  454. };
  455. }
  456. // 执行右键操作后,需要取消框选区域
  457. if self.listView.toolMode == .CSelectToolMode {
  458. objc_sync_enter(self)
  459. self.listView.selectionRect = NSZeroRect
  460. self.listView.selectionPageIndex = UInt(NSNotFound)
  461. objc_sync_exit(self)
  462. }
  463. }
  464. //MARK: - action
  465. // 开启左边栏
  466. @objc func openLeftPane() -> Void {
  467. self.model.leftPanelOpen = true
  468. applyLeftSideWidth(self.model.panelWidth+functionWidth, rightSideWidth: self.model.lastRightPanWidth)
  469. }
  470. // 关闭左边栏
  471. @objc func closeLeftPane() -> Void {
  472. self.model.leftPanelOpen = false
  473. applyLeftSideWidth(functionWidth, rightSideWidth: self.model.lastRightPanWidth)
  474. }
  475. func rename(_ sender: NSNotification) -> Void {
  476. if (self.view.window == nil || self.view.window!.isVisible == false) {
  477. return
  478. }
  479. let tabController = sender.object as? CTTabController
  480. if tabController?.title == self.document?.documentURL.deletingPathExtension().lastPathComponent {
  481. if let doc = self.myDocument, doc.isDocumentEdited {
  482. Task {
  483. let resp = await KMAlertTool.runModel(message: NSLocalizedString("File Updated", comment: ""), buttons: [NSLocalizedString("Save", comment: ""), NSLocalizedString("Cancel", comment: "")])
  484. if resp != .alertFirstButtonReturn { // 取消
  485. return
  486. }
  487. doc.updateChangeCount(.changeCleared)
  488. self.document?.write(to: doc.fileURL)
  489. Task { @MainActor in
  490. self._renameForSavePanel(tabController)
  491. }
  492. }
  493. return
  494. }
  495. self._renameForSavePanel(tabController)
  496. }
  497. }
  498. func savePdfAlertView() {
  499. if AutoSaveManager.manager.isSaving || AutoSaveManager.manager.isSaveNoti{
  500. return
  501. }
  502. AutoSaveManager.manager.isSaveNoti = true
  503. var num = 0
  504. if self.listView.document != nil{
  505. num = Int(self.listView.document.pageCount)
  506. }
  507. if Thread.current.isMainThread {
  508. self.beginProgressSheet(withMessage: NSLocalizedString("Saving PDF", comment: "") + "...", maxValue: UInt(num))
  509. } else {
  510. DispatchQueue.main.async {
  511. self.beginProgressSheet(withMessage: NSLocalizedString("Saving PDF", comment: "") + "...", maxValue: UInt(num))
  512. }
  513. }
  514. }
  515. func savePdfFinishAlertView() {
  516. if !AutoSaveManager.manager.isSaveNoti{
  517. return
  518. }
  519. AutoSaveManager.manager.isSaveNoti = false
  520. if Thread.current.isMainThread {
  521. self.dismissProgressSheet()
  522. } else {
  523. DispatchQueue.main.async {
  524. self.dismissProgressSheet()
  525. }
  526. }
  527. }
  528. private func _renameForSavePanel(_ tabC: CTTabController?) {
  529. let outputSavePanel = NSSavePanel()
  530. outputSavePanel.title = NSLocalizedString("Rename", comment: "")
  531. outputSavePanel.allowedFileTypes = ["pdf"]
  532. outputSavePanel.nameFieldStringValue = (self.document?.documentURL.lastPathComponent)!
  533. outputSavePanel.directoryURL = self.document?.documentURL.deletingLastPathComponent()
  534. let resp = outputSavePanel.runModal()
  535. if resp == .OK {
  536. let pdfDocument = CPDFDocument(url: self.document?.documentURL)
  537. let fileURL = pdfDocument?.documentURL
  538. let fileManager = FileManager.default
  539. let newFileURL = fileURL!.deletingLastPathComponent().appendingPathComponent(outputSavePanel.url!.lastPathComponent)
  540. var result = true
  541. do {
  542. try fileManager.moveItem(at: fileURL!, to: newFileURL)
  543. } catch {
  544. result = false
  545. KMPrint("Error renaming file! Threw: \(error.localizedDescription)")
  546. }
  547. if (result) {
  548. tabC?.title = outputSavePanel.url!.lastPathComponent
  549. if let newPdfDocument = CPDFDocument(url: newFileURL) {
  550. self.model.isSaveKeyChain = false
  551. newPdfDocument.unlock(withPassword: self.document?.password)
  552. if (newPdfDocument.pageCount > 0) {
  553. self.setDocument = newPdfDocument
  554. }
  555. }
  556. }
  557. } else {
  558. outputSavePanel.close()
  559. }
  560. }
  561. func showInFinder(_ sender: Any) -> Void {
  562. if sender is NSNotification {
  563. let tabController = (sender as! NSNotification).object as? CTTabController
  564. let path = self.document?.documentURL.deletingPathExtension().lastPathComponent
  565. if tabController?.title == path {
  566. if let file = self.myDocument?.fileURL {
  567. if FileManager.default.fileExists(atPath: file.path) {
  568. NSWorkspace.shared.activateFileViewerSelecting([file])
  569. }
  570. }
  571. }
  572. } else {
  573. guard let url = self.myDocument?.fileURL else { return }
  574. let file: URL = url
  575. if FileManager.default.fileExists(atPath: file.path) {
  576. NSWorkspace.shared.activateFileViewerSelecting([file])
  577. }
  578. }
  579. }
  580. func closeTab(_ sender: NSNotification) -> Void {
  581. }
  582. @IBAction func toggleSplitPDF(_ sender: Any) {
  583. }
  584. // MARK: - 图片注释
  585. @IBAction func imageAnnotation(_ sender: Any) {
  586. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Tools_Image"])
  587. guard IAPProductsManager.default().isAvailableAllFunction() else {
  588. KMPurchaseCompareWindowController.sharedInstance().showWindow(nil)
  589. return
  590. }
  591. let accessoryCtr = KMImageAccessoryController()
  592. let openPanel = NSOpenPanel()
  593. openPanel.allowedFileTypes = KMImageAccessoryController.supportedImageTypes()
  594. openPanel.allowsMultipleSelection = false
  595. openPanel.accessoryView = accessoryCtr.view
  596. openPanel.canSelectHiddenExtension = true
  597. openPanel.beginSheetModal(for: NSApp.mainWindow!) { [self] (result) in
  598. if result == .OK {
  599. guard let url = openPanel.url else {
  600. return
  601. }
  602. let filePath = url.path
  603. if filePath.pathExtension.lowercased() == "pdf" {
  604. if let pdf = PDFDocument(url: url), pdf.isEncrypted {
  605. NSSound.beep()
  606. return
  607. }
  608. }
  609. guard let image = NSImage(contentsOfFile: url.path) else {
  610. let alert = NSAlert()
  611. alert.alertStyle = .critical
  612. alert.messageText = String(format: NSLocalizedString("The file \"%@\" could not be opened.", comment: ""), url.lastPathComponent)
  613. alert.informativeText = NSLocalizedString("It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", comment: "")
  614. alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
  615. alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in
  616. if response == .alertFirstButtonReturn {
  617. // Handle cancel button clicked
  618. }
  619. }
  620. return
  621. }
  622. let isDamageImage: Bool = self.isDamageImage(image, imagePath: url.path)
  623. if isDamageImage {
  624. let alert = NSAlert()
  625. alert.alertStyle = .critical
  626. alert.messageText = String(format: NSLocalizedString("The file \"%@\" could not be opened.", comment: ""), url.lastPathComponent)
  627. alert.informativeText = NSLocalizedString("It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", comment: "")
  628. alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
  629. alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in
  630. if response == .alertFirstButtonReturn {
  631. // Handle cancel button clicked
  632. }
  633. }
  634. return
  635. }
  636. let isRemoveBGColor = accessoryCtr.selectedButton.state == .on
  637. listView.addAnnotation(with: image, isRemoveBGColor: isRemoveBGColor)
  638. if (self.listView.activeAnnotation != nil) && (self.listView.activeAnnotation.type == "Image") {
  639. }
  640. }
  641. }
  642. }
  643. @IBAction func tableAnnotation(_ sender: Any) {
  644. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_Tools", withProperties: ["SubTbr_Btn": "Btn_SubTbr_Tools_Table"])
  645. guard IAPProductsManager.default().isAvailableAllFunction() else {
  646. let winC = KMPurchaseCompareWindowController.sharedInstance()
  647. winC?.kEventName = "Reading_Table_BuyNow"
  648. winC?.showWindow(nil)
  649. return
  650. }
  651. listView.addAnnotationWithTable()
  652. toggleOpenRightSide()
  653. }
  654. func isDamageImage(_ image: NSImage, imagePath path: String) -> Bool {
  655. let addImageAnnotation = (NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last! as NSString).appendingPathComponent(Bundle.main.bundleIdentifier!)
  656. if !FileManager.default.fileExists(atPath: addImageAnnotation) {
  657. try? FileManager.default.createDirectory(atPath: addImageAnnotation, withIntermediateDirectories: false, attributes: nil)
  658. }
  659. if let data = image.tiffRepresentation,
  660. let imageRep = NSBitmapImageRep(data: data) {
  661. imageRep.size = image.size
  662. var imageData: Data?
  663. if path.lowercased() == "png" {
  664. imageData = imageRep.representation(using: .png, properties: [:])
  665. } else {
  666. imageData = imageRep.representation(using: .jpeg, properties: [:])
  667. }
  668. if let imageData = imageData {
  669. let rPath = (addImageAnnotation as NSString).appendingPathComponent((self.tagString() as NSString).appendingPathExtension("png")!)
  670. if !((try? imageData.write(to: URL(fileURLWithPath: rPath), options: .atomicWrite)) != nil) {
  671. return true
  672. } else {
  673. return false
  674. }
  675. }
  676. }
  677. return false
  678. }
  679. func tagString() -> String {
  680. let dateFormatter = DateFormatter()
  681. dateFormatter.dateFormat = "yyMMddHHmmss"
  682. return "\(dateFormatter.string(from: Date()))\(Int.random(in: 0..<10000))"
  683. }
  684. }
  685. extension KMMainViewController {
  686. func changeModelAction(mode: CToolMode) {
  687. self.listView.toolMode = mode
  688. if mode == .CEditPDFToolMode {
  689. }
  690. }
  691. func aiTranslationPDFFileAction() {
  692. self._aiTranslationPDFFileAction()
  693. }
  694. private func _aiTranslationPDFFileAction() {
  695. let isExceedsLimit = self.isPDFPageCountExceedsLimit(filePath: (self.document?.documentURL.path)!)
  696. if KMTools.isFileGreaterThan10MB(atPath: (self.document?.documentURL.path)!) {
  697. let alert = NSAlert()
  698. alert.alertStyle = .critical
  699. alert.messageText = NSLocalizedString("The uploaded file size cannot exceed 10MB", comment: "")
  700. alert.runModal()
  701. return
  702. } else if isExceedsLimit {
  703. let alert = NSAlert()
  704. alert.alertStyle = .critical
  705. alert.messageText = NSLocalizedString("Documents cannot exceed 30 pages", comment: "")
  706. alert.runModal()
  707. return
  708. }
  709. let alert = NSAlert()
  710. alert.messageText = NSLocalizedString("Processing times may be longer for larger documents. Thank you for your patience.", comment: "")
  711. alert.addButton(withTitle: NSLocalizedString("Continue", comment: ""))
  712. alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
  713. alert.beginSheetModal(for: view.window!) { [weak self] result in
  714. if (result == .alertFirstButtonReturn) {
  715. } else if result == .alertSecondButtonReturn {
  716. return
  717. }
  718. }
  719. }
  720. func openNewWindowAlertWindow() {
  721. var needShowChooseWindow = false
  722. //#if VERSION_FREE
  723. if (!IAPProductsManager.default().isAvailableAllFunction()) {
  724. needShowChooseWindow = true
  725. }
  726. //#endif
  727. if needShowChooseWindow {
  728. let preferenceNoteShow = UserDefaults.standard.bool(forKey: KMTabbingHintShowFlag)
  729. if preferenceNoteShow {
  730. } else {
  731. if !KMDataManager.default.isTabbingWin{
  732. KMDataManager.default.isTabbingWin = true
  733. let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController()
  734. tabbingWin.selectCallBack = {[weak self] continueOrNot in
  735. KMDataManager.default.isTabbingWin = false
  736. if continueOrNot {
  737. self?.reopenDocument(forPaths: [])
  738. } else {
  739. }
  740. }
  741. self.km_beginSheet(windowC: tabbingWin)
  742. }
  743. }
  744. }else{
  745. handleTabbingLogic()
  746. }
  747. }
  748. func reopenDocument(forPaths paths: [String]) -> Void {
  749. let browser = KMBrowser.init() as KMBrowser
  750. browser.windowController = KMBrowserWindowController.init(browser: browser)
  751. browser.addHomeTabContents()
  752. browser.windowController.showWindow(self)
  753. }
  754. func handleTabbingLogic() {
  755. self.browserWindowController?.browser?.selectTabContents(at: 0, userGesture: true)
  756. }
  757. }
  758. //MARK: LeftSideViewController
  759. extension KMMainViewController {
  760. func leftSideViewCancelSelect() {
  761. if self.listView.isEditing() == true {
  762. if self.listView.editingAreas() != nil &&
  763. self.listView.editingAreas().count != 0 {
  764. let areas = self.listView.editingAreas().first
  765. if areas is CPDFEditTextArea {
  766. self.listView.clearEditingSelectCharItem()
  767. self.listView.updateEditing([])
  768. KMPrint("取消选中")
  769. }
  770. }
  771. }
  772. }
  773. }
  774. extension KMMainViewController {
  775. func documentAllowsEdit() -> Bool {
  776. if (self.listView.document.allowsCopying == false || self.listView.document.allowsPrinting == false) {
  777. let alert = NSAlert()
  778. alert.alertStyle = .critical
  779. alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "")
  780. alert.runModal()
  781. return false
  782. } else {
  783. return true
  784. }
  785. }
  786. func changeFont(_ sender: NSFontManager) {
  787. KMPrint("changeFont ...")
  788. if ((self.listView.activeAnnotation?.isKind(of: CPDFFreeTextAnnotation.self)) != nil) {
  789. let annotation: CPDFFreeTextAnnotation = self.listView.activeAnnotation as! CPDFFreeTextAnnotation
  790. var font = NSFont(name: annotation.fontName() ?? "Helvetica", size: (annotation.fontSize()) )
  791. font = sender.convert(font!)
  792. annotation.fontSize = font?.pointSize ?? 12
  793. self.listView.commitEditAnnotationFreeText(annotation)
  794. self.listView.setNeedsDisplay(annotation)
  795. }
  796. }
  797. func currentSetup() -> [String: Any] {
  798. var setup: [String: Any] = [:]
  799. var point = NSZeroPoint
  800. if listView == nil {
  801. return setup
  802. }
  803. let pageIndex = listView.currentPageIndexAndPoint(&point, rotated: nil)
  804. setup[kWindowFrameKey] = NSStringFromRect(mainWindow?.frame ?? NSZeroRect)
  805. setup[KMMainModel.Key.kLeftSidePaneWidth] = self.model.lastLeftPanWidth
  806. setup[KMMainModel.Key.kRightSidePaneWidth] = self.model.lastRightPanWidth
  807. setup[KMMainModel.Key.pageIndex] = pageIndex
  808. return setup
  809. }
  810. }