KMMainViewController+Action.swift 38 KB

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