KMBatchOperateAddHeaderFooterViewController.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. //
  2. // KMBatchOperateAddHeaderFooterViewController.swift
  3. // PDF Master
  4. //
  5. // Created by liujiajie on 2023/11/7.
  6. //
  7. import Cocoa
  8. class KMBatchOperateAddHeaderFooterViewController: KMBatchOperateBaseViewController, NSTableViewDelegate,NSTableViewDataSource{
  9. var isBates = false
  10. var onlyManagerTemplate = false
  11. var isBatchOperation = false
  12. var pdfView: PDFView?
  13. @IBOutlet var topBaseView: NSView!
  14. @IBOutlet var bottomBaseView: NSView!
  15. @IBOutlet var tableView: NSTableView!
  16. @IBOutlet var titleLabel: NSTextField!
  17. @IBOutlet var actionButton: NSButton!
  18. @IBOutlet var managerTemplateTitleLabel: NSTextField!
  19. @IBOutlet var addButton: NSButton!
  20. @IBOutlet var blankView: KMBlankView!
  21. @IBOutlet var managerTemplateTopConstraint: NSLayoutConstraint!
  22. @IBOutlet var managerTemplateButtonHeightConstraint: NSButton!
  23. @IBOutlet var topHeightConstraint: NSLayoutConstraint!
  24. var haveFiles = false
  25. var currentObject: KMHeaderFooterObject?
  26. override var interfaceStatus: KMBatchOperateInterfaceStatus?{
  27. set{
  28. super.interfaceStatus = newValue
  29. if newValue == .PrepareProcess {
  30. DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
  31. let files = NSMutableArray()
  32. for url in self.successFilePathURLArray! {
  33. if FileManager.default.fileExists(atPath: url.path) {
  34. files.add(url)
  35. }
  36. }
  37. if files.count > 0 {
  38. let workspace = NSWorkspace.shared
  39. workspace.activateFileViewerSelecting(files as! [URL])
  40. }
  41. }
  42. self.actionButton.tag = 1
  43. self.actionButton.title = KMLocalizedString("Apply", nil)
  44. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color())
  45. } else {
  46. self.actionButton.tag = 0
  47. self.actionButton.title = KMLocalizedString("Cancel", nil)
  48. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color())
  49. }
  50. }
  51. get{
  52. return super.interfaceStatus
  53. }
  54. }
  55. deinit {
  56. NotificationCenter.default.removeObserver(self)
  57. }
  58. override func viewDidLoad() {
  59. super.viewDidLoad()
  60. localizedLanguage()
  61. configuInterface()
  62. NotificationCenter.default.addObserver(self, selector: #selector(headerFootersNotification(notification:)), name: Notification.Name(rawValue: "KMBatchOperateHeaderFootersNotification"), object: nil)
  63. NotificationCenter.default.addObserver(self, selector: #selector(themeChanged(notification:)), name: Notification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil)
  64. NotificationCenter.default.addObserver(self, selector: #selector(batchFilesCountNotification(notification:)), name: NSNotification.Name("KMBatchFilesCountNotification"), object: nil)
  65. }
  66. func localizedLanguage() {
  67. self.addButton.title = KMLocalizedString("Add Template", nil)
  68. self.actionButton.title = KMLocalizedString("Apply", nil)
  69. self.titleLabel.stringValue = KMLocalizedString("Apply", nil)
  70. }
  71. func configuInterface() {
  72. self.titleLabel.font = NSFont.systemFont(ofSize: 14)
  73. self.titleLabel.textColor = KMAppearance.Layout.h0Color()
  74. self.tableView.enclosingScrollView?.borderType = .noBorder
  75. self.actionButton.wantsLayer = true
  76. self.addButton.wantsLayer = true
  77. self.topHeightConstraint.constant = 0
  78. self.topBaseView.isHidden = true
  79. self.addButton.imagePosition = .imageLeft
  80. self.addButton.image = NSImage(named: "KMImageNameHeaderFooterAddBtn")
  81. self.addButton.layer?.backgroundColor = KMAppearance.Interactive.s0Color().cgColor
  82. self.addButton.setTitleColor(KMAppearance.Layout.h0Color())
  83. self.actionButton.layer?.backgroundColor = KMAppearance.Interactive.m0Color().cgColor
  84. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color())
  85. self.actionButton.imagePosition = .noImage
  86. if !self.onlyManagerTemplate {
  87. if self.files?.count ?? 0 > 0 {
  88. self.haveFiles = true
  89. } else {
  90. self.haveFiles = false
  91. }
  92. } else {
  93. self.haveFiles = true
  94. }
  95. updateActionButtonbackgroundColor()
  96. self.addButton.layer?.cornerRadius = 1.0
  97. self.actionButton.layer?.cornerRadius = 1.0
  98. self.topBaseView.wantsLayer = true
  99. self.topBaseView.layer?.backgroundColor = KMAppearance.Layout.l0Color().cgColor
  100. self.bottomBaseView.wantsLayer = true
  101. self.bottomBaseView.layer?.backgroundColor = KMAppearance.Layout.l0Color().cgColor
  102. self.managerTemplateTitleLabel.font = NSFont.systemFont(ofSize: 14)
  103. self.managerTemplateTitleLabel.textColor = KMAppearance.Layout.h0Color()
  104. self.titleLabel.isHidden = false
  105. self.addButton.isHidden = false
  106. self.managerTemplateTitleLabel.isHidden = true
  107. self.managerTemplateTitleLabel.stringValue = NSLocalizedString("Manage Templates", comment: "")
  108. self.view.addSubview(self.blankView)
  109. self.blankView.mas_makeConstraints { make in
  110. make?.top.equalTo()(self.topBaseView.mas_bottom)
  111. make?.left.equalTo()(self.view)
  112. make?.right.equalTo()(self.view)
  113. make?.bottom.equalTo()(self.bottomBaseView.mas_top)
  114. make?.height.greaterThanOrEqualTo()(200)
  115. }
  116. self.blankView.titleLabel.stringValue = KMLocalizedString("No Templates", nil)
  117. self.tableView.backgroundColor = KMAppearance.Layout.l0Color()
  118. let menu = NSMenu(title: "")
  119. if !self.isBatchOperation && !self.isBates {
  120. menu.addItem(withTitle: NSLocalizedString("Batch Add Header & Footer", comment: ""), action: #selector(buttonItemClick_addBatch(_:)), keyEquivalent: "")
  121. } else if !self.isBatchOperation && self.isBates {
  122. menu.addItem(withTitle: NSLocalizedString("Batch Add Bates Numbers", comment: ""), action: #selector(buttonItemClick_addBatch(_:)), keyEquivalent: "")
  123. }
  124. if !self.isBates {
  125. menu.addItem(withTitle: NSLocalizedString("Remove All Header & Footer Templates", comment: ""), action: #selector(buttonItemClick_CleanAll(_:)), keyEquivalent: "")
  126. } else {
  127. menu.addItem(withTitle: NSLocalizedString("Remove All Bates Numbers Templates", comment: ""), action: #selector(buttonItemClick_CleanAll(_:)), keyEquivalent: "")
  128. }
  129. self.view.menu = menu
  130. updateViewColor()
  131. }
  132. func updateActionButtonbackgroundColor() {
  133. let row = self.tableView.selectedRow
  134. if (self.files?.count ?? 0 > 0 || self.pdfView != nil) && row > -1 {
  135. self.actionButton.layer?.backgroundColor = KMAppearance.Interactive.m0Color().cgColor
  136. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color())
  137. } else {
  138. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color().withAlphaComponent(0.6))
  139. self.actionButton.layer?.backgroundColor = KMAppearance.Interactive.m0Color().withAlphaComponent(0.6).cgColor
  140. }
  141. }
  142. @objc func buttonItemClick_addBatch(_ sender: Any) {
  143. let baseWindowController = KMBatchOperateBaseWindowController(windowNibName: "KMBatchOperateBaseWindowController")
  144. if #available(macOS 10.13, *) {
  145. baseWindowController.window?.makeKeyAndOrderFront(nil)
  146. } else {
  147. baseWindowController.showWindow(nil)
  148. }
  149. var arr = NSMutableArray()
  150. let file = KMBatchOperateFile(filePath: self.pdfView!.document!.documentURL!.path, type: self.isBates ? .AddBates : .AddHeaderFooter)
  151. arr.add(file)
  152. baseWindowController.checkNeedPasswordSwitchToOperateType(operateType: self.isBates ? .AddBates : .AddHeaderFooter, files: arr as! [KMBatchOperateFile])
  153. }
  154. @objc func buttonItemClick_CleanAll(_ sender: Any) {
  155. let alert = NSAlert()
  156. alert.alertStyle = .warning
  157. alert.messageText = ""
  158. alert.informativeText = NSLocalizedString("Are you sure to delete all templates?", comment: "")
  159. alert.addButton(withTitle: NSLocalizedString("Delete", comment: ""))
  160. alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
  161. alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in
  162. if response == .alertFirstButtonReturn {
  163. self.deleteAll()
  164. }
  165. }
  166. }
  167. @objc func headerFootersNotification(notification: Notification) {
  168. if let addHeaderFooter = notification.object as? KMBatchOperateAddHeaderFooterViewController {
  169. if self != addHeaderFooter {
  170. loadData()
  171. }
  172. }
  173. }
  174. @objc func themeChanged(notification: Notification) {
  175. DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
  176. self.updateViewColor()
  177. }
  178. }
  179. @objc func batchFilesCountNotification(notification: Notification) {
  180. let files = notification.object as? [Any]
  181. if files?.count ?? 0 > 0 {
  182. haveFiles = true
  183. } else {
  184. haveFiles = false
  185. }
  186. updateActionButtonbackgroundColor()
  187. }
  188. func loadData() {
  189. self.tableView.reloadData()
  190. }
  191. func updateViewColor() {
  192. if KMAppearance.isDarkMode() {
  193. self.bottomBaseView.layer?.backgroundColor = NSColor(red: 0.149, green: 0.157, blue: 0.169, alpha: 1).cgColor
  194. self.addButton.layer?.backgroundColor = NSColor(red: 0.337, green: 0.345, blue: 0.353, alpha: 1).cgColor
  195. self.addButton.setTitleColor(NSColor.white)
  196. self.actionButton.layer?.backgroundColor = NSColor(red: 0.306, green: 0.498, blue: 0.859, alpha: 1).cgColor
  197. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color())
  198. } else {
  199. self.bottomBaseView.layer?.backgroundColor = NSColor(red: 0.988, green: 0.992, blue: 1.000, alpha: 1).cgColor
  200. self.addButton.layer?.backgroundColor = NSColor(red: 0.855, green: 0.859, blue: 0.871, alpha: 1).cgColor
  201. self.addButton.setTitleColor(NSColor(red: 0.055, green: 0.067, blue: 0.078, alpha: 1))
  202. self.actionButton.layer?.backgroundColor = NSColor(red: 0.153, green: 0.235, blue: 0.384, alpha: 1).cgColor
  203. self.actionButton.setTitleColor(KMAppearance.Layout.w0Color())
  204. }
  205. }
  206. func deleteAll() {
  207. if self.isBates {
  208. for waterMark in KMHeaderFooterManager.defaultManager.onlyBatesObjects {
  209. KMHeaderFooterManager.defaultManager.removeHeaderFooter(waterMark)
  210. }
  211. } else {
  212. for waterMark in KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects {
  213. KMHeaderFooterManager.defaultManager.removeHeaderFooter(waterMark)
  214. }
  215. }
  216. loadData()
  217. reloadTable()
  218. postNotification()
  219. }
  220. func reloadTable() {
  221. self.tableView.noteNumberOfRowsChanged()
  222. var count = 0
  223. var array: [KMHeaderFooterObject] = []
  224. if self.isBates {
  225. count = KMHeaderFooterManager.defaultManager.onlyBatesObjects.count
  226. array = KMHeaderFooterManager.defaultManager.onlyBatesObjects
  227. } else {
  228. count = KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects.count
  229. array = KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects
  230. }
  231. if array.contains(self.currentObject!) {
  232. let row = array.firstIndex(of: self.currentObject!)!
  233. let indexSet = IndexSet(integer: row)
  234. self.tableView.selectRowIndexes(indexSet, byExtendingSelection: false)
  235. }
  236. updateActionButtonbackgroundColor()
  237. }
  238. func postNotification() {
  239. NotificationCenter.default.post(name: NSNotification.Name("KMBatchOperateHeaderFootersNotification"), object: self)
  240. }
  241. @IBAction func buttonClicked_AddHeaderFooter(_ sender: Any) {
  242. // guard let windowController = self.view.window?.windowController else { return }
  243. // var filePath: String?
  244. // var password: String?
  245. // if let mainWC = windowController as? MainWindowController {
  246. // // filePath = mainWC.pdfView?.document?.documentURL?.path
  247. // // password = (mainWC.pdfView?.document as? CPDFDocument)?.password
  248. // }
  249. // let wc = KMHeaderFooterManagerWindowController(baseFile: filePath, headerFooter: nil, password: password, type: .KMBatchModifyTemplateType_Add)
  250. // wc.isBates = self.isBates
  251. // wc.operateCallBack = { [weak self] obj in
  252. // self?.currentObject = obj
  253. // self?.loadData()
  254. // self?.postNotification()
  255. // DispatchQueue.main.async {
  256. // guard let strongSelf = self else {
  257. // return
  258. // }
  259. // strongSelf.tableView.selectRowIndexes(IndexSet(integer: 0), byExtendingSelection: false)
  260. // }
  261. // }
  262. // wc.beginSheetModal(for: NSApp.keyWindow!, completionHandler: nil)
  263. }
  264. @IBAction func buttonClicked_Action(_ sender: Any) {
  265. }
  266. func checkAndResetTask() -> Bool {
  267. if files?.count ?? 0 < 1 {
  268. return false
  269. }
  270. for i in 0..<(files?.count ?? 0) {
  271. if let file = files?[i] as? KMBatchOperateFile {
  272. if isBates {
  273. file.addBatesInfo.resetState()
  274. } else {
  275. file.addHeaderFooterInfo.resetState()
  276. }
  277. }
  278. }
  279. return true
  280. }
  281. func choosePathAndBeginOperation(_ obj: Any) {
  282. let openPanel = NSOpenPanel()
  283. openPanel.canChooseFiles = false
  284. openPanel.canChooseDirectories = true
  285. openPanel.canCreateDirectories = true
  286. openPanel.beginSheetModal(for: self.view.window!) { (result) in
  287. if result == NSApplication.ModalResponse.OK {
  288. for fileURL in openPanel.urls {
  289. self.choosePath = fileURL.path
  290. if self.isBates {
  291. self.beginAddBates(obj as! KMHeaderFooterObject)
  292. } else {
  293. self.beginAddHeaderFooter(obj as! KMHeaderFooterObject)
  294. }
  295. }
  296. }
  297. }
  298. }
  299. func beginAddBates(_ bates: KMHeaderFooterObject) {
  300. hiddenWindowCloseButtonIfNeeded()
  301. successFilePathURLArray?.removeAll()
  302. for i in 0..<(files?.count ?? 0) {
  303. if let file = files?[i] as? KMBatchOperateFile {
  304. if file.fileType == .PDF {
  305. file.addBatesInfo.savePath = choosePath
  306. if file.status == .Waiting {
  307. let operation = KMBatchAddHeaderFooterOperation(file: file, headerFooter: bates)
  308. operation.delegate = self
  309. queue?.addOperation(operation)
  310. }
  311. }
  312. }
  313. }
  314. if queue?.operationCount ?? 0 > 0 {
  315. interfaceStatus = .Processing
  316. }
  317. }
  318. func beginAddHeaderFooter(_ headerFooter: KMHeaderFooterObject) {
  319. hiddenWindowCloseButtonIfNeeded()
  320. successFilePathURLArray?.removeAll()
  321. for i in 0..<(files?.count ?? 0) {
  322. if let file = files?[i] as? KMBatchOperateFile {
  323. if file.fileType == .PDF {
  324. file.addHeaderFooterInfo.savePath = choosePath
  325. if file.status == .Waiting {
  326. let operation = KMBatchAddHeaderFooterOperation(file: file, headerFooter: headerFooter)
  327. operation.delegate = self
  328. queue?.addOperation(operation)
  329. }
  330. }
  331. }
  332. }
  333. if queue?.operationCount ?? 0 > 0 {
  334. interfaceStatus = .Processing
  335. }
  336. }
  337. func modify(obj: KMHeaderFooterObject) {
  338. // let windowController = self.view.window?.windowController
  339. // var filePath: String? = nil
  340. // var password: String? = nil
  341. // if let mainWindowController = windowController as? MainWindowController {
  342. // filePath = mainWindowController.mainViewController.listView?.document?.documentURL?.path
  343. // let document = mainWindowController.mainViewController.listView?.document as? CPDFDocument
  344. // password = document?.password
  345. // }
  346. // let wc = KMHeaderFooterManagerWindowController(baseFile: filePath, headerFooter: obj, password: password, type: .KMBatchModifyTemplateType_Edit)
  347. // wc?.isBates = self.isBates
  348. // let blockSelf = self
  349. // wc?.operateCallBack = { obj in
  350. // blockSelf.currentObject = obj
  351. // blockSelf.loadData()
  352. // blockSelf.reloadTable()
  353. // blockSelf.postNotification()
  354. // }
  355. // wc?.beginSheetModalForWindow(NSApp.keyWindow, completionHandler: nil)
  356. }
  357. func delete(obj: KMHeaderFooterObject) {
  358. KMHeaderFooterManager.defaultManager.removeHeaderFooter(obj)
  359. loadData()
  360. reloadTable()
  361. postNotification()
  362. }
  363. func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
  364. let action = menuItem.action
  365. if action == #selector(buttonItemClick_CleanAll(_:)) {
  366. if (self.isBates && KMHeaderFooterManager.defaultManager.onlyBatesObjects.count < 1) || (!self.isBates && KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects.count < 1){
  367. return false
  368. }
  369. return true
  370. }
  371. return true
  372. }
  373. func headerFooterInterfaceSelectHeaderFooter(headerFooter: KMHeaderFooterObject) {
  374. self.tableView.reloadData()
  375. if let index = KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects.index(of: headerFooter) {
  376. let indexSet = IndexSet(integer: index)
  377. self.tableView.selectRowIndexes(indexSet, byExtendingSelection: false)
  378. }
  379. }
  380. func batesInterfaceSelectBates(headerFooter: KMHeaderFooterObject) {
  381. self.tableView.reloadData()
  382. if let index = KMHeaderFooterManager.defaultManager.onlyBatesObjects.index(of: headerFooter) {
  383. let indexSet = IndexSet(integer: index)
  384. self.tableView.selectRowIndexes(indexSet, byExtendingSelection: false)
  385. }
  386. }
  387. func numberOfRows(in tableView: NSTableView) -> Int {
  388. var count = 0
  389. if self.isBates {
  390. count = KMHeaderFooterManager.defaultManager.onlyBatesObjects.count
  391. } else {
  392. count = KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects.count
  393. }
  394. self.blankView.isHidden = count != 0
  395. return count
  396. }
  397. func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
  398. var obj: KMHeaderFooterObject? = nil
  399. if self.isBates {
  400. obj = KMHeaderFooterManager.defaultManager.onlyBatesObjects[row]
  401. } else {
  402. obj = KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects[row]
  403. }
  404. guard let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "mainCell"), owner: self) as? KMHeaderFooterTableCellView else {
  405. return nil
  406. }
  407. cellView.updateInterface(obj!)
  408. cellView.headerFooterTableCellViewCallback = { type in
  409. if type == .Edit {
  410. let indexSet = IndexSet(integer: row)
  411. self.tableView.selectRowIndexes(indexSet, byExtendingSelection: false)
  412. self.currentObject = obj
  413. self.modify(obj: obj!)
  414. } else {
  415. self.delete(obj: obj!)
  416. }
  417. }
  418. return cellView
  419. }
  420. func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
  421. let rowView = KMTableRowView()
  422. return rowView
  423. }
  424. func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
  425. if self.isBates {
  426. return KMHeaderFooterManager.defaultManager.onlyBatesObjects[row].cellHeight
  427. } else {
  428. return KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects[row].cellHeight
  429. }
  430. }
  431. func tableViewSelectionDidChange(_ notification: Notification) {
  432. let row = self.tableView.selectedRow
  433. updateActionButtonbackgroundColor()
  434. if row == -1 { return }
  435. if self.isBates {
  436. let bates = KMHeaderFooterManager.defaultManager.onlyBatesObjects[row]
  437. self.currentObject = bates
  438. for i in 0..<(self.files?.count ?? 0) {
  439. let file = self.files?[i]
  440. file?.addBatesInfo.pageChoice = bates.pageChoice
  441. if file?.addBatesInfo.pageChoice == .Input {
  442. let arr = allPageNumbers(bates.pagesString)
  443. let sortedArray: NSArray = file!.pagesArrayIntersect(with: arr) as NSArray
  444. if sortedArray.count < 1 {
  445. file?.addBatesInfo.pageChoice = .All
  446. } else {
  447. file!.addBatesInfo.pageRangeString = sortedArray.componentsJoined(by: ",")
  448. }
  449. }
  450. }
  451. } else {
  452. let headerFooter = KMHeaderFooterManager.defaultManager.onlyHeaderFooterObjects[row]
  453. self.currentObject = headerFooter
  454. for i in 0..<(self.files?.count ?? 0) {
  455. let file = self.files?[i]
  456. file?.addHeaderFooterInfo.pageChoice = headerFooter.pageChoice
  457. if file?.addHeaderFooterInfo.pageChoice == .Input {
  458. let arr = allPageNumbers(headerFooter.pagesString)
  459. let sortedArray: NSArray = file!.pagesArrayIntersect(with: arr) as NSArray
  460. if sortedArray.count < 1 {
  461. file?.addHeaderFooterInfo.pageChoice = .All
  462. } else {
  463. file!.addHeaderFooterInfo.pageRangeString = sortedArray.componentsJoined(by: ",")
  464. }
  465. }
  466. }
  467. }
  468. reloadTable()
  469. NotificationCenter.default.post(name: NSNotification.Name(rawValue: kNeedChangePageRangeNotification), object: nil)
  470. }
  471. }