KMNPopAnnotationWindowController.swift 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. //
  2. // KMNPopAnnotationWindowController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by 丁林圭 on 2024/12/2.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. let popOffSet:CGFloat = 8.0
  10. typealias PaneCallback = (_ isOpenPane: Bool) -> ()
  11. typealias UpdatePDFViewCallback = () -> ()
  12. class KMNPopOperationWindow: NSWindow {
  13. override var canBecomeKey: Bool {
  14. return true
  15. }
  16. override var canBecomeMain: Bool {
  17. return true
  18. }
  19. }
  20. class KMNPopAnnotationWindowController: KMNBaseWindowController {
  21. public var popType:ListViewPopType = .popTypeNone {
  22. didSet {
  23. rightOffsetConstraint.constant = 45.0
  24. operationHeightConstraint.constant = 32.0
  25. paneBox.isHidden = false
  26. switch popType {
  27. case .generaAnnotation :
  28. generaPopView.layoutSubtreeIfNeeded()
  29. operationWidthConstraint.constant = generaPopView.bounds.width
  30. self.window?.display() //需刷新约束才会有值,不然会变化
  31. operationBox.contentView = generaPopView
  32. break
  33. case .freeTextAnnotation:
  34. fontPopView.layoutSubtreeIfNeeded()
  35. operationWidthConstraint.constant = fontPopView.bounds.width
  36. self.window?.display() //需刷新约束才会有值,不然会变化
  37. operationBox.contentView = fontPopView
  38. break
  39. case .shapeAnnotation:
  40. shapeView.layoutSubtreeIfNeeded()
  41. operationWidthConstraint.constant = shapeView.bounds.width
  42. self.window?.display() //需刷新约束才会有值,不然会变化
  43. operationBox.contentView = shapeView
  44. break
  45. case .linkAnnotation:
  46. if let newLinkAnnotation = annotationPopMode.annotation as? CPDFLinkAnnotation {
  47. linkAnnotation = newLinkAnnotation
  48. }
  49. break
  50. case .formAnnotation:
  51. formRightConstraint.constant = 0
  52. gropNameInput.isHidden = true
  53. formView.layoutSubtreeIfNeeded()
  54. operationWidthConstraint.constant = formView.bounds.width
  55. self.window?.display() //需刷新约束才会有值,不然会变化
  56. operationBox.contentView = formView
  57. break
  58. case .formRadioAnnotation:
  59. formRightConstraint.constant = 110
  60. gropNameInput.isHidden = false
  61. formView.layoutSubtreeIfNeeded()
  62. operationWidthConstraint.constant = formView.bounds.width
  63. self.window?.display() //需刷新约束才会有值,不然会变化
  64. operationBox.contentView = formView
  65. break
  66. case .multpleAnnotation:
  67. alightView.layoutSubtreeIfNeeded()
  68. operationWidthConstraint.constant = alightView.bounds.width
  69. self.window?.display() //需刷新约束才会有值,不然会变化
  70. operationBox.contentView = alightView
  71. break
  72. case .popTypeNone:
  73. break
  74. }
  75. }
  76. }
  77. public var isOpenPane = false {
  78. didSet {
  79. if isOpenPane == true {
  80. paneSelectorItem.properties.state = .pressed
  81. } else {
  82. paneSelectorItem.properties.state = .normal
  83. }
  84. paneSelectorItem.reloadData()
  85. }
  86. }
  87. public var annotationPopMode:KMNAnnotationPopMode = KMNAnnotationPopMode(pdfAnnotations: []) {
  88. didSet {
  89. let annotationPopType = annotationPopMode.popType
  90. popType = annotationPopType
  91. if annotationPopType == .generaAnnotation {
  92. let newColor = annotationPopMode.annotationColor()
  93. let oldColor = annotationColor
  94. if !CPDFListView.isTheSameColor(newColor, anotherColor: oldColor) {
  95. annotationColor = newColor
  96. }
  97. } else if(annotationPopType == .shapeAnnotation) {
  98. let newColor = annotationPopMode.annotationColor()
  99. let oldColor = annotationColor
  100. if !CPDFListView.isTheSameColor(newColor, anotherColor: oldColor) {
  101. annotationColor = newColor
  102. }
  103. } else if(annotationPopType == .freeTextAnnotation) {
  104. let newColor = annotationPopMode.annotationFontColor()
  105. let oldColor = fontColor
  106. if !CPDFListView.isTheSameColor(newColor, anotherColor: oldColor) {
  107. fontColor = newColor
  108. }
  109. let alignment = annotationPopMode.annotationAlignment()
  110. if(alignment != self.fontAlight) {
  111. fontAlight = alignment
  112. }
  113. let font = annotationPopMode.annotationFontName()
  114. if(font?.familyName != compdfFont?.familyName || font?.styleName != compdfFont?.styleName) {
  115. compdfFont = font
  116. }
  117. } else if annotationPopType == .linkAnnotation {
  118. if annotationPopMode.annotation != nil {
  119. linkAnnotation = annotationPopMode.annotation as! CPDFLinkAnnotation
  120. }
  121. } else if annotationPopType == .formAnnotation {
  122. if annotationPopMode.annotationFieldName() != fildNameString {
  123. fildNameString = annotationPopMode.annotationFieldName() ?? ""
  124. }
  125. } else if annotationPopType == .formRadioAnnotation {
  126. if annotationPopMode.annotationFieldName() != fildNameString {
  127. fildNameString = annotationPopMode.annotationFieldName() ?? ""
  128. }
  129. if annotationPopMode.annotationGropName() != gropNameString {
  130. gropNameString = annotationPopMode.annotationGropName() ?? ""
  131. }
  132. }
  133. }
  134. }
  135. private var annotationColor:NSColor?{
  136. didSet {
  137. if popType == .generaAnnotation {
  138. generaColorGroup.currentColor = annotationColor
  139. generaColorGroup.refreshUI()
  140. } else if popType == .shapeAnnotation {
  141. shapeColorGroup.currentColor = annotationColor
  142. shapeColorGroup.refreshUI()
  143. }
  144. }
  145. }
  146. private var fontColor:NSColor?{
  147. didSet {
  148. fontColorItem.properties?.color = fontColor
  149. fontColorItem.reloadData()
  150. }
  151. }
  152. private var linkAnnotation:CPDFLinkAnnotation = CPDFLinkAnnotation(){
  153. didSet {
  154. if let destination = linkAnnotation.destination() {
  155. linkType = .page
  156. } else if let annotationURL = linkAnnotation.url(){
  157. var urlString = annotationURL.fileURL.absoluteString
  158. if annotationURL.hasPrefix("mailto:") {
  159. linkType = .email
  160. } else {
  161. linkType = .url
  162. }
  163. } else {
  164. linkType = .linkSetting
  165. }
  166. }
  167. }
  168. private var fildNameString:String = ""{
  169. didSet {
  170. fildNameInput.properties.text = fildNameString
  171. fildNameInput.reloadData()
  172. }
  173. }
  174. private var gropNameString:String = ""{
  175. didSet {
  176. gropNameInput.properties.text = gropNameString
  177. gropNameInput.reloadData()
  178. }
  179. }
  180. private var compdfFont:CPDFFont?{
  181. didSet {
  182. if(compdfFont != nil) {
  183. let styleName = compdfFont!.styleName
  184. if(styleName?.isEmpty == true) {
  185. fontNameSelect.properties.text = compdfFont!.familyName
  186. } else {
  187. fontNameSelect.properties.text = compdfFont!.familyName + "-" + (compdfFont!.styleName ?? "")
  188. }
  189. } else {
  190. fontNameSelect.properties.text = "-"
  191. }
  192. fontNameSelect.selectItemAtIndex(0)
  193. fontNameSelect.reloadData()
  194. }
  195. }
  196. private var fontAlight:NSTextAlignment = .left {
  197. didSet {
  198. if fontAlight == .center {
  199. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightCenter")
  200. } else if fontAlight == .right {
  201. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightRight")
  202. } else {
  203. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightLeft")
  204. }
  205. fontAlightButton.reloadData()
  206. }
  207. }
  208. private var objectAlignType:ObjectAlignType = .alightLeft {
  209. didSet {
  210. let activeAnnotations = annotationPopMode.annotations
  211. switch objectAlignType {
  212. case .alightLeft :
  213. listView?.change(activeAnnotations, alignmentType: .left)
  214. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightLeft")
  215. break
  216. case .alightRight:
  217. listView?.change(activeAnnotations, alignmentType: .right)
  218. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightRight")
  219. break
  220. case .alightTop:
  221. listView?.change(activeAnnotations, alignmentType: .top)
  222. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightTop")
  223. break
  224. case .alightVer:
  225. listView?.change(activeAnnotations, alignmentType: .vertical)
  226. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightVer")
  227. break
  228. case .alightHor:
  229. listView?.change(activeAnnotations, alignmentType: .horizontally)
  230. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightHor")
  231. break
  232. case .alightBottom:
  233. listView?.change(activeAnnotations, alignmentType: .bottom)
  234. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightBottom")
  235. break
  236. case .averageVer:
  237. listView?.change(activeAnnotations, alignmentType: .disVertical)
  238. alightButton.properties.icon = NSImage(named: "KMNImageNameObjecAlignAverageVer")
  239. break
  240. case .averageHor:
  241. listView?.change(activeAnnotations, alignmentType: .disHorizontally)
  242. alightButton.properties.icon = NSImage(named: "KMNImageNameObjecAlignAverageHor")
  243. break
  244. }
  245. alightButton.reloadData()
  246. }
  247. }
  248. var paneCallback: PaneCallback?
  249. var updatePDFViewCallback: UpdatePDFViewCallback?
  250. static let shared: KMNPopAnnotationWindowController = {
  251. let windowC = KMNPopAnnotationWindowController(windowNibName: "KMNPopAnnotationWindowController")
  252. return windowC
  253. }()
  254. var linkType:linkDetailType = .linkSetting {
  255. didSet {
  256. if linkType == .linkSetting {
  257. linkView.layoutSubtreeIfNeeded()
  258. rightOffsetConstraint.constant = 45.0
  259. operationHeightConstraint.constant = 32.0
  260. operationWidthConstraint.constant = linkView.bounds.width
  261. self.window?.display() //需刷新约束才会有值,不然会变化
  262. operationBox.contentView = linkView
  263. paneBox.isHidden = false
  264. } else if linkType == .page {
  265. linkPageDetailView.layoutSubtreeIfNeeded()
  266. rightOffsetConstraint.constant = 8
  267. operationWidthConstraint.constant = linkPageDetailView.bounds.width
  268. operationHeightConstraint.constant = 224
  269. self.window?.display() //需刷新约束才会有值,不然会变化
  270. operationBox.contentView = linkPageDetailView
  271. paneBox.isHidden = true
  272. if let destination = linkAnnotation.destination() {
  273. reloadPageUrlData()
  274. refreshPageThum()
  275. } else {
  276. paginationView.properties.currentIndex = Int(((listView?.currentPageIndex ?? 0) + 1))
  277. paginationView.reloadData()
  278. refreshPageThum()
  279. }
  280. } else if linkType == .url {
  281. linkUrlDetailView.layoutSubtreeIfNeeded()
  282. rightOffsetConstraint.constant = 8
  283. operationWidthConstraint.constant = linkUrlDetailView.bounds.width
  284. operationHeightConstraint.constant = linkUrlDetailView.bounds.height
  285. self.window?.display() //需刷新约束才会有值,不然会变化
  286. operationBox.contentView = linkUrlDetailView
  287. paneBox.isHidden = true
  288. urlInput.properties.placeholder = KMNCompanyWebsite
  289. if let annotationURL = linkAnnotation.url(){
  290. if annotationURL.hasPrefix("mailto:") {
  291. urlInput.properties.text = ""
  292. } else {
  293. urlInput.properties.text = annotationURL
  294. }
  295. } else {
  296. urlInput.properties.text = ""
  297. }
  298. urlInput.properties.state = .pressed
  299. urlInput.beginEditing()
  300. urlInput.reloadData()
  301. } else if linkType == .email {
  302. linkUrlDetailView.layoutSubtreeIfNeeded()
  303. rightOffsetConstraint.constant = 8
  304. operationWidthConstraint.constant = linkUrlDetailView.bounds.width
  305. operationHeightConstraint.constant = linkUrlDetailView.bounds.height
  306. self.window?.display() //需刷新约束才会有值,不然会变化
  307. operationBox.contentView = linkUrlDetailView
  308. paneBox.isHidden = true
  309. urlInput.properties.placeholder = KMNCompanyEamil
  310. if let annotationURL = linkAnnotation.url(){
  311. if annotationURL.hasPrefix("mailto:") {
  312. if let range = annotationURL.range(of: "mailto:") {
  313. let trimmedString = String(annotationURL[range.upperBound...])
  314. urlInput.properties.text = trimmedString
  315. }
  316. } else {
  317. urlInput.properties.text = ""
  318. }
  319. } else {
  320. urlInput.properties.text = ""
  321. }
  322. urlInput.properties.state = .pressed
  323. urlInput.beginEditing()
  324. urlInput.reloadData()
  325. }
  326. updateFrame(listView: listView ?? CPDFListView())
  327. }
  328. }
  329. @IBOutlet weak var contentBox: NSBox!
  330. @IBOutlet weak var operationBox: NSBox!
  331. @IBOutlet weak var paneBox: NSBox!
  332. @IBOutlet weak var lineBox: NSBox!
  333. @IBOutlet var paneSelectorItem: ComponentCSelector!
  334. @IBOutlet weak var operationWidthConstraint: NSLayoutConstraint!
  335. @IBOutlet weak var rightOffsetConstraint: NSLayoutConstraint!
  336. @IBOutlet weak var operationHeightConstraint: NSLayoutConstraint!
  337. @IBOutlet var generaPopView: NSView!
  338. @IBOutlet var generaColorGroup: ComponentCColorGroup!
  339. @IBOutlet var fontPopView: NSView!
  340. @IBOutlet var fontColorItem: ComponentCColorItem!
  341. @IBOutlet var fontNameSelect: ComponentSelect!
  342. @IBOutlet var fontSizeZoomOutButton: ComponentButton!
  343. @IBOutlet var fontSizeZoomInButton: ComponentButton!
  344. @IBOutlet var fontAlightButton: ComponentButton!
  345. @IBOutlet var shapeView: NSView!
  346. @IBOutlet var shapeColorGroup: ComponentCColorGroup!
  347. @IBOutlet var widthZoomOutButton: ComponentButton!
  348. @IBOutlet var widthZoomInButton: ComponentButton!
  349. @IBOutlet var linkView: NSView!
  350. @IBOutlet var pageLinkButton: ComponentButton!
  351. @IBOutlet var urlLinkButton: ComponentButton!
  352. @IBOutlet var emailLinkButton: ComponentButton!
  353. @IBOutlet weak var pageLinkWidthConstraint: NSLayoutConstraint!
  354. @IBOutlet weak var urlLinkWidthConstraint: NSLayoutConstraint!
  355. @IBOutlet weak var emailLinkWidthConstraint: NSLayoutConstraint!
  356. @IBOutlet var formView: NSView!
  357. @IBOutlet var fildNameInput: ComponentInput!
  358. @IBOutlet var gropNameInput: ComponentInput!
  359. @IBOutlet var formRightConstraint: NSLayoutConstraint!
  360. @IBOutlet var alightView: NSView!
  361. @IBOutlet var alightButton: ComponentButton!
  362. @IBOutlet var linkPageDetailView: NSView!
  363. @IBOutlet var backPageLinkButton: ComponentButton!
  364. @IBOutlet var paginationView: ComponentPagination!
  365. @IBOutlet var paginationDesBox: NSBox!
  366. @IBOutlet var pageThumImageView: NSImageView!
  367. @IBOutlet var goPageLinkButton: ComponentButton!
  368. @IBOutlet weak var backPageWidthConstraint: NSLayoutConstraint!
  369. @IBOutlet var linkUrlDetailView: NSView!
  370. @IBOutlet var backUrlLinkButton: ComponentButton!
  371. @IBOutlet var goUrlLinkButton: ComponentButton!
  372. @IBOutlet var urlInput: ComponentInput!
  373. @IBOutlet weak var backUrlWidthConstraint: NSLayoutConstraint!
  374. private var fontPopover:NSPopover?
  375. private var ObjectPopover:NSPopover?
  376. weak var listView:CPDFListView? {
  377. didSet {
  378. paginationView.properties.totalCount = Int(listView?.document.pageCount ?? 1)
  379. paginationView.reloadData()
  380. }
  381. }
  382. override func windowDidLoad() {
  383. super.windowDidLoad()
  384. }
  385. override func initContentView() {
  386. super.initContentView()
  387. configFormPopUI()
  388. congfigFontPopUI()
  389. congfigGeneraPopUI()
  390. congfigShapePopUI()
  391. paneSelectorItem.properties = ComponentCSelectorProperty(iconImage:NSImage(named: "KMNImageNameListViewPopPane"))
  392. paneSelectorItem.setTarget(self, action: #selector(paneButtonClicked(_ :)))
  393. fontSizeZoomOutButton.properties = ComponentButtonProperty(type: .text_gray,
  394. size: .s,
  395. state: .normal,
  396. onlyIcon: true,
  397. icon:NSImage(named: "KMNImageNameListViewPopFontSizeZoomOut"),
  398. keepPressState: false)
  399. fontSizeZoomOutButton.setTarget(self, action: #selector(fontSizeZoomOutButtonClicked(_ :)))
  400. fontSizeZoomInButton.properties = ComponentButtonProperty(type: .text_gray,
  401. size: .s,
  402. state: .normal,
  403. onlyIcon: true,
  404. icon:NSImage(named: "KMNImageNameListViewPopFontSizeZoomIn"),
  405. keepPressState: false)
  406. fontSizeZoomInButton.setTarget(self, action: #selector(fontSizeZoomInButtonClicked(_ :)))
  407. fontAlightButton.properties = ComponentButtonProperty(type: .text_gray,
  408. size: .s,
  409. state: .normal,
  410. onlyIcon: true,
  411. icon:NSImage(named: "KMNImageNameListViewPopAlightLeft"))
  412. fontAlightButton.setTarget(self, action: #selector(fontAlightButtonClicked(_ :)))
  413. widthZoomOutButton.properties = ComponentButtonProperty(type: .text_gray,
  414. size: .s,
  415. state: .normal,
  416. onlyIcon: true,
  417. icon:NSImage(named: "KMNImageNameListViewPopWidthZoomOut"),
  418. keepPressState: false)
  419. widthZoomOutButton.setTarget(self, action: #selector(widthZoomOutButtonClicked(_ :)))
  420. widthZoomInButton.properties = ComponentButtonProperty(type: .text_gray,
  421. size: .s,
  422. state: .normal,
  423. onlyIcon: true,
  424. icon:NSImage(named: "KMNImageNameListViewPopWidthZoomIn"),
  425. keepPressState: false)
  426. widthZoomInButton.setTarget(self, action: #selector(widthZoomInButtonClicked(_ :)))
  427. pageLinkButton.setTarget(self, action: #selector(pageLinkButtonClicked(_ :)))
  428. urlLinkButton.setTarget(self, action: #selector(urlLinkButtonClicked(_ :)))
  429. emailLinkButton.setTarget(self, action: #selector(emailLinkButtonClicked(_ :)))
  430. alightButton.properties = ComponentButtonProperty(type: .text_gray,
  431. size: .s,
  432. state: .normal,
  433. onlyIcon: true,
  434. icon:NSImage(named: "KMNImageNameObjectPopAlightLeft"))
  435. alightButton.setTarget(self, action: #selector(alightButtonClicked(_ :)))
  436. goUrlLinkButton.properties = ComponentButtonProperty(type: .text_gray,
  437. size: .s,
  438. state: .normal,
  439. onlyIcon: true,
  440. icon:NSImage(named: "KMNImageNamePopLinkGO"),keepPressState: false)
  441. goUrlLinkButton.setTarget(self, action: #selector(linkGoButtonClicked(_ :)))
  442. goPageLinkButton.properties = ComponentButtonProperty(type: .text_gray,
  443. size: .s,
  444. state: .normal,
  445. onlyIcon: true,
  446. icon:NSImage(named: "KMNImageNamePopLinkGO"),keepPressState: false)
  447. goPageLinkButton.setTarget(self, action: #selector(linkGoButtonClicked(_ :)))
  448. paginationView.properties = ComponentPaginationProperty(doubleArrow_show: false, currentIndex: 0, totalCount: 1)
  449. paginationView.delegate = self
  450. let inputFiedProperty: ComponentInputProperty = ComponentInputProperty(size: .s,
  451. state:.pressed ,
  452. isError: false,
  453. showPrefix: false,
  454. showSuffix: false,
  455. showClear: false,
  456. isDisabled: false,
  457. placeholder: KMNCompanyWebsite,
  458. text: "")
  459. urlInput.properties = inputFiedProperty
  460. urlInput.delegate = self
  461. }
  462. override func updateUIThemeColor() {
  463. super.updateUIThemeColor()
  464. lineBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider")
  465. contentBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/popup")
  466. contentBox.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/3-default")
  467. paginationDesBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorFill/4")
  468. paginationDesBox.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/4")
  469. pageThumImageView.wantsLayer = true
  470. paginationDesBox.layer?.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider").cgColor
  471. }
  472. override func updateUILanguage() {
  473. super.updateUILanguage()
  474. pageLinkButton.properties = ComponentButtonProperty(type: .text_gray,
  475. size: .s,
  476. state: .normal,
  477. onlyIcon: false,
  478. showLeftIcon:true,
  479. buttonText:KMLocalizedString("Page"),
  480. icon:NSImage(named: "KMNImageNameListViewLinkPage"),keepPressState: false)
  481. urlLinkButton.properties = ComponentButtonProperty(type: .text_gray,
  482. size: .s,
  483. state: .normal,
  484. onlyIcon: false,
  485. showLeftIcon:true,
  486. buttonText:KMLocalizedString("Web"),
  487. icon:NSImage(named: "KMNImageNameListViewLinkUrl"),keepPressState: false)
  488. emailLinkButton.properties = ComponentButtonProperty(type: .text_gray,
  489. size: .s,
  490. state: .normal,
  491. onlyIcon: false,
  492. showLeftIcon:true,
  493. buttonText:KMLocalizedString("Email"),
  494. icon:NSImage(named: "KMNImageNameListViewLinkEmail"),keepPressState: false)
  495. pageLinkWidthConstraint.constant = pageLinkButton.properties.propertyInfo.viewWidth
  496. urlLinkWidthConstraint.constant = urlLinkButton.properties.propertyInfo.viewWidth
  497. emailLinkWidthConstraint.constant = emailLinkButton.properties.propertyInfo.viewWidth
  498. backUrlLinkButton.properties = ComponentButtonProperty(type: .text_primary,
  499. size: .s,
  500. state: .normal,
  501. onlyIcon: false,
  502. showLeftIcon: true,
  503. buttonText: KMLocalizedString("Back"),
  504. icon:NSImage(named: "KMNImageNamePopLinkBack"),keepPressState: false)
  505. backUrlLinkButton.setTarget(self, action: #selector(linkBackButtonClicked(_ :)))
  506. backUrlWidthConstraint.constant = backUrlLinkButton.properties.propertyInfo.viewWidth
  507. backUrlLinkButton.reloadData()
  508. backPageLinkButton.properties = ComponentButtonProperty(type: .text_primary,
  509. size: .s,
  510. onlyIcon: false,
  511. showLeftIcon:true,
  512. buttonText: KMLocalizedString("Back"),
  513. icon:NSImage(named: "KMNImageNamePopLinkBack"),keepPressState: false)
  514. backPageLinkButton.setTarget(self, action: #selector(linkBackButtonClicked(_ :)))
  515. backPageWidthConstraint.constant = backPageLinkButton.properties.propertyInfo.viewWidth
  516. }
  517. //MARK: - Public
  518. public func updateFrame(listView:CPDFListView) {
  519. let activeAnnotations = annotationPopMode.annotations
  520. let page = activeAnnotations.first?.page
  521. let windowFram = listView.window?.frame ?? CGRectZero
  522. if(page != nil) {
  523. let pageRect = listView.selectionMultipleBounds(with: activeAnnotations)
  524. let positioningRect = listView.convert(pageRect, from: page!)
  525. if (CGRectIntersectsRect(positioningRect, listView.frame)) {
  526. let view: NSView? = nil
  527. let position = listView.convert(positioningRect, to: view)
  528. var positionNew = position.origin
  529. positionNew.x += windowFram.origin.x + position.width/2
  530. positionNew.y += windowFram.origin.y + position.height
  531. var positionRect = self.window?.frame ?? CGRectZero
  532. positionRect.origin.x = positionNew.x - positionRect.width/2
  533. positionRect.origin.y = positionNew.y + popOffSet
  534. var listViewWindRect = listView.convert(listView.frame, to: view)
  535. listViewWindRect.origin.x += windowFram.origin.x
  536. listViewWindRect.origin.y += windowFram.origin.y
  537. if CGRectGetMaxY(positionRect) > CGRectGetMaxY(listViewWindRect) {
  538. positionRect.origin.y = positionNew.y - popOffSet - position.height - positionRect.size.height
  539. }
  540. if CGRectGetMinX(positionRect) < CGRectGetMinX(listViewWindRect) {
  541. positionRect.origin.x = CGRectGetMinX(listViewWindRect)
  542. }
  543. if CGRectGetMaxX(positionRect) > CGRectGetMaxX(listViewWindRect) {
  544. positionRect.origin.x = CGRectGetMaxX(listViewWindRect) - positionRect.width
  545. }
  546. self.window?.setFrame(positionRect, display: true)
  547. updateUILanguage()
  548. } else {
  549. }
  550. }
  551. }
  552. public func closeWindow(listView:CPDFListView?) {
  553. if self.window?.isVisible == true {
  554. listView?.window?.removeChildWindow(self.window ?? NSWindow())
  555. self.window?.close()
  556. }
  557. if ObjectPopover?.isShown == true {
  558. ObjectPopover?.close()
  559. }
  560. if fontPopover?.isShown == true {
  561. fontPopover?.close()
  562. }
  563. }
  564. //MARK: - private
  565. private func congfigGeneraPopUI() {
  566. var colors = KMAnnotationPropertiesColorManager.manager.markHighlightColors
  567. if(annotationPopMode.annotation is CPDFMarkupAnnotation) {
  568. let markupAnnotation:CPDFMarkupAnnotation = annotationPopMode.annotation as! CPDFMarkupAnnotation
  569. if markupAnnotation.markupType() == .highlight {
  570. colors = KMAnnotationPropertiesColorManager.manager.markHighlightColors
  571. } else {
  572. colors = KMAnnotationPropertiesColorManager.manager.markOtherColors
  573. }
  574. }
  575. let colorAProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[0])
  576. let colorBProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[1])
  577. let colorCProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[2])
  578. let colorDProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[3])
  579. let colorEProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: true, color: colors[4])
  580. generaColorGroup.setUpWithColorPropertys([colorAProperty, colorBProperty, colorCProperty, colorDProperty], customItemProperty: colorEProperty)
  581. generaColorGroup.delegate = self
  582. }
  583. private func congfigFontPopUI() {
  584. fontNameSelect.properties = ComponentSelectProperties(size: .s,
  585. state: .normal,
  586. isDisabled: false,
  587. isError: false,
  588. leftIcon: false,
  589. placeholder: nil,
  590. errorText: nil,
  591. creatable: false,
  592. text: NSLocalizedString("", comment: ""))
  593. fontNameSelect.delegate = self
  594. var menuItemArr: [ComponentMenuitemProperty] = []
  595. for familyName in CPDFFont.familyNames {
  596. let fontNames = CPDFFont.fontNames(forFamilyName: familyName)
  597. let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  598. itemSelected: false,
  599. isDisabled: false,
  600. keyEquivalent: nil,
  601. text: familyName,identifier: "1")
  602. var subMenuItemArr: [ComponentMenuitemProperty] = []
  603. for fontName in fontNames {
  604. let subItemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  605. itemSelected: false,
  606. isDisabled: false,
  607. keyEquivalent: nil,
  608. text: fontName,identifier: "2")
  609. subMenuItemArr.append(subItemProperty)
  610. }
  611. itemProperty.subPropertys = subMenuItemArr
  612. menuItemArr.append(itemProperty)
  613. }
  614. fontNameSelect.updateMenuItemsArr(menuItemArr)
  615. fontColorItem.properties = ComponentCColorProperty(colorType: .color,
  616. state: .normal,
  617. isCustom: true,
  618. color: NSColor.red)
  619. fontColorItem.delegate = self
  620. fontColorItem.reloadData()
  621. }
  622. private func congfigShapePopUI() {
  623. var colors = KMAnnotationPropertiesColorManager.manager.inkColors
  624. let annotation = annotationPopMode.annotation ?? CPDFAnnotation()
  625. if annotation.isKind(of: CPDFInkAnnotation.self) {
  626. colors = KMAnnotationPropertiesColorManager.manager.inkColors
  627. } else if annotation.isKind(of: CPDFCircleAnnotation.self) ||
  628. annotation.isKind(of: CPDFSquareAnnotation.self) {
  629. colors = KMAnnotationPropertiesColorManager.manager.inkColors
  630. } else if annotation.isKind(of: CPDFLineAnnotation.self) {
  631. if let lineAnnotation:CPDFLineAnnotation = annotation as? CPDFLineAnnotation {
  632. if lineAnnotation.isMeasure {
  633. colors = KMAnnotationPropertiesColorManager.manager.measure_Border_Colors
  634. } else {
  635. colors = KMAnnotationPropertiesColorManager.manager.inkColors
  636. }
  637. }
  638. } else if (annotation.isKind(of: CPDFPolygonAnnotation.self) ||
  639. annotation.isKind(of: CPDFPolylineAnnotation.self)) {
  640. colors = KMAnnotationPropertiesColorManager.manager.measure_Border_Colors
  641. } else if annotation.isKind(of: CPDFTextAnnotation.self) {
  642. colors = KMAnnotationPropertiesColorManager.manager.anchoredNoteColors
  643. } else if annotation.isKind(of: CSelfSignAnnotation.self) {
  644. colors = KMAnnotationPropertiesColorManager.manager.selfSignColors
  645. }
  646. let colorAProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[0])
  647. let colorBProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[1])
  648. let colorCProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[2])
  649. let colorDProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: colors[3])
  650. let colorEProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: true, color: colors[4])
  651. shapeColorGroup.setUpWithColorPropertys([colorAProperty, colorBProperty, colorCProperty, colorDProperty], customItemProperty: colorEProperty)
  652. shapeColorGroup.delegate = self
  653. }
  654. private func configFormPopUI() {
  655. let inputFiedProperty: ComponentInputProperty = ComponentInputProperty(size: .s,
  656. state:.pressed ,
  657. isError: false,
  658. showPrefix: false,
  659. showSuffix: false,
  660. showClear: false,
  661. isDisabled: false,
  662. placeholder: "File Name",
  663. text: "")
  664. fildNameInput.properties = inputFiedProperty
  665. fildNameInput.delegate = self
  666. let inputGropProperty: ComponentInputProperty = ComponentInputProperty(size: .s,
  667. state:.pressed ,
  668. isError: false,
  669. showPrefix: false,
  670. showSuffix: false,
  671. showClear: false,
  672. isDisabled: false,
  673. placeholder: "Grop Name",
  674. text: "")
  675. gropNameInput.properties = inputGropProperty
  676. gropNameInput.delegate = self
  677. }
  678. private func reloadPageUrlData() {
  679. if let destination = linkAnnotation.destination() {
  680. if let page = destination.page() {
  681. paginationView.properties.currentIndex = Int(page.pageIndex() + 1)
  682. paginationView.reloadData()
  683. return
  684. }
  685. }
  686. paginationView.properties.currentIndex = Int(((listView?.currentPageIndex ?? 0) + 1))
  687. paginationView.reloadData()
  688. }
  689. private func refreshPageThum() {
  690. guard let pdfView = listView else {
  691. return
  692. }
  693. let thumbnail = KMNThumbnail.init(document: pdfView.document, currentPageIndex:Int(paginationView.properties.currentIndex - 1))
  694. thumbnail.generateThumImage {[weak self] image in
  695. self?.pageThumImageView.image = image
  696. }
  697. }
  698. //MARK: - Action
  699. @objc func paneButtonClicked(_ sender: NSView) {
  700. isOpenPane = !isOpenPane
  701. paneCallback?(isOpenPane)
  702. }
  703. @objc func fontSizeZoomOutButtonClicked(_ sender: NSView) {
  704. if let freeText = annotationPopMode.annotation as? CPDFFreeTextAnnotation {
  705. if listView?.isEdit(withCurrentFreeText: freeText) == true {
  706. listView?.commitEditAnnotationFreeText(freeText)
  707. }
  708. if annotationPopMode.zoomOutFontSize() {
  709. updatePDFViewCallback?()
  710. }
  711. }
  712. }
  713. @objc func fontSizeZoomInButtonClicked(_ sender: NSView) {
  714. if let freeText = annotationPopMode.annotation as? CPDFFreeTextAnnotation {
  715. if listView?.isEdit(withCurrentFreeText: freeText) == true {
  716. listView?.commitEditAnnotationFreeText(freeText)
  717. }
  718. if annotationPopMode.zoomInFontSize() {
  719. updatePDFViewCallback?()
  720. }
  721. }
  722. }
  723. @objc func fontAlightButtonClicked(_ sender: NSView) {
  724. if fontPopover?.isShown == true {
  725. fontPopover?.close()
  726. } else {
  727. let vc = KMNPopDetailsViewController(nibName: "KMNPopDetailsViewController", bundle: nil)
  728. let createFilePopover: NSPopover = NSPopover.init()
  729. createFilePopover.contentViewController = vc
  730. createFilePopover.delegate = self
  731. createFilePopover.animates = true
  732. createFilePopover.behavior = .semitransient
  733. createFilePopover.setValue(true, forKey: "shouldHideAnchor")
  734. createFilePopover.show(relativeTo: CGRect(x: sender.bounds.origin.x, y: 20, width: sender.bounds.size.width, height: sender.bounds.size.height), of: sender, preferredEdge: .maxY)
  735. vc.detailPopType = .freeTextAlight
  736. vc.fontChangeAlighCallback = { [weak self] alight in
  737. if let freeText = self?.annotationPopMode.annotation as? CPDFFreeTextAnnotation {
  738. if self?.listView?.isEdit(withCurrentFreeText: freeText) == true {
  739. self?.listView?.commitEditAnnotationFreeText(freeText)
  740. }
  741. }
  742. self?.annotationPopMode.setAnnotationAlignment(annotationAlignment: alight)
  743. self?.updatePDFViewCallback?()
  744. self?.fontAlight = alight
  745. }
  746. fontPopover = createFilePopover
  747. vc.fontAlight = fontAlight
  748. }
  749. }
  750. @objc func widthZoomOutButtonClicked(_ sender: NSView) {
  751. if annotationPopMode.zoomOutShapeWidth() {
  752. updatePDFViewCallback?()
  753. }
  754. }
  755. @objc func widthZoomInButtonClicked(_ sender: NSView) {
  756. if annotationPopMode.zoomInShapeWidth() {
  757. updatePDFViewCallback?()
  758. }
  759. }
  760. @objc func pageLinkButtonClicked(_ sender: NSView) {
  761. linkType = .page
  762. }
  763. @objc func urlLinkButtonClicked(_ sender: NSView) {
  764. linkType = .url
  765. }
  766. @objc func emailLinkButtonClicked(_ sender: NSView) {
  767. linkType = .email
  768. }
  769. @objc func alightButtonClicked(_ sender: NSView) {
  770. if ObjectPopover?.isShown == true {
  771. ObjectPopover?.close()
  772. } else {
  773. let vc = KMNPopDetailsViewController(nibName: "KMNPopDetailsViewController", bundle: nil)
  774. let createFilePopover: NSPopover = NSPopover.init()
  775. createFilePopover.contentViewController = vc
  776. createFilePopover.delegate = self
  777. createFilePopover.animates = true
  778. createFilePopover.behavior = .semitransient
  779. createFilePopover.setValue(true, forKey: "shouldHideAnchor")
  780. createFilePopover.show(relativeTo: CGRect(x: sender.bounds.origin.x, y: 20, width: sender.bounds.size.width, height: sender.bounds.size.height), of: sender, preferredEdge: .maxY)
  781. if (annotationPopMode.annotations.count == 2) {
  782. vc.detailPopType = .freeTextDoubleAlight
  783. } else if (annotationPopMode.annotations.count > 2) {
  784. vc.detailPopType = .freeTextMultpleAlight
  785. }
  786. vc.objectChangeAlighCallback = { [weak self] alight in
  787. self?.objectAlignType = alight
  788. self?.updatePDFViewCallback?()
  789. }
  790. ObjectPopover = createFilePopover
  791. vc.objectAlignType = objectAlignType
  792. }
  793. }
  794. @objc func linkGoButtonClicked(_ sender: NSView) {
  795. if linkType == .url {
  796. guard let webString = linkAnnotation.url() else { return }
  797. if let data = URL(string: webString) {
  798. NSWorkspace.shared.open(data)
  799. }
  800. } else if linkType == .email {
  801. guard let emailString = linkAnnotation.url() else {
  802. let alert = NSAlert()
  803. alert.alertStyle = .critical
  804. alert.messageText = NSLocalizedString("Invalid Email. Please try again.", comment: "")
  805. alert.runModal()
  806. return
  807. }
  808. if KMNTools.isValidateEmail(emailString) {
  809. let alert = NSAlert()
  810. alert.alertStyle = .critical
  811. alert.messageText = NSLocalizedString("Invalid Email. Please try again.", comment: "")
  812. alert.runModal()
  813. } else {
  814. NSWorkspace.shared.open(URL(string: emailString)!)
  815. }
  816. } else if linkType == .page {
  817. if let destination = linkAnnotation.destination() {
  818. listView?.go(to: destination)
  819. closeWindow(listView: listView)
  820. }
  821. }
  822. }
  823. @objc func linkBackButtonClicked(_ sender: NSView) {
  824. linkType = .linkSetting
  825. }
  826. @objc func fontColorChange(_ sender: Any) {
  827. if let color = (sender as? NSColorPanel)?.color {
  828. if let freeText = annotationPopMode.annotation as? CPDFFreeTextAnnotation {
  829. if listView?.isEdit(withCurrentFreeText: freeText) == true {
  830. listView?.commitEditAnnotationFreeText(freeText)
  831. }
  832. }
  833. annotationPopMode.setAnnotationFontColor(annotationFontColor: color)
  834. fontColor = color
  835. updatePDFViewCallback?()
  836. }
  837. }
  838. }
  839. //MARK: - ComponentCColorDelegate
  840. extension KMNPopAnnotationWindowController: ComponentCColorDelegate {
  841. func componentCColorDidChooseColor(_ view: NSView, _ color: NSColor?) {
  842. if(view == generaColorGroup) {
  843. self.annotationPopMode.setAnnotationColor(annotationColor: color)
  844. updatePDFViewCallback?()
  845. } else if (view == shapeColorGroup) {
  846. self.annotationPopMode.setAnnotationColor(annotationColor: color)
  847. updatePDFViewCallback?()
  848. } else if (view == fontColorItem) {
  849. fontColorItem.properties?.state = .normal
  850. fontColorItem.reloadData()
  851. let colorPanel = NSColorPanel.shared
  852. colorPanel.setTarget(self)
  853. colorPanel.showsAlpha = false
  854. colorPanel.setAction(#selector(self.fontColorChange(_:)))
  855. colorPanel.orderFront(nil)
  856. }
  857. }
  858. }
  859. //MARK: - ComponentInputDelegate
  860. extension KMNPopAnnotationWindowController: ComponentInputDelegate {
  861. func componentInputDidChanged(inputView: ComponentInput) {
  862. if (inputView == fildNameInput) {
  863. for i in 0 ..< annotationPopMode.annotations.count {
  864. let annotation = annotationPopMode.annotations[i]
  865. if let widgt = annotation as? CPDFWidgetAnnotation {
  866. widgt.setFieldName(inputView.properties.text)
  867. }
  868. }
  869. updatePDFViewCallback?()
  870. } else if (inputView == gropNameInput) {
  871. for i in 0 ..< annotationPopMode.annotations.count {
  872. let annotation = annotationPopMode.annotations[i]
  873. if let button = annotation as? CPDFButtonWidgetAnnotation {
  874. button.setButtonWidgetStateString(inputView.properties.text)
  875. }
  876. }
  877. updatePDFViewCallback?()
  878. } else if (inputView == urlInput) {
  879. }
  880. }
  881. func componentInputDidEndEditing(inputView: ComponentInput) {
  882. if (inputView == fildNameInput) {
  883. } else if (inputView == gropNameInput) {
  884. } else if (inputView == urlInput) {
  885. if linkType == .email {
  886. let emailString = urlInput.properties.text
  887. if KMNTools.isValidateEmail(emailString) {
  888. linkAnnotation.setDestination(nil)
  889. let linkUrlPath = KMNTools.judgeEmailURL(emailString)
  890. linkAnnotation.setURL(linkUrlPath)
  891. updatePDFViewCallback?()
  892. }
  893. } else if linkType == .url {
  894. let webString = urlInput.properties.text
  895. linkAnnotation.setDestination(nil)
  896. let linkUrlPath = KMNTools.judgeWebURL(webString)
  897. linkAnnotation.setURL(linkUrlPath)
  898. updatePDFViewCallback?()
  899. }
  900. }
  901. }
  902. }
  903. //MARK: - ComponentSelectDelegate
  904. extension KMNPopAnnotationWindowController: ComponentSelectDelegate {
  905. func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) {
  906. if(view == fontNameSelect) {
  907. if menuItemProperty?.identifier == "1" {
  908. let familyName = fontNameSelect.properties.text ?? "Helvetica"
  909. let styles = CPDFFont.fontNames(forFamilyName: familyName)
  910. compdfFont = CPDFFont(familyName: familyName, fontStyle: styles.first ?? "")
  911. annotationPopMode.setAnnotationFont(font: compdfFont ?? CPDFFont.init(familyName: "Helvetica", fontStyle: ""))
  912. } else if menuItemProperty?.identifier == "2"{ //字体样式
  913. compdfFont = CPDFFont(familyName: compdfFont?.familyName ?? "Helvetica", fontStyle: menuItemProperty?.text ?? "")
  914. annotationPopMode.setAnnotationFont(font: compdfFont ?? CPDFFont.init(familyName: "Helvetica", fontStyle: ""))
  915. }
  916. }
  917. }
  918. }
  919. //MARK: - ComponentSelectDelegate
  920. extension KMNPopAnnotationWindowController: NSPopoverDelegate {
  921. func popoverWillClose(_ notification: Notification) {
  922. if fontPopover == (notification.object as? NSPopover) {
  923. if(fontAlightButton.properties.state == .pressed) {
  924. fontAlightButton.properties.state = .normal
  925. fontAlightButton.reloadData()
  926. }
  927. } else if ObjectPopover == (notification.object as? NSPopover) {
  928. if(alightButton.properties.state == .pressed) {
  929. alightButton.properties.state = .normal
  930. alightButton.reloadData()
  931. }
  932. }
  933. }
  934. }
  935. //MARK: - ComponentPaginationDelegate
  936. extension KMNPopAnnotationWindowController: ComponentPaginationDelegate {
  937. public func componentPaginationDidValueChanged(pagination: ComponentPagination) {
  938. let pageIndex = pagination.properties.currentIndex
  939. if let page = listView?.document.page(at: UInt(pageIndex)) {
  940. linkAnnotation.setURL(nil)
  941. let destination = CPDFDestination(document: listView?.document ?? CPDFDocument(), pageIndex: Int(paginationView.properties.currentIndex - 1))
  942. linkAnnotation.setDestination(destination)
  943. refreshPageThum()
  944. reloadPageUrlData()
  945. updatePDFViewCallback?()
  946. }
  947. }
  948. }