KMNPopAnnotationViewController.swift 50 KB

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