KMNHomeViewController.swift 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. //
  2. // KMNHomeViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by Niehaoyu on 2024/10/8.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. class KMNHomeViewController: KMNBaseViewController {
  10. @IBOutlet var leftContendBox: NSBox!
  11. @IBOutlet var leftDivider: ComponentDivider!
  12. @IBOutlet var homeOpenView: KMHomeOpenView!
  13. @IBOutlet var homeRecommondView: KMHomeRecommondView!
  14. @IBOutlet var rightContendBox: NSBox!
  15. @IBOutlet var rightInfoView: KMHomeRightView!
  16. @IBOutlet var homeDragView: KMHomeDragView!
  17. var demoVC: WCCompWindowController = WCCompWindowController(windowNibName: "WCCompWindowController")
  18. var createWC: KMURLCreatePDFWindowController = KMURLCreatePDFWindowController(windowNibName: "KMURLCreatePDFWindowController")
  19. var currentWindowController: NSWindowController?
  20. var currentController: NSWindowController?
  21. //合并
  22. var mergeWindowController: KMMergeWindowController?
  23. var extrackWindowController: KMExtractWindowController?
  24. override func viewDidLoad() {
  25. super.viewDidLoad()
  26. // Do view setup here.
  27. self.configLeftContendView()
  28. self.configRightContendView()
  29. self.initAdvertisementData()
  30. homeDragView.delegate = self
  31. }
  32. override func viewDidAppear() {
  33. super.viewDidAppear()
  34. rightInfoView.resetScrollerStyle()
  35. rightInfoView.reloadData()
  36. }
  37. override func updateUIThemeColor() {
  38. super.updateUIThemeColor()
  39. leftContendBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle")
  40. rightContendBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-low")
  41. }
  42. func configLeftContendView() {
  43. leftDivider.properties = ComponentDividerProperty(type: .vertical, dash: false)
  44. homeOpenView.delegate = self
  45. self.homeRecommondView.reloadData()
  46. }
  47. func configRightContendView() {
  48. rightInfoView.delegate = self
  49. rightInfoView.reloadData()
  50. }
  51. func initAdvertisementData() {
  52. KMAdvertisementManager.manager.fetchDataWithResponseObject { [weak self] data, responseObject, error in
  53. KMPrint("获取广告数据成功")
  54. if data != nil {
  55. let content = data!.recommondContent
  56. let item = content?.recommondContentPDFPro
  57. var infos: [KMAdvertisementItemInfo] = []
  58. for info in item?.content ?? [] {
  59. if info.version == "recommondPDF-PDFtoOfficePack" {
  60. if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() == false {
  61. infos.append(info)
  62. }
  63. } else {
  64. infos.append(info)
  65. }
  66. }
  67. item?.content = infos
  68. if KMAdvertisementManager.manager.infoDict.allKeys.count > 0 {
  69. if let adsInfo = KMAdvertisementManager.manager.infoDict["adsInfo"] {
  70. let infoDict: NSDictionary = KMAdvertisementManager.manager.infoDict["adsInfo"] as! NSDictionary
  71. let array: [[String: Any]] = infoDict["content"] as! [[String : Any]]
  72. let arrM = NSMutableArray.init()
  73. for dict in array {
  74. let adsInfo = KMAdsInfo.init()
  75. let mutableDictionary = NSMutableDictionary(dictionary: dict)
  76. adsInfo.infoDict = mutableDictionary
  77. arrM.add(adsInfo)
  78. }
  79. KMAdsInfoManager.shareInstance.adsInfoArrM = arrM
  80. }
  81. if let couponInfo = KMAdvertisementManager.manager.infoDict["couponContent"] {
  82. let infoDict: NSDictionary = KMAdvertisementManager.manager.infoDict["couponContent"] as! NSDictionary
  83. let array: [[String: Any]] = infoDict["content"] as! [[String : Any]]
  84. if array.isEmpty == false {
  85. let dict = array[0]
  86. let adsInfo = KMCouponInfo.init()
  87. let mutableDictionary = NSMutableDictionary(dictionary: dict)
  88. adsInfo.infoDict = mutableDictionary
  89. KMAdsInfoManager.shareInstance.couponInfo = adsInfo
  90. }
  91. }
  92. }
  93. }
  94. DispatchQueue.main.async {
  95. self?.homeRecommondView.reloadData()
  96. }
  97. }
  98. }
  99. @IBAction func showDemo(_ sender: Any) {
  100. demoVC.window?.center()
  101. demoVC.showWindow(nil)
  102. }
  103. func loadOpenFileFunctionGuide(_ showType: KMGuideInfoType) -> Void {
  104. if showType == .messageDiscount && KMGuideInfoWindowController.availableShow(.messageDiscount) {
  105. let guideInfoWindowController = KMGuideInfoWindowController.currentWC()
  106. guideInfoWindowController.type = .messageDiscount
  107. let winC = self.view.window?.windowController as? KMBrowserWindowController
  108. guard let item = winC?.rightMessageVC.discountItemView, item.isHidden == false else {
  109. return
  110. }
  111. guard let win = self.view.window else {
  112. return
  113. }
  114. guideInfoWindowController.targetRect = (win.contentView?.convert(item.frame, from: item.superview)) ?? .zero
  115. guideInfoWindowController.finishHandle = { [weak self] winC, type in
  116. if type == .getIt {
  117. // self?.showAITypeChooseView(aiConfigType: .none)
  118. return
  119. }
  120. }
  121. guideInfoWindowController.autoClose = true
  122. guideInfoWindowController.autoCloseTimeInterval = 5
  123. guideInfoWindowController.window?.collectionBehavior = [.canJoinAllSpaces]
  124. var rect = self.view.window!.frame
  125. rect.size.height += 20
  126. guideInfoWindowController.window?.setFrame(rect, display: false)
  127. guideInfoWindowController.window?.minSize = rect.size
  128. guideInfoWindowController.window?.maxSize = rect.size
  129. self.view.window?.addChildWindow(guideInfoWindowController.window!, ordered: .above)
  130. guideInfoWindowController.show()
  131. }
  132. }
  133. override func keyDown(with event: NSEvent) {
  134. let command = event.modifierFlags.contains(.command)
  135. let control = event.modifierFlags.contains(.control)
  136. let shift = event.modifierFlags.contains(.shift)
  137. let option = event.modifierFlags.contains(.option)
  138. if let _windowC = NSApp.mainWindow?.windowController as? KMBrowserWindowController {
  139. if command && event.keyCode == 17 {
  140. //新标签
  141. // _windowC.openDocumentWindow()
  142. } else {
  143. super.keyDown(with: event)
  144. }
  145. } else {
  146. super.keyDown(with: event)
  147. }
  148. }
  149. }
  150. //MARK: - KMHomeOpenViewDelegate
  151. extension KMNHomeViewController: KMHomeOpenViewDelegate {
  152. func homeOpenViewDidChooseFileURL(_ view: KMHomeOpenView?, _ url: URL) {
  153. self.openFile(withFilePath: url)
  154. }
  155. }
  156. //MARK: - KMHomeRightViewDelegate
  157. extension KMNHomeViewController: KMHomeRightViewDelegate {
  158. //点击管理快捷工具按钮
  159. func homeRightViewDidManageQuickTools(_ view: KMHomeRightView) {
  160. let quickToolWindowController: KMNQuickToolWindowController = KMNQuickToolWindowController.init(windowNibName: "KMNQuickToolWindowController")
  161. quickToolWindowController.delegate = self
  162. quickToolWindowController.own_beginSheetModal(for: self.view.window) { string in
  163. }
  164. }
  165. //点击快捷工具列表中的某一项
  166. func homeRightViewDidQuickToolsItemClicked(_ view: KMHomeRightView, _ toolType: HomeQuickToolType) {
  167. self.quickToolsActionWith(toolType)
  168. }
  169. //最近文件列表删除更新结束后回调
  170. func homeRightViewDidRecentFilesUpdated(_ view: KMHomeRightView) {
  171. }
  172. //选择打开文件
  173. func homeRightViewDidChooseFileToOpen(_ view: KMHomeRightView, _ fileURL: URL) {
  174. self.openFile(withFilePath: fileURL)
  175. }
  176. }
  177. //MARK: - KMNQuickToolWindowDelegate
  178. extension KMNHomeViewController: KMNQuickToolWindowDelegate {
  179. func quickToolWindowControllerUpdate() {
  180. rightInfoView.reloadData()
  181. }
  182. }
  183. //MARK: - KMHomeDragViewDelegate
  184. extension KMNHomeViewController: KMHomeDragViewDelegate {
  185. func homeDragView(_ viewController: KMHomeDragView, filePath: URL) {
  186. self.openFile(withFilePath: filePath)
  187. }
  188. func homeDragView(_ viewController: KMHomeDragView, notSupport: Bool) {
  189. if notSupport {
  190. let alert = NSAlert()
  191. alert.alertStyle = .critical
  192. alert.messageText = KMLocalizedString("This file format is not supported. Please enter PDF, picture, or Office file")
  193. alert.runModal()
  194. }
  195. }
  196. }
  197. //MARK: - Open Files
  198. extension KMNHomeViewController {
  199. func openFile(withFilePath path: URL) -> Void {
  200. if let _windowC = NSApp.mainWindow?.windowController as? KMBrowserWindowController {
  201. _windowC.openFile(withFilePath: path)
  202. } else {
  203. for window in NSApp.windows {
  204. if let browseWindow = window as? KMBrowserWindow {
  205. if let browseWC = browseWindow.windowController as? KMBrowserWindowController {
  206. browseWC.openFile(withFilePath: path)
  207. break
  208. }
  209. }
  210. }
  211. }
  212. }
  213. func openImageToPdfWindow(urls: Array<URL>) {
  214. if let _windowC = NSApp.mainWindow?.windowController as? KMBrowserWindowController {
  215. _windowC.showBatchWindow(type: .imageToPDF, files: urls)
  216. } else {
  217. for window in NSApp.windows {
  218. if let browseWindow = window as? KMBrowserWindow {
  219. if let browseWC = browseWindow.windowController as? KMBrowserWindowController {
  220. browseWC.showBatchWindow(type: .imageToPDF, files: urls)
  221. break
  222. }
  223. }
  224. }
  225. }
  226. }
  227. func showLimitWindowAlert(url: URL?) {
  228. if !KMDataManager.default.isTabbingWin{
  229. KMDataManager.default.isTabbingWin = true
  230. let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController()
  231. tabbingWin.selectCallBack = {[weak self] continueOrNot in
  232. KMDataManager.default.isTabbingWin = false
  233. if continueOrNot {
  234. self?.reopenDocument(forPaths: url)
  235. } else {
  236. }
  237. }
  238. self.km_beginSheet(windowC: tabbingWin)
  239. }
  240. }
  241. func reopenDocument(forPaths path: URL?) -> Void {
  242. if path == nil {
  243. let browser = KMBrowser.init() as KMBrowser
  244. browser.windowController = KMBrowserWindowController.init(browser: browser)
  245. browser.addHomeTabContents()
  246. browser.windowController.showWindow(self)
  247. }else {
  248. let browser = KMBrowser.init() as KMBrowser
  249. browser.windowController = KMBrowserWindowController.init(browser: browser)
  250. browser.addHomeTabContents()
  251. browser.windowController.showWindow(self)
  252. NSDocumentController.shared.km_safe_openDocument(withContentsOf: path!, display: true) { doc, open, err in
  253. }
  254. }
  255. }
  256. func fetchUniquePath(_ originalPath: String) -> String {
  257. var path = originalPath
  258. let dManager = FileManager.default
  259. if !dManager.fileExists(atPath: path) {
  260. if path.extension.count < 1 {
  261. path = path.stringByAppendingPathExtension("pdf")
  262. }
  263. return path
  264. } else {
  265. let originalFullFileName = path.lastPathComponent
  266. let originalFileName = path.lastPathComponent.deletingPathExtension.lastPathComponent
  267. let originalExtension = path.extension
  268. let startIndex: Int = 0
  269. let endIndex: Int = startIndex + originalPath.count - originalFullFileName.count - 1
  270. let fileLocatePath = originalPath.substring(to: endIndex)
  271. var i = 1
  272. while (1 != 0) {
  273. var newName = String(format: "%@%ld", originalFileName, i)
  274. newName = String(format: "%@%@", newName, originalExtension)
  275. let newPath = fileLocatePath.stringByAppendingPathComponent(newName)
  276. if !dManager.fileExists(atPath: newPath) {
  277. return newPath
  278. } else {
  279. i+=1
  280. continue
  281. }
  282. }
  283. }
  284. }
  285. func fetchDifferentFilePath(filePath: String) -> String {
  286. var resultFilePath = filePath
  287. var index: Int = 0
  288. while (FileManager.default.fileExists(atPath: resultFilePath)) {
  289. index += 1
  290. let path = NSString(string: filePath).deletingPathExtension + "(" + String(index) + ")"
  291. resultFilePath = NSString(string: path).appendingPathExtension(NSString(string: filePath).pathExtension)!
  292. }
  293. return resultFilePath;
  294. }
  295. func isDamageImage(image: NSImage?, path: String) -> Bool {
  296. if (image == nil) {
  297. return true
  298. }
  299. let addImageAnnotation = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).last!.appendingPathComponent(Bundle.main.bundleIdentifier!).appendingPathComponent("addImageAnnotation")
  300. if !FileManager.default.fileExists(atPath: addImageAnnotation.path) {
  301. try? FileManager.default.createDirectory(atPath: addImageAnnotation.path, withIntermediateDirectories: false, attributes: nil)
  302. }
  303. guard let data = image!.tiffRepresentation else { return false }
  304. guard let imageRep = NSBitmapImageRep(data: data) else { return false }
  305. imageRep.size = image!.size
  306. var imageData: Data?
  307. if path.lowercased() == "png" {
  308. imageData = imageRep.representation(using: .png, properties: [:])
  309. } else {
  310. imageData = imageRep.representation(using: .jpeg, properties: [:])
  311. }
  312. let rPath: URL = addImageAnnotation.appendingPathComponent(tagString()).appendingPathExtension("png")
  313. if let data = imageData {
  314. try?data.write(to: rPath)
  315. return false
  316. } else {
  317. return true
  318. }
  319. }
  320. func tagString() -> String {
  321. let dateFormatter = DateFormatter()
  322. dateFormatter.dateFormat = "yyMMddHHmmss"
  323. let currentDate = Date()
  324. let randomNum = Int(arc4random_uniform(10000))
  325. let str = String(format: "%@%04d", dateFormatter.string(from: Date()),randomNum)
  326. return str
  327. }
  328. func convertTIFFDataToPDF(_ tiffData: Data) -> Data? {
  329. guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil }
  330. let pdfData = NSMutableData(capacity: tiffData.count)
  331. let consumer = CGDataConsumer(data: pdfData! as CFMutableData)!
  332. var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height))
  333. let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil)
  334. ctxt!.beginPDFPage(nil)
  335. ctxt!.draw(cgImage, in: rect)
  336. ctxt!.endPDFPage()
  337. ctxt!.closePDF()
  338. return pdfData as? Data
  339. }
  340. }
  341. //MARK: - Quick Tools Action
  342. extension KMNHomeViewController {
  343. func quickToolsActionWith(_ type: HomeQuickToolType) {
  344. switch type {
  345. case .Batch:
  346. fastTool_Batch()
  347. break
  348. case .MergePDF:
  349. fastTool_MergePDF()
  350. break
  351. case .ImageToPDF:
  352. imageToPDFAction()
  353. break
  354. case .OCR:
  355. fastTool_OCR()
  356. break
  357. case .ConvertPDF:
  358. fastTool_ConvertPDF()
  359. break
  360. case .PDFToWord:
  361. fastTool_ConvertPDF()
  362. break
  363. case .PDFToExcel:
  364. fastTool_PDFToExcel()
  365. break
  366. case .Compression:
  367. fastTool_Compression()
  368. break
  369. case .PDFToPPT:
  370. fastTool_PDFToPPT()
  371. break
  372. case .Security:
  373. fastTool_Security()
  374. break
  375. case .FileCompare:
  376. fastTool_FileCompare()
  377. break
  378. case .Watermark:
  379. fastTool_Watermark()
  380. break
  381. case .Insert:
  382. fastTool_Insert()
  383. break
  384. case .Extract:
  385. fastTool_Extract()
  386. break
  387. case .DigitalSignature:
  388. break
  389. case .Print:
  390. fastTool_Print()
  391. break
  392. }
  393. }
  394. func imageToPDFAction() {
  395. let openPanel = NSOpenPanel()
  396. openPanel.allowedFileTypes = KMBatchManager.supportedImageTypes()
  397. //MARK: 允许多选还是单选,如果是付费用户允许多选
  398. openPanel.allowsMultipleSelection = true
  399. openPanel.message = KMLocalizedString("Select images to create a new document. To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "")
  400. if KMMemberInfo.shared.isLogin == true {
  401. openPanel.allowsMultipleSelection = true
  402. } else {
  403. openPanel.allowsMultipleSelection = false
  404. }
  405. openPanel.beginSheetModal(for: NSWindow.currentWindow()) {[weak self] result in
  406. if result == NSApplication.ModalResponse.OK {
  407. guard let weakSelf = self else { return }
  408. let urls = openPanel.urls as [URL]
  409. weakSelf.openImageToPdfWindow(urls: urls)
  410. }
  411. }
  412. }
  413. func fastTool_Batch() { // Batch
  414. if KMMemberInfo.shared.isLogin == false {
  415. KMLoginWindowsController.shared.showWindow(nil)
  416. return
  417. }
  418. let batchWindowController = KMBatchWindowController.manager
  419. batchWindowController.type = .convertPDF
  420. batchWindowController.inputData = []
  421. batchWindowController.window?.makeKeyAndOrderFront("")
  422. }
  423. func fastTool_MergePDF() { // MergePDF
  424. mergeWindowController = KMMergeWindowController(windowNibName: "KMMergeWindowController")
  425. mergeWindowController!.type = .merge
  426. mergeWindowController!.cancelAction = { [unowned self] controller in
  427. self.view.window?.endSheet((self.mergeWindowController!.window)!)
  428. }
  429. view.window?.beginSheet(mergeWindowController!.window!)
  430. }
  431. func fastTool_OCR() { // OCR
  432. let openPanel = NSOpenPanel()
  433. var arr = KMBatchManager.supportedImageTypes()
  434. arr.append("pdf")
  435. openPanel.allowedFileTypes = arr
  436. openPanel.allowsMultipleSelection = false
  437. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  438. if result == NSApplication.ModalResponse.OK {
  439. quickOcr(urls: openPanel.urls)
  440. }
  441. }
  442. }
  443. func quickOcr(urls: Array<URL>) {
  444. showBatchWindow(type: .OCR, files: urls)
  445. }
  446. func fastTool_ConvertPDF() { // 转换PDF
  447. let openPanel = NSOpenPanel()
  448. var arr = KMBatchManager.supportedImageTypes()
  449. arr.append("pdf")
  450. openPanel.allowedFileTypes = ["pdf","PDF"]
  451. //MARK: 允许多选还是单选,如果是付费用户允许多选
  452. openPanel.allowsMultipleSelection = false
  453. openPanel.beginSheetModal(for: self.view.window!) { [self] (result) in
  454. if result == NSApplication.ModalResponse.OK {
  455. quickConvertPdf(urls: openPanel.urls, type: .WordAdvance)
  456. }
  457. }
  458. }
  459. func quickConvertPdf(urls: Array<URL>, type: KMConvertWithPDFType) {
  460. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  461. self.showBatchWindow(type: .convertPDF, subType: type.rawValue,files: urls)
  462. }
  463. }
  464. func fastTool_PDFToPPT() {
  465. let openPanel = NSOpenPanel()
  466. openPanel.allowedFileTypes = ["pdf","PDF"]
  467. //MARK: 允许多选还是单选,如果是付费用户允许多选
  468. openPanel.allowsMultipleSelection = false
  469. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  470. if result == NSApplication.ModalResponse.OK {
  471. quickConvertPdf(urls: openPanel.urls, type: .PowerPoint)
  472. }
  473. }
  474. }
  475. func fastTool_PDFToExcel() {
  476. let openPanel = NSOpenPanel()
  477. openPanel.allowedFileTypes = ["pdf","PDF"]
  478. //MARK: 允许多选还是单选,如果是付费用户允许多选
  479. openPanel.allowsMultipleSelection = false
  480. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  481. if result == NSApplication.ModalResponse.OK {
  482. quickConvertPdf(urls: openPanel.urls, type: .Excel)
  483. }
  484. }
  485. }
  486. // 压缩
  487. func fastTool_Compression() {
  488. let openPanel = NSOpenPanel()
  489. openPanel.allowedFileTypes = ["pdf","PDF"]
  490. //MARK: 允许多选还是单选,如果是付费用户允许多选
  491. openPanel.allowsMultipleSelection = false
  492. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  493. if result == NSApplication.ModalResponse.OK {
  494. quickCompressPdf(urls: openPanel.urls)
  495. }
  496. }
  497. }
  498. func quickCompressPdf(urls: Array<URL>) {
  499. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  500. self.showBatchWindow(type: .compress, files: urls)
  501. }
  502. }
  503. // 安全
  504. func fastTool_Security() {
  505. let openPanel = NSOpenPanel()
  506. openPanel.allowedFileTypes = ["pdf","PDF"]
  507. //MARK: 允许多选还是单选,如果是付费用户允许多选
  508. openPanel.allowsMultipleSelection = true
  509. openPanel.message = KMLocalizedString("To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "")
  510. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  511. if result == NSApplication.ModalResponse.OK {
  512. quickPassword(urls: openPanel.urls)
  513. }
  514. }
  515. }
  516. func quickPassword(urls: Array<URL>) {
  517. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  518. self.showBatchWindow(type: .security, files: urls)
  519. }
  520. }
  521. func fastTool_FileCompare() { // 文件对比
  522. let openPanel = NSOpenPanel()
  523. openPanel.allowsMultipleSelection = false
  524. openPanel.allowedFileTypes = ["pdf"]
  525. openPanel.beginSheetModal(for: NSApp.mainWindow!) { result in
  526. if result == .cancel {
  527. return
  528. }
  529. if !openPanel.url!.path.isPDFValid() {
  530. let alert = NSAlert()
  531. alert.alertStyle = .critical
  532. alert.messageText = KMLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  533. alert.runModal()
  534. return
  535. }
  536. NSWindowController.checkPassword(url: URL(fileURLWithPath: openPanel.url!.path), type: .owner) { [unowned self] success, resultPassword in
  537. if success {
  538. DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
  539. let controller = KMCompareWindowController(windowNibName: "KMCompareWindowController")
  540. controller.password = resultPassword
  541. controller.filePath = openPanel.url!.path
  542. controller.cancelAction = { [unowned self] contr in
  543. self.view.window?.endSheet((controller.window)!)
  544. }
  545. controller.contentComplete = { [unowned self] controller, pdfCompareContent, result, oldDocument, document in
  546. self.view.window?.endSheet((controller.window)!)
  547. self.openContentCompareVC(with: pdfCompareContent, results: result, oldDocument: oldDocument, document: document)
  548. }
  549. controller.coveringComplete = { [unowned self] controller, document in
  550. self.openCoveringCompareVC(with: document)
  551. self.view.window?.endSheet((controller.window)!)
  552. }
  553. controller.fileType = .content
  554. NSWindow.currentWindow().beginSheet(controller.window!)
  555. }
  556. } else {
  557. }
  558. }
  559. }
  560. }
  561. func fastTool_Watermark() { // 水印
  562. let openPanel = NSOpenPanel()
  563. openPanel.allowedFileTypes = ["pdf","PDF"]
  564. //MARK: 允许多选还是单选,如果是付费用户允许多选
  565. openPanel.allowsMultipleSelection = false
  566. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  567. if result == NSApplication.ModalResponse.OK {
  568. quickWaterMark(urls: openPanel.urls)
  569. }
  570. }
  571. }
  572. func quickWaterMark(urls: Array<URL>) {
  573. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  574. self.showBatchWindow(type: .watermark, files: urls)
  575. }
  576. }
  577. func fastTool_Background() { // 背景
  578. let openPanel = NSOpenPanel()
  579. openPanel.allowedFileTypes = ["pdf","PDF"]
  580. //MARK: 允许多选还是单选,如果是付费用户允许多选
  581. openPanel.allowsMultipleSelection = false
  582. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  583. if result == NSApplication.ModalResponse.OK {
  584. quickBackgroudMark(urls: openPanel.urls)
  585. }
  586. }
  587. }
  588. func quickBackgroudMark(urls: Array<URL>) {
  589. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  590. self.showBatchWindow(type: .background, files: urls)
  591. }
  592. }
  593. //MARK: 打印
  594. func fastTool_Print() {
  595. let openPanel = NSOpenPanel()
  596. openPanel.allowedFileTypes = ["pdf","PDF"]
  597. openPanel.allowsMultipleSelection = false
  598. openPanel.beginSheetModal(for: NSWindow.currentWindow()) { [self] (result) in
  599. if result == NSApplication.ModalResponse.OK {
  600. if let url = openPanel.url {
  601. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  602. self.showPrintWindowWithURL(url)
  603. }
  604. }
  605. }
  606. }
  607. }
  608. func showPrintWindowWithURL(_ url: URL) {
  609. if let cPDFDocument = CPDFDocument(url: url) {
  610. KMPrintWindowController.openDocument(inputDocument: cPDFDocument, inputPageRange: KMPrintPageRange(type: .allPage, selectPages: []))
  611. }
  612. }
  613. func fastTool_Insert() { // 插入
  614. let openPanel = NSOpenPanel()
  615. openPanel.prompt = KMLocalizedString("Insert", comment: "")
  616. openPanel.allowsMultipleSelection = false
  617. openPanel.allowedFileTypes = ["pdf"]
  618. openPanel.beginSheetModal(for: NSApp.mainWindow!) { result in
  619. if result == .OK {
  620. let windowC = KMPDFInsertWindowController(fileURL: openPanel.url!)
  621. windowC.callback = { [weak self] idx, params in
  622. if params.count >= 4 {
  623. if let doc = params.first as? CPDFDocument {
  624. self?.savePDFDocument(doc, password: params[1] as? String ?? "")
  625. }
  626. }
  627. windowC.own_closeEndSheet()
  628. }
  629. windowC.own_beginSheetModal(for: self.view.window) { result in
  630. }
  631. }
  632. }
  633. }
  634. func savePDFDocument(_ pdf: CPDFDocument, password: String) -> Void {
  635. DispatchQueue.global(qos: .`default`).async {
  636. var isSuccessfully = false
  637. if pdf.isEncrypted {
  638. let dic = [
  639. CPDFDocumentWriteOption.userPasswordOption : password,
  640. CPDFDocumentWriteOption.ownerPasswordOption : password
  641. ]
  642. isSuccessfully = pdf.write(to: pdf.documentURL, withOptions: dic)
  643. } else {
  644. isSuccessfully = pdf.write(to: pdf.documentURL)
  645. }
  646. if !isSuccessfully {
  647. if let data = pdf.dataRepresentation() {
  648. isSuccessfully = NSData(data: data).write(to: pdf.documentURL, atomically: true)
  649. }
  650. }
  651. DispatchQueue.main.sync {
  652. if isSuccessfully {
  653. let workspace = NSWorkspace.shared
  654. let url = URL(fileURLWithPath: pdf.documentURL?.path ?? "")
  655. workspace.activateFileViewerSelecting([url])
  656. } else {
  657. let alert = NSAlert()
  658. alert.alertStyle = .critical
  659. alert.messageText = KMLocalizedString("Failed to insert page(s)!", comment: "")
  660. alert.runModal()
  661. }
  662. }
  663. }
  664. }
  665. func fastTool_Extract() { // 提取
  666. let openPanel = NSOpenPanel()
  667. openPanel.prompt = "提取"
  668. openPanel.allowsMultipleSelection = false
  669. openPanel.allowedFileTypes = ["pdf"]
  670. openPanel.beginSheetModal(for: NSApp.mainWindow!) { result in
  671. if result == .OK {
  672. DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
  673. if self.extrackWindowController == nil {
  674. self.extrackWindowController = KMExtractWindowController(windowNibName: "KMExtractWindowController")
  675. }
  676. self.extrackWindowController?.fileURL = openPanel.url
  677. self.extrackWindowController?.own_beginSheetModal(for: self.view.window, completionHandler: { result in
  678. })
  679. }
  680. }
  681. }
  682. }
  683. func extractPageAction(_ pdfDocument: CPDFDocument, _ pages: [CPDFPage], _ oneDocumentPerPage: Bool, _ isDeletePage: Bool) -> Void {
  684. if pages.count < 1 {
  685. let alert = NSAlert()
  686. alert.alertStyle = .critical
  687. alert.messageText = KMLocalizedString("Please select two or more pages first to organize.", comment: "")
  688. alert.runModal()
  689. return
  690. }
  691. if !oneDocumentPerPage {
  692. let fileName = pdfDocument.getFileNameAccordingSelctPages(pages)
  693. let outputSavePanel = NSSavePanel()
  694. outputSavePanel.allowedFileTypes = ["pdf"]
  695. outputSavePanel.nameFieldStringValue = fileName
  696. outputSavePanel.beginSheetModal(for: self.view.window!) { result in
  697. if result == .OK {
  698. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
  699. let saveFilePath = outputSavePanel.url?.path
  700. DispatchQueue.global().async {
  701. let pdf = CPDFDocument.init()
  702. let success = (pdf!.extractAsOneDocument(withPages: pages, savePath: saveFilePath)) as Bool
  703. DispatchQueue.main.async {
  704. if success {
  705. let workspace = NSWorkspace.shared
  706. let url = URL(fileURLWithPath: saveFilePath!)
  707. workspace.activateFileViewerSelecting([url])
  708. if isDeletePage {
  709. for page in pages {
  710. let indexPage = pdfDocument.index(for: page)
  711. pdfDocument.removePage(at: indexPage)
  712. }
  713. }
  714. }
  715. }
  716. }
  717. }
  718. }
  719. }
  720. } else {
  721. let panel = NSOpenPanel()
  722. panel.canChooseFiles = false
  723. panel.canChooseDirectories = true
  724. panel.canCreateDirectories = true
  725. panel.allowsMultipleSelection = false
  726. panel.beginSheetModal(for: self.view.window!) { result in
  727. if result == .OK {
  728. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
  729. let outputURL = panel.url
  730. DispatchQueue.global().async {
  731. let folderName = String(pdfDocument.documentURL!.lastPathComponent.split(separator: ".")[0]) + "_extract"
  732. var filePath = URL(fileURLWithPath: outputURL!.path).appendingPathComponent(folderName).path
  733. var i = 1
  734. let testFilePath = filePath
  735. while FileManager.default.fileExists(atPath: filePath) {
  736. filePath = testFilePath + "\(i)"
  737. i += 1
  738. }
  739. try? FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: false, attributes: nil)
  740. let successArray = pdfDocument.extractPerPageDocument(withPages: pages, folerPath: filePath)
  741. DispatchQueue.main.async {
  742. if successArray!.count > 0 {
  743. NSWorkspace.shared.activateFileViewerSelecting(successArray!)
  744. if !isDeletePage {
  745. for page in pages {
  746. let indexPage = pdfDocument.index(for: page)
  747. pdfDocument.removePage(at: indexPage)
  748. }
  749. }
  750. }
  751. }
  752. }
  753. }
  754. }
  755. }
  756. }
  757. }
  758. //MARK: Batch
  759. func showBatchWindow(type: KMBatchCollectionViewType, subType: Int = 0, files: [URL]?) {
  760. let batchWindowController = KMBatchWindowController.manager
  761. batchWindowController.window?.makeKeyAndOrderFront("")
  762. // var datas: [KMBatchProcessingTableViewModel] = []
  763. // for file in files! {
  764. // let data = KMBatchProcessingTableViewModel.initWithFilePath(url: file)
  765. // datas.append(data)
  766. // }
  767. batchWindowController.inputData = files ?? []
  768. batchWindowController.type = type
  769. batchWindowController.inputSubType = subType
  770. }
  771. }
  772. extension KMNHomeViewController {
  773. //文件对比
  774. func openContentCompareVC(with pdfCompareContent: CPDFCompareContent?, results: [CPDFCompareResults], oldDocument: CPDFDocument, document: CPDFDocument) {
  775. let compareContentController = KMCompareContentWindowController(document: document, oldDocument: oldDocument, results: results)
  776. self.currentController = compareContentController
  777. compareContentController.saveHandle = { [unowned self] view in
  778. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) { [unowned self] in
  779. let saveController = KMCompareSaveWindow(windowNibName: "KMCompareSaveWindow")
  780. self.currentWindowController = saveController
  781. let window = NSWindow.currentWindow()
  782. window.beginSheet(saveController.window!)
  783. saveController.cancelHandle = { [weak self] controller in
  784. window.endSheet(saveController.window!)
  785. self?.currentWindowController = nil
  786. }
  787. saveController.saveHandle = { [unowned self] controller, saveType in
  788. let folderPath = controller.fileSaveFolderPath
  789. if folderPath != nil {
  790. if !FileManager.default.fileExists(atPath: folderPath) {
  791. try? FileManager.default.createDirectory(atPath: folderPath, withIntermediateDirectories: true, attributes: nil)
  792. }
  793. var savePath: String
  794. #if VERSION_DMG
  795. #else
  796. let url = URL(fileURLWithPath: folderPath)
  797. let fileAccess = AppSandboxFileAccess()
  798. fileAccess?.persistPermissionURL(url)
  799. if let bookmarkData = try?url.bookmarkData(options: [.withSecurityScope]) {
  800. fileAccess?.bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, for: url)
  801. let urlString = url.path
  802. let _url = URL(fileURLWithPath: urlString)
  803. fileAccess?.bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, for: _url)
  804. }
  805. #endif
  806. switch saveType {
  807. case 0:
  808. let filePath = oldDocument.documentURL.path
  809. let fileName = filePath.deletingPathExtension.lastPathComponent
  810. savePath = "\(folderPath)/\(fileName)_compare\(filePath.extension)"
  811. savePath = self.getValidFilePath(savePath)
  812. oldDocument.write(to: URL(fileURLWithPath: savePath))
  813. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: savePath)])
  814. case 1:
  815. let filePath = document.documentURL.path
  816. let fileName = filePath.deletingPathExtension.lastPathComponent
  817. savePath = "\(folderPath)/\(fileName)_compare\(filePath.extension)"
  818. savePath = self.getValidFilePath(savePath)
  819. document.write(to: URL(fileURLWithPath: savePath))
  820. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: savePath)])
  821. case 2:
  822. let filePath = oldDocument.documentURL.path
  823. let fileName = filePath.deletingPathExtension.lastPathComponent
  824. savePath = "\(folderPath)/MergedCompareFile\(filePath.extension)"
  825. savePath = self.getValidFilePath(savePath)
  826. pdfCompareContent!.saveAsComparisonDocument(withFilePath: savePath)
  827. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: savePath)])
  828. default:
  829. break
  830. }
  831. }
  832. window.endSheet(saveController.window!)
  833. self.currentWindowController = nil
  834. }
  835. }
  836. }
  837. compareContentController.closeHandle = { [weak self] controller in
  838. self?.view.window?.endSheet(controller.window!)
  839. self?.currentController = nil
  840. }
  841. self.view.window?.beginSheet(compareContentController.window!)
  842. }
  843. func getValidFilePath(_ oldPath: String) -> String {
  844. let fileManager = FileManager.default
  845. do {
  846. let fileAttributes = try fileManager.attributesOfItem(atPath: oldPath)
  847. guard let fileType = fileAttributes[FileAttributeKey.type] as? String else {
  848. return oldPath
  849. }
  850. var i = 1
  851. var newPath = oldPath
  852. while fileManager.fileExists(atPath: newPath) {
  853. if fileType == FileAttributeType.typeDirectory.rawValue {
  854. newPath = oldPath + "(\(i))"
  855. } else {
  856. let fileExtension = (oldPath as NSString).pathExtension
  857. newPath = ((oldPath as NSString).deletingPathExtension as NSString).appendingFormat("(\(i)).\(fileExtension)" as NSString) as String
  858. }
  859. i += 1
  860. }
  861. return newPath
  862. } catch {
  863. print("Error getting file attributes: \(error)")
  864. return oldPath
  865. }
  866. }
  867. func openCoveringCompareVC(with pdfDocument: CPDFDocument) {
  868. let controller = KMCompareCoveringWindowController(document: pdfDocument)
  869. self.currentController = controller
  870. controller.closeHandle = { [weak self] controller in
  871. self?.view.window?.endSheet(controller.window!)
  872. self?.currentController = nil
  873. }
  874. controller.saveHandle = { [weak self] controller in
  875. let savePanel = NSSavePanel()
  876. savePanel.nameFieldStringValue = "untitled"
  877. savePanel.allowedFileTypes = ["pdf"]
  878. savePanel.beginSheetModal(for: NSWindow.currentWindow()) { result in
  879. if result == .OK {
  880. pdfDocument.write(to: savePanel.url!)
  881. NSWorkspace.shared.activateFileViewerSelecting([savePanel.url!])
  882. }
  883. }
  884. }
  885. self.view.window?.beginSheet(controller.window!)
  886. }
  887. }