KMBatchTableCellView.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. //
  2. // KMBatchTableCellView.swift
  3. // PDF Master
  4. //
  5. // Created by kdanmobile on 2023/10/27.
  6. //
  7. import Cocoa
  8. typealias batchTableCellComboboxMouseDownCallback = (_ mouseDown: Bool) -> ()
  9. typealias batchTableCellRemoveFileCallBack = (_ file: KMBatchOperateFile) -> ()
  10. @objc enum KMBatchTableCellViewType: Int {
  11. case Size = 0
  12. case PageRange
  13. case FileName
  14. case Status
  15. case DPI
  16. case Dimensions
  17. }
  18. class KMBatchTableCellCombobox: KMComboBox{
  19. var mouseDownCallback: batchTableCellComboboxMouseDownCallback?
  20. override func mouseDown(with event: NSEvent) {
  21. super.mouseDown(with: event)
  22. if (self.mouseDownCallback != nil) {
  23. self.mouseDownCallback!(true)
  24. }
  25. }
  26. }
  27. class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
  28. var removeFileCallBack: batchTableCellRemoveFileCallBack?
  29. var pageRangeCombobox: KMBatchTableCellCombobox?
  30. var errorTextField: NSTextField?
  31. var statusView: NSView?
  32. var removeButton: KMButton?
  33. var progressIndicator: NSProgressIndicator?
  34. var type: KMBatchTableCellViewType?
  35. var file: KMBatchOperateFile?
  36. var DPIComboBox: NSComboBox?
  37. var indicateImageView: NSImageView?
  38. var comboBoxContent: String?
  39. deinit {
  40. DistributedNotificationCenter.default().removeObserver(self)
  41. }
  42. convenience init(type: KMBatchTableCellViewType) {
  43. self.init()
  44. switch type {
  45. case .Size:
  46. configuUIForSize()
  47. case .Dimensions:
  48. configuUIForSize()
  49. case .PageRange:
  50. configuUIForPageRange()
  51. case .FileName:
  52. configuUIForFileName()
  53. case .Status:
  54. configuUIForStatus()
  55. case .DPI:
  56. configuUIForDPI()
  57. default:
  58. break
  59. }
  60. DistributedNotificationCenter.default().addObserver(self, selector: #selector(themeChanged(notification:)), name: NSNotification.Name("AppleInterfaceThemeChangedNotification"), object: nil)
  61. self.type = type
  62. }
  63. func configuUIForSize() {
  64. var tf = NSTextField(frame: .zero)
  65. self.textField = tf
  66. self.textField?.isBordered = false
  67. self.textField?.drawsBackground = true
  68. self.textField?.backgroundColor = NSColor.clear
  69. self.textField?.isEditable = false
  70. self.addSubview(self.textField!)
  71. self.textField?.mas_makeConstraints({ make in
  72. make?.top.equalTo()(self)?.offset()(13)
  73. make?.left.equalTo()(self)
  74. })
  75. self.textField?.textColor = KMAppearance.Layout.h0Color()
  76. self.textField?.font = NSFont.systemFont(ofSize: 12)
  77. }
  78. func configuUIForPageRange() {
  79. self.pageRangeCombobox = KMBatchTableCellCombobox(frame: .zero)
  80. self.pageRangeCombobox?.focusRingType = .none
  81. self.pageRangeCombobox?.type = .none
  82. self.pageRangeCombobox?.wantsLayer = true
  83. self.pageRangeCombobox?.layer?.backgroundColor = KMAppearance.Layout.l1Color().cgColor
  84. self.pageRangeCombobox?.layer?.borderWidth = 1.0
  85. self.pageRangeCombobox?.layer?.borderColor = KMAppearance.Interactive.s0Color().cgColor
  86. self.pageRangeCombobox?.layer?.cornerRadius = 1.0
  87. self.pageRangeCombobox?.backgroundColor = KMAppearance.Layout.l1Color()
  88. self.addSubview(self.pageRangeCombobox!)
  89. self.pageRangeCombobox?.mas_makeConstraints({ make in
  90. make?.left.equalTo()(self)
  91. make?.width.equalTo()(144)
  92. make?.top.equalTo()(self)?.offset()(10)
  93. })
  94. let choiceArray = [
  95. " \(NSLocalizedString("All Pages", comment: ""))",
  96. " \(NSLocalizedString("Odd Pages Only", comment: ""))",
  97. " \(NSLocalizedString("Even Pages Only", comment: ""))",
  98. " \(NSLocalizedString("e.g. 1,3-5,10", comment: ""))"
  99. ]
  100. self.pageRangeCombobox!.addItems(withObjectValues: choiceArray)
  101. let placeholderString = " \(NSLocalizedString("e.g. 1,3-5,10", comment: ""))"
  102. // self.pageRangeCombobox!.cell.placeholderString = placeholderString
  103. self.pageRangeCombobox?.selectItem(at: 0)
  104. self.pageRangeCombobox?.isEditable = false
  105. self.pageRangeCombobox?.delegate = self
  106. self.comboBoxContent = placeholderString
  107. self.updateViewColor()
  108. weak var weakSelf = self
  109. self.pageRangeCombobox?.mouseDownCallback = { mouseDown in
  110. let itemIdex = weakSelf!.pageRangeCombobox!.indexOfSelectedItem
  111. if itemIdex == 3 {//KMBatchOperatePageChoice.Input
  112. if weakSelf?.comboBoxContent == placeholderString {
  113. weakSelf?.pageRangeCombobox!.stringValue = ""
  114. } else {
  115. weakSelf?.pageRangeCombobox!.stringValue = (weakSelf?.comboBoxContent)!
  116. }
  117. }
  118. }
  119. }
  120. func configuUIForFileName() {
  121. var tf = NSTextField(frame: .zero)
  122. self.textField = tf
  123. self.textField?.isBordered = false
  124. self.textField?.drawsBackground = true
  125. self.textField?.backgroundColor = NSColor.clear
  126. self.textField?.isEditable = false
  127. self.textField?.maximumNumberOfLines = 1
  128. self.textField?.lineBreakMode = .byTruncatingMiddle
  129. self.addSubview(self.textField!)
  130. self.textField?.mas_makeConstraints({ make in
  131. make?.top.equalTo()(self)?.offset()(13)
  132. make?.left.equalTo()(self)
  133. make?.right.equalTo()(self)?.offset()(-10)
  134. })
  135. self.textField?.font = NSFont.systemFont(ofSize: 12)
  136. self.textField?.textColor = KMAppearance.Layout.h0Color()
  137. self.errorTextField = NSTextField(frame: .zero)
  138. self.errorTextField?.isBordered = false
  139. self.errorTextField?.drawsBackground = true
  140. self.errorTextField?.backgroundColor = NSColor.clear
  141. self.errorTextField?.isEditable = false
  142. self.errorTextField?.font = NSFont.systemFont(ofSize: 12)
  143. self.errorTextField?.textColor = KMAppearance.Status.errColor()
  144. self.addSubview(self.errorTextField!)
  145. self.errorTextField?.mas_makeConstraints({ make in
  146. make?.top.equalTo()(self.textField?.mas_bottom)
  147. make?.left.equalTo()(self)
  148. make?.bottom.equalTo()(self)?.offset()(-11)
  149. make?.right.equalTo()(self.mas_right)
  150. })
  151. }
  152. func configuUIForStatus() {
  153. self.statusView = NSView(frame: .zero)
  154. self.statusView?.wantsLayer = true
  155. self.addSubview(self.statusView!)
  156. self.statusView?.mas_makeConstraints({ make in
  157. make?.left.equalTo()(self)
  158. make?.top.equalTo()(self)?.offset()(12)
  159. make?.width.equalTo()(16)
  160. make?.height.equalTo()(16)
  161. })
  162. self.indicateImageView = NSImageView(frame: .zero)
  163. self.statusView?.addSubview(self.indicateImageView!)
  164. self.indicateImageView?.mas_makeConstraints({ make in
  165. make?.edges.equalTo()(self.statusView)
  166. })
  167. self.progressIndicator = NSProgressIndicator(frame: .zero)
  168. self.statusView?.addSubview(self.progressIndicator!)
  169. self.progressIndicator?.mas_makeConstraints({ make in
  170. make?.edges.equalTo()(self.statusView)
  171. })
  172. self.progressIndicator?.maxValue = 1.0
  173. self.progressIndicator?.minValue = 0
  174. self.progressIndicator?.style = .spinning
  175. self.progressIndicator?.controlSize = .small
  176. self.removeButton = KMButton(image: NSImage(named: KMImageNameUXIconBtnCloseNor)!, target: self, action: #selector(deleteFile(sender:)))
  177. self.removeButton?.isBordered = false
  178. self.removeButton?.isHidden = true
  179. self.addSubview(self.removeButton!)
  180. self.removeButton?.mas_makeConstraints({ make in
  181. // make?.left.equalTo()(self)?.offset()(10)
  182. make?.centerY.equalTo()(self)
  183. make?.right.equalTo()(self)?.offset()(0)
  184. make?.width.equalTo()(20)
  185. make?.height.equalTo()(20)
  186. })
  187. weak var weakSelf = self
  188. self.removeButton!.mouseMoveCallback = { mouseEntered in
  189. if mouseEntered {
  190. weakSelf?.removeButton!.image = NSImage(named: KMImageNameUXIconBtnCloseHov)
  191. } else {
  192. weakSelf?.removeButton!.image = NSImage(named: KMImageNameUXIconBtnCloseNor)
  193. }
  194. }
  195. }
  196. func configuUIForDPI() {
  197. self.DPIComboBox = NSComboBox(frame: .zero)
  198. self.addSubview(self.DPIComboBox!)
  199. let DPIArray = ["50 dpi", "72 dpi", "96 dpi", "150 dpi", "300 dpi", "600 dpi"]
  200. self.DPIComboBox?.addItems(withObjectValues: DPIArray)
  201. self.DPIComboBox?.selectItem(at: 0)
  202. self.DPIComboBox?.isEditable = false
  203. self.DPIComboBox?.delegate = self
  204. self.removeButton?.mas_makeConstraints({ make in
  205. make?.left.equalTo()(self)
  206. make?.top.equalTo()(self)?.offset()(10)
  207. make?.centerX.equalTo()(self)
  208. })
  209. }
  210. @objc func themeChanged(notification: NSNotification) {
  211. DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
  212. self.updateViewColor()
  213. }
  214. }
  215. @objc func deleteFile(sender: Any) {
  216. if (self.removeFileCallBack != nil) {
  217. self.removeFileCallBack!(self.file!)
  218. }
  219. }
  220. func updateViewColor() {
  221. if KMAppearance.isDarkMode() {
  222. self.pageRangeCombobox!.backgroundColor = NSColor(red: 0.224, green: 0.235, blue: 0.243, alpha: 1)
  223. self.pageRangeCombobox!.layer!.backgroundColor = NSColor(red: 0.224, green: 0.235, blue: 0.243, alpha: 1).cgColor
  224. self.pageRangeCombobox!.layer!.borderColor = NSColor(red: 0.337, green: 0.345, blue: 0.353, alpha: 1).cgColor
  225. } else {
  226. self.pageRangeCombobox!.backgroundColor = NSColor.white
  227. self.pageRangeCombobox!.layer!.backgroundColor = NSColor.white.cgColor
  228. self.pageRangeCombobox!.layer!.borderColor = NSColor(red: 0.855, green: 0.859, blue: 0.871, alpha: 1).cgColor
  229. }
  230. }
  231. func updateInterface(_ file: KMBatchOperateFile) {
  232. self.file = file
  233. if self.type == .Size {
  234. self.textField?.stringValue = file.sizeString
  235. } else if self.type == .FileName {
  236. if (file.error != nil) {
  237. self.errorTextField?.stringValue = file.error!.localizedDescription
  238. self.errorTextField?.isHidden = false
  239. } else {
  240. self.errorTextField?.isHidden = true
  241. }
  242. self.textField?.stringValue = file.filePath.lastPathComponent
  243. } else if self.type == .PageRange {
  244. self.pageRangeCombobox?.isEnabled = self.file!.status != .processing
  245. self.pageRangeCombobox?.delegate = nil
  246. self.pageRangeCombobox?.selectItem(at: file.currentOperateInfo?.pageChoice?.rawValue ?? 0)
  247. self.pageRangeCombobox?.isEditable = false
  248. if file.currentOperateInfo?.pageChoice == .Input {
  249. self.pageRangeCombobox?.isEditable = true
  250. self.pageRangeCombobox?.stringValue = file.currentOperateInfo?.pageRangeString ?? ""
  251. }
  252. self.pageRangeCombobox?.delegate = self
  253. } else if self.type == .Status {
  254. if file.status == .Waiting {
  255. self.indicateImageView?.isHidden = false
  256. self.progressIndicator?.isHidden = true
  257. self.indicateImageView?.image = NSImage(named: KMImageNameUXIconProgressWaiting)
  258. } else if file.status == .Success {
  259. self.indicateImageView?.isHidden = false
  260. self.progressIndicator?.isHidden = true
  261. self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressComplete")
  262. } else if file.status == .Failed {
  263. self.indicateImageView?.isHidden = false
  264. self.progressIndicator?.isHidden = true
  265. self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressFailure")
  266. } else if file.status == .processing {
  267. self.indicateImageView?.isHidden = true
  268. self.progressIndicator?.isHidden = false
  269. self.progressIndicator?.startAnimation(nil)
  270. }
  271. } else if self.type == .DPI {
  272. switch self.file?.dpi {
  273. case 50:
  274. self.DPIComboBox?.selectItem(at: 0)
  275. case 72:
  276. self.DPIComboBox?.selectItem(at: 1)
  277. case 96:
  278. self.DPIComboBox?.selectItem(at: 2)
  279. case 150:
  280. self.DPIComboBox?.selectItem(at: 3)
  281. case 300:
  282. self.DPIComboBox?.selectItem(at: 4)
  283. case 600:
  284. self.DPIComboBox?.selectItem(at: 5)
  285. default:
  286. break
  287. }
  288. self.DPIComboBox?.isEnabled = self.file?.status != .processing
  289. } else if self.type == .Dimensions {
  290. }
  291. }
  292. func updateInterface( file: KMBatchOperateFile, progress: Float) {
  293. updateInterface(file)
  294. if progress > 0 && file.status == .processing {
  295. self.progressIndicator?.doubleValue = Double(progress)
  296. self.progressIndicator?.startAnimation(nil)
  297. self.progressIndicator?.isIndeterminate = false
  298. }
  299. }
  300. func updateInterface(isProgress progress: Int) {
  301. if progress == -1 {
  302. self.indicateImageView?.isHidden = false
  303. self.progressIndicator?.isHidden = true
  304. self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressFailure")
  305. } else if progress == 0 {
  306. self.indicateImageView?.isHidden = false
  307. self.progressIndicator?.isHidden = true
  308. self.indicateImageView?.image = NSImage(named: KMImageNameUXIconProgressWaiting)
  309. } else {
  310. self.indicateImageView?.isHidden = false
  311. self.progressIndicator?.isHidden = true
  312. self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressComplete")
  313. }
  314. }
  315. func controlTextDidEndEditing(_ obj: Notification) {
  316. if (self.pageRangeCombobox?.isEqual(obj.object)) != nil {
  317. self.file?.currentOperateInfo?.pageRangeString = self.pageRangeCombobox!.stringValue
  318. if self.file?.currentOperateInfo?.pagesArray == nil {
  319. let alert = NSAlert()
  320. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  321. alert.alertStyle = .critical
  322. alert.messageText = self.file!.filePath.lastPathComponent.lastPathComponent + NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
  323. alert.beginSheetModal(for: self.window!, completionHandler: nil)
  324. self.pageRangeCombobox?.selectItem(at: 0)
  325. self.file?.currentOperateInfo?.pageChoice = .All
  326. }
  327. }
  328. }
  329. func controlTextDidChange(_ obj: Notification) {
  330. let comboBox: NSComboBox = obj.object as! NSComboBox;
  331. if comboBox.isEqual(self.pageRangeCombobox) {
  332. self.comboBoxContent = comboBox.stringValue;
  333. }
  334. }
  335. func comboBoxSelectionDidChange(_ notification: Notification) {
  336. if notification.object as? NSComboBox == self.pageRangeCombobox {
  337. self.pageRangeCombobox!.delegate = nil
  338. self.file?.currentOperateInfo!.pageChoice = self.tromsformPageChoice(index: self.pageRangeCombobox?.indexOfSelectedItem ?? 0)
  339. if self.pageRangeCombobox?.indexOfSelectedItem == 0 {
  340. self.pageRangeCombobox?.isEditable = true
  341. self.pageRangeCombobox?.isSelectable = true
  342. self.window?.makeFirstResponder(self.pageRangeCombobox)
  343. } else {
  344. self.pageRangeCombobox?.resignFirstResponder()
  345. self.pageRangeCombobox?.isEditable = false
  346. self.pageRangeCombobox?.isSelectable = false
  347. }
  348. self.pageRangeCombobox?.delegate = self
  349. } else if notification.object as? NSComboBox == self.DPIComboBox {
  350. switch self.DPIComboBox?.indexOfSelectedItem
  351. {
  352. case 0:
  353. self.file?.currentConvertParameter?.dpi = 50
  354. case 1:
  355. self.file?.currentConvertParameter?.dpi = 72
  356. case 2:
  357. self.file?.currentConvertParameter?.dpi = 96
  358. case 3:
  359. self.file?.currentConvertParameter?.dpi = 150
  360. case 4:
  361. self.file?.currentConvertParameter?.dpi = 300
  362. case 5:
  363. self.file?.currentConvertParameter?.dpi = 600
  364. default:
  365. break
  366. }
  367. }
  368. }
  369. func tromsformPageChoice(index: Int) -> KMBatchOperatePageChoice {
  370. var pageChoice: KMBatchOperatePageChoice?
  371. switch index {
  372. case 0:
  373. pageChoice = .All
  374. case 1:
  375. pageChoice = .Odd
  376. case 2:
  377. pageChoice = .Even
  378. case 3:
  379. pageChoice = .Input
  380. default:
  381. pageChoice = .All
  382. }
  383. return pageChoice ?? .All
  384. }
  385. }