KMOutlineViewController.swift 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  1. //
  2. // KMOutlineViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lxy on 2022/10/10.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. class KMOutlineViewController: KMNBaseViewController {
  10. @IBOutlet var contendView: NSView!
  11. @IBOutlet weak var topView: NSView!
  12. @IBOutlet weak var titleLabel: NSTextField!
  13. @IBOutlet weak var lineView: NSView!
  14. @IBOutlet weak var addButton: NSButton!
  15. @IBOutlet weak var moreButton: NSButton!
  16. @IBOutlet var topSepline: NSView!
  17. @IBOutlet weak var emptyView: NSView!
  18. @IBOutlet weak var bigTipLabel: NSTextField!
  19. @IBOutlet weak var tipLabel: NSTextField!
  20. @IBOutlet weak var BOTAOutlineView: KMBOTAOutlineView!
  21. var dragPDFOutline : KMBOTAOutlineItem!
  22. var renameTextField : NSTextField!
  23. // var listView : CPDFListView!
  24. var renamePDFOutline : KMBOTAOutlineItem!
  25. let moreMenu = NSMenu()
  26. var isLocalEvent = false
  27. var handdler = KMNOutlineHanddler()
  28. private lazy var searchButton_: ComponentButton = {
  29. let view = ComponentButton()
  30. view.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, state: .normal, isDisable: false, onlyIcon: true)
  31. return view
  32. }()
  33. private lazy var addButton_: ComponentButton = {
  34. let view = ComponentButton()
  35. view.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, state: .normal, isDisable: false, onlyIcon: true, keepPressState: false)
  36. return view
  37. }()
  38. private lazy var moreDropdown_: ComponentDropdown = {
  39. let view = ComponentDropdown()
  40. view.properties = ComponentDropdownProperty(type: .split_primary, size: .xxs, state: .normal, split: false, disabled: false)
  41. return view
  42. }()
  43. private lazy var headerSearchView_: KMNBotaHeaderSearchView? = {
  44. let view = KMNBotaHeaderSearchView.createFromNib()
  45. return view
  46. }()
  47. private var emptyView_: ComponentEmpty = {
  48. let view = ComponentEmpty()
  49. view.properties = ComponentEmptyProperty(emptyType: .noOutline, state: .normal, image: NSImage(named: "KMImageNameOutlineEmpty"), text: KMLocalizedString("No Outline"), subText: KMLocalizedString("Here is the description."))
  50. return view
  51. }()
  52. private var groupView_: ComponentGroup?
  53. private var menuGroupView_: ComponentGroup?
  54. deinit {
  55. self.BOTAOutlineView.delegate = nil
  56. }
  57. override func viewWillDisappear() {
  58. super.viewWillDisappear()
  59. self.cancelSelect()
  60. }
  61. override func viewDidLoad() {
  62. super.viewDidLoad()
  63. handdler.delegate = self
  64. self.addOutlineMenu()
  65. titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-bold")
  66. self.topView.wantsLayer = true
  67. addButton.image = nil
  68. topView.addSubview(searchButton_)
  69. searchButton_.km_add_size_constraint(size: NSMakeSize(24, 24))
  70. searchButton_.km_add_centerY_constraint(constant: 1)
  71. searchButton_.km_add_trailing_constraint(equalTo: addButton, attribute: .leading, constant: -4)
  72. searchButton_.setTarget(self, action: #selector(_searchAction))
  73. addButton.addSubview(addButton_)
  74. addButton_.km_add_size_constraint(size: NSMakeSize(24, 24))
  75. addButton_.km_add_centerX_constraint()
  76. addButton_.km_add_centerY_constraint()
  77. addButton_.setTarget(self, action: #selector(addNewOutline))
  78. moreButton.image = nil
  79. moreButton.addSubview(moreDropdown_)
  80. moreDropdown_.km_add_size_constraint(size: NSMakeSize(24, 24))
  81. moreDropdown_.km_add_centerX_constraint()
  82. moreDropdown_.km_add_centerY_constraint()
  83. moreDropdown_.componentDelegate = self
  84. if let data = headerSearchView_ {
  85. topView.addSubview(data)
  86. headerSearchView_?.frame = topView.bounds
  87. headerSearchView_?.autoresizingMask = [.width, .height]
  88. }
  89. _hideHeaderSearch()
  90. headerSearchView_?.itemClick = { [weak self] idx, _ in
  91. if idx == 1 { // 忽略大小写
  92. } else if idx == 2 { // 关闭搜索
  93. self?._hideHeaderSearch()
  94. }
  95. }
  96. emptyView.wantsLayer = true
  97. bigTipLabel.stringValue = ""
  98. tipLabel.stringValue = ""
  99. emptyView.addSubview(emptyView_)
  100. emptyView_.km_add_top_constraint(constant: 232)
  101. emptyView_.km_add_bottom_constraint()
  102. emptyView_.km_add_leading_constraint()
  103. emptyView_.km_add_trailing_constraint()
  104. self.BOTAOutlineView.delegate = self
  105. self.BOTAOutlineView.inputData = self.handdler.outlineRoot()
  106. self.BOTAOutlineView.outlineView.doubleAction = #selector(outlineViewDoubleAction)
  107. }
  108. // To create an outline, please right-click on the selected page and choose \"Add Outline\", or click \"Add\" in the upper right corner.
  109. override func updateUILanguage() {
  110. super.updateUILanguage()
  111. KMMainThreadExecute {
  112. self.titleLabel.stringValue = KMLocalizedString("Outline")
  113. self.moreButton.toolTip = KMLocalizedString("More")
  114. self.addButton.toolTip = KMLocalizedString("Add Outline")
  115. }
  116. }
  117. override func updateUIThemeColor() {
  118. super.updateUIThemeColor()
  119. KMMainThreadExecute {
  120. self.contendView.wantsLayer = true
  121. let color = KMNColorTools.colorBg_layoutMiddle()
  122. self.contendView.layer?.backgroundColor = color.cgColor
  123. self.headerSearchView_?.wantsLayer = true
  124. self.headerSearchView_?.layer?.backgroundColor = color.cgColor
  125. self.headerSearchView_?.bottomLine.wantsLayer = true
  126. self.headerSearchView_?.bottomLine.layer?.backgroundColor = KMNColorTools.colorPrimary_border1().cgColor
  127. self.titleLabel.textColor = KMNColorTools.colorText_2()
  128. self.addButton_.properties.icon = NSImage(named: "KMBookmarkAdd")
  129. self.addButton_.reloadData()
  130. self.searchButton_.properties.icon = NSImage(named: "KMImageNameOutlineSearch")
  131. self.searchButton_.reloadData()
  132. let dividerColor = KMNColorTools.colorBorder_divider()
  133. self.topSepline.wantsLayer = true
  134. self.topSepline.layer?.backgroundColor = dividerColor.cgColor
  135. self.lineView.backgroundColor(dividerColor)
  136. }
  137. }
  138. override func addNotifations() {
  139. super.addNotifations()
  140. NotificationCenter.default.addObserver(self, selector: #selector(KMPDFViewCurrentPageDidChangedNotification), name: NSNotification.Name.init(rawValue: "KMPDFViewCurrentPageDidChanged"), object: nil)
  141. }
  142. private func addOutlineMenu(){
  143. moreMenu.addItem(withTitle: NSLocalizedString("Expand All", comment: ""), action: #selector(expandAllComments), target: self, tag: 0)
  144. moreMenu.addItem(withTitle: NSLocalizedString("Collapse All", comment: ""), action: #selector(collapseAllComments), target: self, tag: 1)
  145. moreMenu.addItem(withTitle: NSLocalizedString("Remove All Outlines", comment: ""), action: #selector(removeAllOutlineItem), target: self, tag: 2)
  146. }
  147. func addRightMenu(view: NSView, event: NSEvent) {
  148. let menus : NSMenu = NSMenu(title: "")
  149. let addItem = self.menuItemWithTitle(title: NSLocalizedString("Add Item", comment: ""), action: #selector(addItemAction))
  150. let addChildItem = self.menuItemWithTitle(title: NSLocalizedString("Add Sub-Item", comment: ""), action: #selector(addChildItemAction))
  151. let addHigherItem = self.menuItemWithTitle(title: NSLocalizedString("Add A Higher Level", comment: ""), action: #selector(addHigherItemAction))
  152. let deleteItem = self.menuItemWithTitle(title: NSLocalizedString("Delete", comment: ""), action: #selector(deleteItemAction))
  153. // let editItem = self.menuItemWithTitle(title: NSLocalizedString("Edit", comment: ""), action: #selector(editItemAction))
  154. let renameItem = self.menuItemWithTitle(title: NSLocalizedString("Rename", comment: ""), action: #selector(renameItemAction))
  155. let changeItem = self.menuItemWithTitle(title: NSLocalizedString("Change Destination", comment: ""), action: #selector(changeItemAction))
  156. let promoteItem = self.menuItemWithTitle(title: NSLocalizedString("Promote", comment: ""), action: #selector(promoteItemAction))
  157. let demoteItem = self.menuItemWithTitle(title: NSLocalizedString("Demote", comment: ""), action: #selector(demoteItemAction))
  158. menus.addItem(addItem)
  159. menus.addItem(addChildItem)
  160. menus.addItem(addHigherItem)
  161. menus.addItem(NSMenuItem.separator())
  162. menus.addItem(deleteItem)
  163. menus.addItem(NSMenuItem.separator())
  164. // menus.addItem(editItem)
  165. menus.addItem(renameItem)
  166. menus.addItem(changeItem)
  167. menus.addItem(NSMenuItem.separator())
  168. menus.addItem(promoteItem)
  169. menus.addItem(demoteItem)
  170. // let point = view.convert(event.locationInWindow, from: nil)
  171. // menus.popUp(positioning: nil, at: point, in: view)
  172. // let idxs = self?.bookTableView.selectedRowIndexes.count ?? 0
  173. //
  174. // let tempView = self?.bookTableView.rowView(atRow: row, makeIfNecessary: false)
  175. let point = event.locationInWindow
  176. let tempView = view
  177. var viewHeight: CGFloat = 0
  178. let items: [String] = ["Add Item", "Add Sub-Item", "Add A Higher Level","", "Delete","", "Edit", "Rename", "Change Destination","", "Promote", "Demote"]
  179. var menuItemArr: [ComponentMenuitemProperty] = []
  180. for value in items {
  181. if value.count == 0 {
  182. let property: ComponentMenuitemProperty = ComponentMenuitemProperty.divider()
  183. menuItemArr.append(property)
  184. viewHeight += 8
  185. } else {
  186. let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  187. itemSelected: false,
  188. isDisabled: false,
  189. keyEquivalent: nil,
  190. text: KMLocalizedString(value),
  191. identifier: value)
  192. menuItemArr.append(properties_Menuitem)
  193. viewHeight += 36
  194. }
  195. }
  196. if self.BOTAOutlineView.outlineView.selectedRowIndexes.count > 1 {
  197. // if action == #selector(deleteItemAction) {
  198. // return true
  199. // }
  200. // return false
  201. for data in menuItemArr {
  202. if data.text == KMLocalizedString("Delete") {
  203. data.isDisabled = false
  204. } else {
  205. data.isDisabled = true
  206. }
  207. }
  208. if menuGroupView_ == nil {
  209. menuGroupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  210. }
  211. if menuGroupView_ != nil {
  212. menuGroupView_?.clickedAutoHide = false
  213. menuGroupView_?.groupDelegate = self
  214. menuGroupView_?.frame = CGRectMake(0, 0, 180, viewHeight)
  215. menuGroupView_?.updateGroupInfo(menuItemArr)
  216. menuGroupView_?.showWithPoint(CGPoint(x: point.x, y: point.y - viewHeight), relativeTo: tempView)
  217. }
  218. return
  219. } else if self.BOTAOutlineView.outlineView.selectedRowIndexes.count > 0 {
  220. // if action == #selector(addChildItemAction) || action == #selector(changeItemAction) {
  221. // return true
  222. // }
  223. for data in menuItemArr {
  224. if data.text == KMLocalizedString("Add Sub-Item") || data.text == KMLocalizedString("Change Destination") {
  225. data.isDisabled = false
  226. } else {
  227. // data.isDisabled = true
  228. }
  229. }
  230. }
  231. if self.BOTAOutlineView.outlineView.clickedRow == -1 {
  232. // if action == #selector(addItemAction) {
  233. // return true
  234. // } else {
  235. // return false
  236. // }
  237. for data in menuItemArr {
  238. if data.text == KMLocalizedString("Add Item") {
  239. data.isDisabled = false
  240. } else {
  241. data.isDisabled = true
  242. }
  243. }
  244. } else {
  245. let outlineItem : KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
  246. if outlineItem.outline.index > 0 {
  247. // if action == #selector(demoteItemAction) {
  248. // return true
  249. // }
  250. for data in menuItemArr {
  251. if data.text == KMLocalizedString("Demote") {
  252. data.isDisabled = false
  253. } else {
  254. // data.isDisabled = true
  255. }
  256. }
  257. } else {
  258. // if action == #selector(demoteItemAction) {
  259. // return false
  260. // }
  261. for data in menuItemArr {
  262. if data.text == KMLocalizedString("Demote") {
  263. data.isDisabled = true
  264. } else {
  265. // data.isDisabled = true
  266. }
  267. }
  268. }
  269. let parentOutline = outlineItem.outline.parent
  270. let grandparentOutline = parentOutline?.parent
  271. if grandparentOutline != nil {
  272. // if action == #selector(addHigherItemAction) {
  273. // return true
  274. // } else if action == #selector(promoteItemAction) {
  275. // return true
  276. // }
  277. for data in menuItemArr {
  278. if data.text == KMLocalizedString("Add A Higher Level") || data.text == KMLocalizedString("Promote") {
  279. data.isDisabled = false
  280. } else {
  281. // data.isDisabled = true
  282. }
  283. }
  284. } else {
  285. // if action == #selector(addHigherItemAction) {
  286. // return false
  287. // } else if action == #selector(promoteItemAction) {
  288. // return false
  289. // }
  290. for data in menuItemArr {
  291. if data.text == KMLocalizedString("Add A Higher Level") || data.text == KMLocalizedString("Promote") {
  292. data.isDisabled = true
  293. } else {
  294. // data.isDisabled = true
  295. }
  296. }
  297. }
  298. }
  299. if menuGroupView_ == nil {
  300. menuGroupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  301. }
  302. if menuGroupView_ != nil {
  303. menuGroupView_?.clickedAutoHide = false
  304. menuGroupView_?.groupDelegate = self
  305. menuGroupView_?.frame = CGRectMake(0, 0, 180, viewHeight)
  306. menuGroupView_?.updateGroupInfo(menuItemArr)
  307. menuGroupView_?.showWithPoint(CGPoint(x: point.x, y: point.y - viewHeight), relativeTo: tempView)
  308. }
  309. }
  310. func menuItemWithTitle(title:String, action:Selector?) -> NSMenuItem {
  311. let menuItem = NSMenuItem.init(title: title as String, action: action, keyEquivalent: "")
  312. menuItem.target = self
  313. return menuItem
  314. }
  315. func reloadData() {
  316. self.BOTAOutlineView.reloadData(expandItemType: .none)
  317. }
  318. func editOutlineUI(editVC : KMOutlineEditViewController!) {
  319. if editVC.pageButton.state == NSControl.StateValue.on {
  320. let index = Int(editVC.outlineTargetPageIndexTextField.stringValue)!
  321. if editVC.originalDestination?.pageIndex != index {
  322. let page = editVC.pdfView?.document.page(at: UInt(index))
  323. if page != nil {
  324. let destination = CPDFDestination.init(document: editVC.pdfView!.document, pageIndex: index)
  325. editVC.outline?.destination = destination
  326. } else {
  327. __NSBeep()
  328. }
  329. }
  330. } else if editVC.urlButton.state == NSControl.StateValue.on {
  331. if editVC.originalURLString != editVC.outlineURLTextField.stringValue {
  332. var urlString = editVC.outlineURLTextField.stringValue
  333. let tLowerUrl = urlString.lowercased()
  334. if !tLowerUrl.hasPrefix("https://") && !tLowerUrl.hasPrefix("pf]://") && !urlString.hasPrefix("https://") &&
  335. urlString.lengthOfBytes(using: String.Encoding(rawValue: String.Encoding.utf16.rawValue)) > 0 {
  336. urlString = "http://\(urlString)"
  337. }
  338. let action = CPDFURLAction.init(url: urlString)
  339. editVC.outline?.action = action
  340. }
  341. } else if editVC.mailButton.state == NSControl.StateValue.on {
  342. var mailString = editVC.mailAddressTextField.stringValue
  343. let tLowerStr = mailString.lowercased()
  344. if !tLowerStr.hasPrefix("mailto:") {
  345. mailString = "mailto:\(mailString)"
  346. }
  347. if mailString != editVC.originalURLString {
  348. var action = CPDFURLAction.init(url: mailString)
  349. if action?.url == nil {
  350. action = CPDFURLAction.init(url: "mailto:")
  351. }
  352. editVC.outline?.action = action
  353. }
  354. }
  355. }
  356. // MARK: - Private Methods
  357. private func _showAlert(style: NSAlert.Style, message: String, info: String, buttons: [String]) -> NSApplication.ModalResponse {
  358. let alert = NSAlert()
  359. alert.alertStyle = style
  360. alert.messageText = message
  361. alert.informativeText = info
  362. for button in buttons {
  363. alert.addButton(withTitle: button)
  364. }
  365. return alert.runModal()
  366. }
  367. private func _showHeaderSearch() {
  368. headerSearchView_?.isHidden = false
  369. }
  370. private func _hideHeaderSearch() {
  371. headerSearchView_?.isHidden = true
  372. }
  373. //MARK: - GroupView
  374. func showGroupView() {
  375. var viewHeight: CGFloat = 8
  376. var menuItemArr: [ComponentMenuitemProperty] = []
  377. for i in ["Expand All", "Collapse All", "Remove All Outlines"] {
  378. let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  379. itemSelected: false,
  380. isDisabled: false,
  381. keyEquivalent: nil,
  382. text: KMLocalizedString(i))
  383. menuItemArr.append(properties_Menuitem)
  384. viewHeight += 36
  385. }
  386. if let data = menuItemArr.first {
  387. var canExpand = false
  388. for row in 0..<self.BOTAOutlineView.outlineView.numberOfRows {
  389. // 检查当前项目是否可以展开
  390. let item = self.BOTAOutlineView.outlineView.item(atRow: row)
  391. if self.BOTAOutlineView.outlineView.isExpandable(item) {
  392. if !self.BOTAOutlineView.outlineView.isItemExpanded(item) {
  393. canExpand = true
  394. break
  395. }
  396. }
  397. }
  398. data.isDisabled = !canExpand
  399. }
  400. if let data = menuItemArr.safe_element(for: 1) as? ComponentMenuitemProperty {
  401. var canCollapse = false
  402. for row in 0..<self.BOTAOutlineView.outlineView.numberOfRows {
  403. let item = self.BOTAOutlineView.outlineView.item(atRow: row)
  404. if self.BOTAOutlineView.outlineView.isExpandable(item) {
  405. if self.BOTAOutlineView.outlineView.isItemExpanded(item) {
  406. canCollapse = true
  407. break
  408. }
  409. }
  410. }
  411. data.isDisabled = !canCollapse
  412. }
  413. if let data = menuItemArr.last {
  414. if self.BOTAOutlineView.outlineView.item(atRow: 0) != nil {
  415. data.isDisabled = false
  416. } else {
  417. data.isDisabled = true
  418. }
  419. }
  420. if groupView_ == nil {
  421. groupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  422. }
  423. groupView_?.groupDelegate = self
  424. groupView_?.frame = CGRectMake(310, 0, 200, viewHeight)
  425. groupView_?.updateGroupInfo(menuItemArr)
  426. var point = moreDropdown_.convert(moreDropdown_.frame.origin, to: nil)
  427. point.y -= viewHeight
  428. groupView_?.showWithPoint(point, relativeTo: moreDropdown_)
  429. moreDropdown_.properties.state = .pressed
  430. moreDropdown_.reloadData()
  431. }
  432. func removeGroupView() {
  433. if groupView_ != nil {
  434. groupView_?.removeFromSuperview()
  435. }
  436. moreDropdown_.properties.state = .normal
  437. moreDropdown_.reloadData()
  438. }
  439. func updateExtempViewState() {
  440. if(self.handdler.outlineRoot() == nil || self.handdler.outlineRoot()?.numberOfChildren == 0) { //无数据时的图
  441. self.emptyView.isHidden = false
  442. } else {
  443. self.emptyView.isHidden = true
  444. }
  445. }
  446. }
  447. //MARK: - Notification
  448. extension KMOutlineViewController {
  449. @objc func KMPDFViewCurrentPageDidChangedNotification(notification: NSNotification) {
  450. if notification.object is CPDFDocument {
  451. let pdfdocument : CPDFDocument = notification.object as! CPDFDocument
  452. if pdfdocument.isEqual(self.handdler.document) {
  453. if !isLocalEvent {
  454. self.updateOutlineSelection()
  455. }
  456. self.isLocalEvent = false
  457. }
  458. }
  459. }
  460. }
  461. //MARK: - Menu 右键菜单
  462. extension KMOutlineViewController {
  463. @objc func outlineViewDoubleAction() {
  464. if(self.BOTAOutlineView.outlineView.clickedRow >= 0) {
  465. self.renameItemAction()
  466. }
  467. }
  468. @objc func addItemAction() {
  469. guard let outlineView = BOTAOutlineView.outlineView else {
  470. return
  471. }
  472. let selectRowIndexs = outlineView.selectedRowIndexes
  473. let dataCount = BOTAOutlineView.data?.children.count ?? 0
  474. var index: Int = 0
  475. var parent: KMBOTAOutlineItem?
  476. var outlineItem: KMBOTAOutlineItem?
  477. if selectRowIndexs.count == 0 {
  478. var lastOulineItem: KMBOTAOutlineItem?
  479. if dataCount == 0 {
  480. let item = KMBOTAOutlineItem()
  481. item.outline = self.handdler.document!.setNewOutlineRoot()
  482. item.parent = nil
  483. parent = item
  484. lastOulineItem = item
  485. } else {
  486. outlineItem = outlineView.item(atRow: outlineView.numberOfRows - 1) as? KMBOTAOutlineItem
  487. lastOulineItem = outlineItem
  488. while lastOulineItem?.parent != nil {
  489. lastOulineItem = lastOulineItem?.parent
  490. }
  491. parent = lastOulineItem
  492. }
  493. index = Int(lastOulineItem?.outline.numberOfChildren ?? 0)
  494. } else {
  495. outlineItem = outlineView.item(atRow: selectRowIndexs.last ?? 0) as? KMBOTAOutlineItem
  496. parent = outlineItem?.parent ?? KMBOTAOutlineItem()
  497. index = Int((outlineItem?.outline.index) ?? 0 + 1)
  498. }
  499. self.addOutlineToIndex(index: index, parent: parent)
  500. }
  501. @objc func addChildItemAction() {
  502. let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
  503. let selectRowIndexs = outlineView.selectedRowIndexes
  504. if selectRowIndexs.count != 0 {
  505. let outlineItem: KMBOTAOutlineItem = outlineView.item(atRow: selectRowIndexs.last!) as! KMBOTAOutlineItem
  506. let index = outlineItem.outline.numberOfChildren
  507. self.addOutlineToIndex(index: NSInteger(index), parent: outlineItem)
  508. }
  509. }
  510. @objc func addHigherItemAction() {
  511. let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
  512. let selectRowIndexs = outlineView.selectedRowIndexes
  513. if selectRowIndexs.count != 0 {
  514. let outlineItem: KMBOTAOutlineItem = outlineView.item(atRow: selectRowIndexs.last!) as! KMBOTAOutlineItem
  515. var parent = outlineItem.parent
  516. let index = NSInteger(parent!.outline.index) + 1
  517. parent = parent?.parent
  518. if parent != nil {
  519. self.addOutlineToIndex(index: index, parent: parent!)
  520. }
  521. }
  522. }
  523. @objc func deleteItemAction() {
  524. let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
  525. let selectRowIndexs = outlineView.selectedRowIndexes
  526. if selectRowIndexs.count != 0 {
  527. var outlineItems: [KMBOTAOutlineItem] = []
  528. for index in selectRowIndexs {
  529. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: index) as! KMBOTAOutlineItem
  530. outlineItem.toIndex = index
  531. outlineItem.parent = outlineItem.parent ?? KMBOTAOutlineItem()
  532. outlineItems.append(outlineItem)
  533. }
  534. self.deleteOutline(outlineItems: outlineItems)
  535. }
  536. }
  537. @objc func editItemAction() {
  538. if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
  539. if self.BOTAOutlineView.outlineView.rowView(atRow: self.BOTAOutlineView.outlineView.clickedRow, makeIfNecessary: true) != nil {
  540. let cell = self.BOTAOutlineView.outlineView.rowView(atRow: self.BOTAOutlineView.outlineView.clickedRow, makeIfNecessary: true)
  541. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
  542. let vc = KMOutlineEditViewController.init(outline: outlineItem.outline, document: self.handdler.pdfView)
  543. vc.pageCount = handdler.pageCount()
  544. let popover = NSPopover()
  545. popover.delegate = self
  546. popover.contentViewController = vc
  547. popover.animates = true
  548. popover.behavior = .applicationDefined
  549. popover.show(relativeTo: cell!.bounds, of: cell!, preferredEdge: .minX)
  550. }
  551. } else {
  552. __NSBeep()
  553. }
  554. }
  555. @objc func renameItemAction() {
  556. if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
  557. self.renameOutlineWithRow(row: self.BOTAOutlineView.outlineView.clickedRow)
  558. } else {
  559. __NSBeep()
  560. }
  561. }
  562. @objc func changeItemAction() {
  563. if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
  564. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
  565. let resp = _showAlert(style: .informational, message: NSLocalizedString("Are you sure you want to set the destination as the current location?", comment: ""), info: "", buttons: [NSLocalizedString("Yes", comment:""), NSLocalizedString("No", comment:"")])
  566. if resp == .alertFirstButtonReturn {
  567. // self.changeLocation(outlineItem: outlineItem, destination: self.fetchCurrentDestination())
  568. }
  569. } else {
  570. __NSBeep()
  571. }
  572. }
  573. @objc func promoteItemAction() {
  574. if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
  575. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
  576. var parent = outlineItem.parent
  577. let index = NSInteger(parent!.outline.index) + 1
  578. parent = parent?.parent
  579. if parent != nil {
  580. self.moveOutline(outlineItem: outlineItem, index: index, parent: parent)
  581. }
  582. }
  583. }
  584. @objc func demoteItemAction() {
  585. if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
  586. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
  587. let parent = outlineItem.parent
  588. let newParent = parent?.children[Int(outlineItem.outline.index) - 1]
  589. let index = newParent?.children.count
  590. if (index != nil) {
  591. self.moveOutline(outlineItem: outlineItem, index: NSInteger(index ?? 0), parent: newParent)
  592. }
  593. }
  594. }
  595. @objc private func expandAllComments(item: NSMenuItem) {
  596. self.BOTAOutlineView.expandAllComments(item: item)
  597. }
  598. @objc private func collapseAllComments(item: NSMenuItem) {
  599. self.BOTAOutlineView.collapseAllComments(item: item)
  600. }
  601. @objc private func removeAllOutlineItem(item: NSMenuItem) {
  602. let alter = NSAlert()
  603. alter.alertStyle = NSAlert.Style.informational
  604. alter.messageText = NSLocalizedString("This will permanently remove all outlines. Are you sure to continue?", comment: "")
  605. alter.addButton(withTitle: NSLocalizedString("Yes", comment:""))
  606. alter.addButton(withTitle: NSLocalizedString("No", comment:""))
  607. let modlres = alter.runModal()
  608. if modlres == NSApplication.ModalResponse.alertFirstButtonReturn {
  609. self.removeAllOutline()
  610. }
  611. }
  612. @objc private func removeAllOutline() {
  613. guard let data = self.BOTAOutlineView.data else { return }
  614. for item in data.children {
  615. item.toIndex = Int(item.outline.index)
  616. }
  617. self.deleteOutline(outlineItems: data.children)
  618. self.BOTAOutlineView.reloadData(expandItemType: .none)
  619. }
  620. @objc private func _searchAction() {
  621. _showHeaderSearch()
  622. }
  623. }
  624. //MARK: - Action
  625. extension KMOutlineViewController {
  626. @IBAction func addNewOutline(_ sender: Any) {
  627. self.addItemAction()
  628. }
  629. @IBAction func moreButton_click(_ sender: NSButton) {
  630. let rect = sender.convert(sender.bounds, to: self.view)
  631. moreMenu.popUp(positioning: nil, at: NSPoint(x: rect.origin.x, y: rect.origin.y-10), in: self.view)
  632. }
  633. @IBAction func escButtonAction(_ sender: Any) {
  634. self.cancelSelect()
  635. }
  636. func cancelSelect() {
  637. self.BOTAOutlineView.cancelSelect()
  638. }
  639. func renameOutlineWithRow(row: NSInteger) {
  640. DispatchQueue.main.async {
  641. self.renamePDFOutline = self.BOTAOutlineView.outlineView.item(atRow: row) as? KMBOTAOutlineItem
  642. let cell : KMBOTAOutlineCellView = self.BOTAOutlineView.outlineView.view(atColumn: 0, row: row, makeIfNecessary: true) as! KMBOTAOutlineCellView
  643. self.renameTextField = cell.titleLabel
  644. self.renameTextField.delegate = self
  645. self.renameTextField.isEditable = true
  646. self.renameTextField.becomeFirstResponder()
  647. }
  648. }
  649. func addOutlineToIndex(index: Int, parent: KMBOTAOutlineItem?) {
  650. let pageIndex = self.handdler.currentPageIndex
  651. let label = self.fetchCurrentLabel(pageIndex: pageIndex)
  652. let destination = self.handdler.currentDestination()
  653. self.addOutlineToIndex(index: index, pageIndex: pageIndex, destination: destination, lable: label, parent: parent)
  654. }
  655. func addOutlineToIndex(index: Int, pageIndex: Int, destination: CPDFDestination?, lable: String, parent: KMBOTAOutlineItem?) {
  656. let outlineItem = KMBOTAOutlineItem()
  657. outlineItem.destination = destination
  658. outlineItem.label = lable
  659. outlineItem.parent = parent
  660. outlineItem.toIndex = index
  661. self.addOutline(outlineItems: [outlineItem])
  662. let tempOutlineView = self.BOTAOutlineView!
  663. var index = -1
  664. if tempOutlineView.outlineView.numberOfRows == 1 || tempOutlineView.data == nil {
  665. index = 0
  666. } else {
  667. index = tempOutlineView.outlineView.row(forItem: outlineItem)
  668. }
  669. tempOutlineView.selectIndex(index: index)
  670. //滑动到指定位置
  671. if(tempOutlineView.outlineView.selectedRow >= 0) {
  672. self.renameOutlineWithRow(row: tempOutlineView.outlineView.selectedRow)
  673. }
  674. let row = tempOutlineView.outlineView.row(forItem: outlineItem)
  675. if Thread.current.isMainThread {
  676. tempOutlineView.outlineView.scrollToVisible(tempOutlineView.outlineView.rect(ofRow: row))
  677. } else {
  678. DispatchQueue.main.async {
  679. tempOutlineView.outlineView.scrollToVisible(tempOutlineView.outlineView.rect(ofRow: row))
  680. }
  681. }
  682. }
  683. func updateOutlineSelection() {
  684. KMPrint("updateOutlineSelection")
  685. let currentPageIndex = self.handdler.currentPageIndex
  686. let numRows = self.BOTAOutlineView.outlineView.numberOfRows
  687. if numRows > 0 {
  688. for i in 0...numRows - 1 {
  689. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: i) as! KMBOTAOutlineItem
  690. if (outlineItem.outline.destination == nil) {
  691. continue
  692. }
  693. if outlineItem.outline.destination.pageIndex == currentPageIndex {
  694. self.BOTAOutlineView.selectIndex(index: currentPageIndex)
  695. break
  696. }
  697. }
  698. }
  699. }
  700. // func fetchCurrentDestination() -> CPDFDestination {
  701. // //destination
  702. // var destination: CPDFDestination
  703. // let pageIndex: Int
  704. // if self.listView.currentSelection != nil {
  705. // let des :CPDFDestination = CPDFDestination.init(document: self.listView.document, pageIndex: Int(self.listView.currentSelection.page.pageIndex()), at: CGPoint(x: self.listView.currentSelection.bounds.origin.x, y: self.listView.currentSelection.bounds.origin.y + self.listView.currentSelection.bounds.size.height), zoom: self.listView.scaleFactor)
  706. // destination = des
  707. // pageIndex = Int(self.listView.currentSelection.page.pageIndex())
  708. // } else {
  709. // let des :CPDFDestination = CPDFDestination.init(document: self.listView.document, pageIndex: Int(self.listView.currentPageIndex), at: CGPoint(x: 0, y: self.listView.currentPage().size.height), zoom: self.listView.scaleFactor)
  710. // destination = des
  711. // pageIndex = Int(self.listView.currentPageIndex)
  712. // }
  713. //
  714. // if "\(destination.point.x )" == "nan" {
  715. // destination = CPDFDestination(document: self.listView.document, pageIndex: pageIndex, at: CGPoint(x: 0, y: 0), zoom: self.listView.scaleFactor)
  716. // }
  717. // return destination
  718. // }
  719. func fetchCurrentLabel(pageIndex: Int) -> String {
  720. var label = "\(NSLocalizedString("Page", comment: ""))\(pageIndex + 1)"
  721. let currentSelection = self.handdler.currentSelection()
  722. if currentSelection != nil && currentSelection?.selectionsByLine != nil {
  723. for data in currentSelection?.selectionsByLine ?? [] {
  724. label = data.string() ?? ""
  725. }
  726. }
  727. return label
  728. }
  729. }
  730. //MARK: - KMBOTAOutlineViewDelegate
  731. extension KMOutlineViewController: KMBOTAOutlineViewDelegate {
  732. func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, rightDidMoseDown: KMBOTAOutlineItem, event: NSEvent) {
  733. let row = outlineView.outlineView.row(forItem: rightDidMoseDown)
  734. if outlineView.outlineView.rowView(atRow: row, makeIfNecessary: false) != nil {
  735. let rowView = outlineView.outlineView.rowView(atRow: row, makeIfNecessary: false)
  736. self.addRightMenu(view: rowView!, event: event)
  737. }
  738. }
  739. func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, didReloadData: KMBOTAOutlineItem) {
  740. self.updateExtempViewState()
  741. }
  742. func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, didSelectItem: [KMBOTAOutlineItem]) {
  743. if self.BOTAOutlineView.outlineView.selectedRowIndexes.count == 1 {
  744. self.isLocalEvent = true
  745. let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow:self.BOTAOutlineView.outlineView.selectedRow) as! KMBOTAOutlineItem
  746. if outlineItem.outline.destination != nil {
  747. if outlineItem.outline.destination.page() != nil {
  748. // self.listView.go(toTargetPoint: outlineItem.outline.destination.point, on: outlineItem.outline.destination.page() , at: .top)
  749. } else {
  750. let alter = NSAlert()
  751. alter.alertStyle = NSAlert.Style.informational
  752. alter.messageText = NSLocalizedString("The target page is invalid, please relocate it.", comment: "")
  753. alter.addButton(withTitle: NSLocalizedString("OK", comment:""))
  754. alter.beginSheetModal(for: self.view.window ?? NSWindow())
  755. }
  756. } else if outlineItem.outline.action != nil {
  757. let alter = NSAlert()
  758. alter.alertStyle = NSAlert.Style.informational
  759. alter.messageText = NSLocalizedString("The target page is invalid, please relocate it.", comment: "")
  760. alter.addButton(withTitle: NSLocalizedString("OK", comment:""))
  761. alter.beginSheetModal(for: self.view.window ?? NSWindow())
  762. // self.listView.perform(outlineItem.outline.action)
  763. }
  764. }
  765. }
  766. func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, writeItems items: [Any], to pasteboard: NSPasteboard) -> Bool {
  767. if outlineView.outlineView.selectedRowIndexes.count > 1 || outlineView.outlineView.selectedRow == -1 {
  768. return false
  769. }
  770. self.dragPDFOutline = items.first as? KMBOTAOutlineItem
  771. let indexSet = [outlineView.outlineView.clickedRow]
  772. let indexSetData: Data = try!NSKeyedArchiver.archivedData(withRootObject: indexSet, requiringSecureCoding: true)
  773. pasteboard.declareTypes([NSPasteboard.PasteboardType(rawValue: "kKMPDFViewOutlineDragDataType")], owner: self)
  774. pasteboard.setData(indexSetData, forType: NSPasteboard.PasteboardType(rawValue: NSPasteboard.PasteboardType.RawValue("kKMPDFViewOutlineDragDataType")))
  775. return true
  776. }
  777. func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
  778. var dragOperation = NSDragOperation.init(rawValue: 0)
  779. if index >= 0 {
  780. dragOperation = NSDragOperation.move
  781. }
  782. return dragOperation
  783. }
  784. func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
  785. guard let dragOutlineItem = self.dragPDFOutline else { return false }
  786. let outlineItem: KMBOTAOutlineItem = (item ?? KMBOTAOutlineItem()) as! KMBOTAOutlineItem
  787. if index < 0 {
  788. return false
  789. }
  790. if outlineItem.parent == nil {
  791. var root = dragOutlineItem.parent
  792. while root?.parent?.children != nil {
  793. root = root?.parent!
  794. }
  795. if dragOutlineItem.parent!.isEqual(root) {
  796. if dragOutlineItem.outline.index > index {
  797. self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: root)
  798. } else {
  799. self.moveOutline(outlineItem: dragOutlineItem, index: index - 1, parent: root)
  800. }
  801. } else {
  802. self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: root)
  803. }
  804. } else {
  805. if dragOutlineItem.parent!.isEqual(item) {
  806. // if dragOutlineItem.outline.index != 0 {
  807. if dragOutlineItem.outline.index > index {
  808. self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: item as? KMBOTAOutlineItem)
  809. } else {
  810. self.moveOutline(outlineItem: dragOutlineItem, index: index - 1, parent: item as? KMBOTAOutlineItem)
  811. }
  812. // } else {
  813. // return false
  814. // }
  815. } else {
  816. var tOutline = outlineItem
  817. var isContains = false
  818. while (tOutline.parent != nil) {
  819. if tOutline.outline.isEqual(dragOutlineItem.outline) {
  820. isContains = true
  821. break
  822. }
  823. tOutline = tOutline.parent!
  824. }
  825. if isContains == false {
  826. self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: item as? KMBOTAOutlineItem)
  827. }
  828. }
  829. }
  830. self.BOTAOutlineView.selectItem(outlineItem: dragOutlineItem)
  831. return true
  832. }
  833. }
  834. //MARK: - NSTextFieldDelegate
  835. extension KMOutlineViewController: NSTextFieldDelegate {
  836. func controlTextDidEndEditing(_ obj: Notification) {
  837. if (self.renameTextField.isEqual(obj.object)) {
  838. let textField : NSTextField = obj.object as! NSTextField
  839. self.renamePDFOutline(outlineItem: self.renamePDFOutline, label: textField.stringValue)
  840. }
  841. }
  842. }
  843. //MARK: - NSPopoverDelegate
  844. extension KMOutlineViewController: NSPopoverDelegate {
  845. func popoverWillClose(_ notification: Notification) {
  846. let popover : NSPopover = notification.object as! NSPopover
  847. if popover.contentViewController!.isKind(of: KMOutlineEditViewController.self) {
  848. }
  849. }
  850. }
  851. //MARK: - NSMenuItemValidation
  852. extension KMOutlineViewController: NSMenuDelegate, NSMenuItemValidation {
  853. func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
  854. let action = menuItem.action
  855. if action == #selector(addItemAction) ||
  856. action == #selector(addChildItemAction) ||
  857. action == #selector(addHigherItemAction) ||
  858. action == #selector(deleteItemAction) ||
  859. action == #selector(editItemAction) ||
  860. action == #selector(changeItemAction) ||
  861. action == #selector(renameItemAction) ||
  862. action == #selector(promoteItemAction) ||
  863. action == #selector(demoteItemAction) {
  864. if self.BOTAOutlineView.outlineView.selectedRowIndexes.count > 1 {
  865. if action == #selector(deleteItemAction) {
  866. return true
  867. }
  868. return false
  869. } else if self.BOTAOutlineView.outlineView.selectedRowIndexes.count > 0 {
  870. if action == #selector(addChildItemAction) || action == #selector(changeItemAction) {
  871. return true
  872. }
  873. }
  874. if self.BOTAOutlineView.outlineView.clickedRow == -1 {
  875. if action == #selector(addItemAction) {
  876. return true
  877. } else {
  878. return false
  879. }
  880. } else {
  881. let outlineItem : KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
  882. if outlineItem.outline.index > 0 {
  883. if action == #selector(demoteItemAction) {
  884. return true
  885. }
  886. } else {
  887. if action == #selector(demoteItemAction) {
  888. return false
  889. }
  890. }
  891. let parentOutline = outlineItem.outline.parent
  892. let grandparentOutline = parentOutline?.parent
  893. if grandparentOutline != nil {
  894. if action == #selector(addHigherItemAction) {
  895. return true
  896. } else if action == #selector(promoteItemAction) {
  897. return true
  898. }
  899. } else {
  900. if action == #selector(addHigherItemAction) {
  901. return false
  902. } else if action == #selector(promoteItemAction) {
  903. return false
  904. }
  905. }
  906. }
  907. return true
  908. }
  909. if (action == #selector(undo)) {
  910. return handdler.canUndo()
  911. }
  912. if (action == #selector(redo)) {
  913. return handdler.canRedo()
  914. }
  915. if (action == #selector(expandAllComments)) {
  916. var canExpand = false
  917. for row in 0..<self.BOTAOutlineView.outlineView.numberOfRows {
  918. // 检查当前项目是否可以展开
  919. let item = self.BOTAOutlineView.outlineView.item(atRow: row)
  920. if self.BOTAOutlineView.outlineView.isExpandable(item) {
  921. if !self.BOTAOutlineView.outlineView.isItemExpanded(item) {
  922. canExpand = true
  923. break
  924. }
  925. }
  926. }
  927. return canExpand
  928. }
  929. if (action == #selector(collapseAllComments)) {
  930. var canCollapse = false
  931. for row in 0..<self.BOTAOutlineView.outlineView.numberOfRows {
  932. let item = self.BOTAOutlineView.outlineView.item(atRow: row)
  933. if self.BOTAOutlineView.outlineView.isExpandable(item) {
  934. if self.BOTAOutlineView.outlineView.isItemExpanded(item) {
  935. canCollapse = true
  936. break
  937. }
  938. }
  939. }
  940. return canCollapse
  941. }
  942. if (action == #selector(removeAllOutlineItem)) {
  943. if self.BOTAOutlineView.outlineView.item(atRow: 0) != nil {
  944. return true
  945. } else {
  946. return false
  947. }
  948. }
  949. return true
  950. }
  951. }
  952. // MARK: - KMNOutlineHanddlerDelegate
  953. extension KMOutlineViewController: KMNOutlineHanddlerDelegate {
  954. func handdler(_ handdler: KMNOutlineHanddler, didAdd info: [String : Any]?) {
  955. let tempOutlineItems = info?["data"] as? [KMBOTAOutlineItem] ?? []
  956. let tempOutlineView = self.BOTAOutlineView
  957. if tempOutlineView?.data?.children.count == 0 || tempOutlineView?.data == nil {
  958. tempOutlineView?.inputData = self.handdler.outlineRoot()
  959. } else {
  960. tempOutlineView?.outlineView.reloadData()
  961. }
  962. //展开
  963. // DispatchQueue.main.async {
  964. for outlineItem in tempOutlineItems {
  965. var tempParent = outlineItem
  966. while tempParent.parent != nil {
  967. tempParent.isItemExpanded = true
  968. tempParent = tempParent.parent!
  969. tempOutlineView?.outlineView.expandItem(tempParent)
  970. }
  971. tempOutlineView?.outlineView.expandItem(tempParent.parent)
  972. }
  973. // }
  974. self.updateExtempViewState()
  975. }
  976. func handdler(_ handdler: KMNOutlineHanddler, didRemove info: [String : Any]?) {
  977. let tempOutlineItems = info?["data"] as? [KMBOTAOutlineItem] ?? []
  978. let tempOutlineView = self.BOTAOutlineView
  979. //展开
  980. for outlineItem in tempOutlineItems {
  981. outlineItem.parent?.isItemExpanded = true
  982. tempOutlineView?.outlineView.expandItem(outlineItem.parent)
  983. }
  984. tempOutlineView?.outlineView.reloadData()
  985. //删除需要取消选中
  986. tempOutlineView?.cancelSelect()
  987. //刷新nil数据
  988. self.updateExtempViewState()
  989. }
  990. func handdler(_ handdler: KMNOutlineHanddler, didRename outline: CPDFOutline?, info: [String : Any]?) {
  991. let outlineItem = info?["data"] as? KMBOTAOutlineItem
  992. let tempOutlineView = self.BOTAOutlineView
  993. tempOutlineView?.outlineView.reloadItem(outlineItem)
  994. }
  995. func handdler(_ handdler: KMNOutlineHanddler, didChangeLocation outline: CPDFOutline?, info: [String : Any]?) {
  996. let outlineItem = info?["data"] as? KMBOTAOutlineItem
  997. let tempOutlineView = self.BOTAOutlineView
  998. tempOutlineView?.outlineView.reloadItem(outlineItem)
  999. }
  1000. func handdler(_ handdler: KMNOutlineHanddler, didMove outline: CPDFOutline?, info: [String : Any]?) {
  1001. guard let outlineItem = info?["data"] as? KMBOTAOutlineItem else {
  1002. return
  1003. }
  1004. let parent = info?["parent"] as? KMBOTAOutlineItem
  1005. let tempOutlineView = self.BOTAOutlineView
  1006. let index = info?["index"] as? Int ?? 0
  1007. //显示数据刷新
  1008. outlineItem.parent?.children.removeObject(outlineItem)
  1009. parent?.children.insert(outlineItem, at: index)
  1010. outlineItem.parent = parent
  1011. tempOutlineView?.outlineView.reloadData()
  1012. tempOutlineView?.cancelSelect()
  1013. //展开
  1014. outlineItem.isItemExpanded = true
  1015. outlineItem.parent?.isItemExpanded = true
  1016. tempOutlineView?.outlineView.expandItem(outlineItem)
  1017. tempOutlineView?.outlineView.expandItem(outlineItem.parent)
  1018. }
  1019. }
  1020. //MARK: - 快捷键
  1021. extension KMOutlineViewController {
  1022. @IBAction func delete(_ sender: Any) {
  1023. self.deleteItemAction()
  1024. }
  1025. }
  1026. //MARK: - undoRedo
  1027. extension KMOutlineViewController {
  1028. func moveOutline(outlineItem: KMBOTAOutlineItem, index: NSInteger, parent: KMBOTAOutlineItem!) {
  1029. // let tempOutlineView = self.BOTAOutlineView!
  1030. // let indexTemp = outlineItem.outline.index
  1031. // let parentTemp = outlineItem.parent
  1032. //元数据移除
  1033. // outlineItem.outline.removeFromParent()
  1034. // parent.outline.insertChild(outlineItem.outline, at: UInt(index))
  1035. handdler.moveOutline(outlineItem: outlineItem, index: index, parent: parent)
  1036. //
  1037. // //显示数据刷新
  1038. // outlineItem.parent?.children.removeObject(outlineItem)
  1039. // parent?.children.insert(outlineItem, at: index)
  1040. // outlineItem.parent = parent
  1041. // tempOutlineView.outlineView.reloadData()
  1042. // tempOutlineView.cancelSelect()
  1043. //
  1044. // //展开
  1045. // outlineItem.isItemExpanded = true
  1046. // outlineItem.parent?.isItemExpanded = true
  1047. // tempOutlineView.outlineView.expandItem(outlineItem)
  1048. // tempOutlineView.outlineView.expandItem(outlineItem.parent)
  1049. // self.listView.undoManager?.registerUndo(withTarget: self) { [weak self] targetType in
  1050. // self?.moveOutline(outlineItem: outlineItem, index: NSInteger(indexTemp), parent: parentTemp)
  1051. // }
  1052. }
  1053. func changeLocation(outlineItem: KMBOTAOutlineItem, destination: CPDFDestination) {
  1054. // let tempOutlineView = self.BOTAOutlineView!
  1055. // let temp = outlineItem.outline.destination
  1056. // outlineItem.outline.destination = CPDFDestination(document: destination.document, pageIndex: destination.pageIndex, at: destination.point, zoom: destination.zoom)
  1057. handdler.changeLocation(outlineItem: outlineItem, destination: destination)
  1058. // tempOutlineView.outlineView.reloadItem(outlineItem)
  1059. // self.listView.undoManager?.registerUndo(withTarget: self) { [weak self] targetType in
  1060. // self?.changeLocation(outlineItem: outlineItem, destination: temp!)
  1061. // }
  1062. }
  1063. func renamePDFOutline(outlineItem: KMBOTAOutlineItem!, label: String) {
  1064. let tempOutlineView = self.BOTAOutlineView!
  1065. self.view.window?.makeFirstResponder(tempOutlineView.outlineView)
  1066. self.renameTextField.isEditable = false
  1067. if outlineItem.outline.label == label {
  1068. return
  1069. }
  1070. // let temp: String = outlineItem.outline.label
  1071. // outlineItem.outline.label = label
  1072. handdler.renamePDFOutline(outlineItem: outlineItem, label: label)
  1073. // tempOutlineView.outlineView.reloadItem(outlineItem)
  1074. // self.listView.undoManager?.registerUndo(withTarget: self) { [weak self] targetType in
  1075. // self?.renamePDFOutline(outlineItem: outlineItem, label: temp)
  1076. // }
  1077. }
  1078. func deleteOutline(outlineItems: [KMBOTAOutlineItem]) {
  1079. NSApp.mainWindow?.makeFirstResponder(self.BOTAOutlineView)
  1080. let tempOutlineView = self.BOTAOutlineView!
  1081. // var tempOutlineItems: [KMBOTAOutlineItem] = outlineItems
  1082. // tempOutlineItems.sort(){$0.toIndex > $1.toIndex}
  1083. //
  1084. // for outlineItem in tempOutlineItems {
  1085. // outlineItem.outline.removeFromParent()
  1086. // let index = outlineItem.parent?.children.firstIndex(of: outlineItem)
  1087. // outlineItem.toIndex = index!
  1088. // outlineItem.parent?.children.removeObject(outlineItem)
  1089. // }
  1090. handdler.deleteOutline(outlineItems: outlineItems)
  1091. // //展开
  1092. // for outlineItem in tempOutlineItems {
  1093. // outlineItem.parent?.isItemExpanded = true
  1094. // tempOutlineView.outlineView.expandItem(outlineItem.parent)
  1095. // }
  1096. //
  1097. // tempOutlineView.outlineView.reloadData()
  1098. // //删除需要取消选中
  1099. // tempOutlineView.cancelSelect()
  1100. //
  1101. // //刷新nil数据
  1102. // self.updateExtempViewState()
  1103. // self.listView.undoManager?.registerUndo(withTarget: self) { [weak self] targetType in
  1104. // self?.addOutline(outlineItems: tempOutlineItems)
  1105. // }
  1106. }
  1107. func addOutline(outlineItems: [KMBOTAOutlineItem]) {
  1108. NSApp.mainWindow?.makeFirstResponder(self.BOTAOutlineView)
  1109. let tempOutlineView = self.BOTAOutlineView!
  1110. //先取消选中
  1111. tempOutlineView.cancelSelect()
  1112. var tempOutlineItems: [KMBOTAOutlineItem] = outlineItems
  1113. tempOutlineItems.sort(){$0.toIndex < $1.toIndex}
  1114. handdler.addOutline(outlineItems: tempOutlineItems)
  1115. // for outlineItem in tempOutlineItems {
  1116. // if outlineItem.outline.label != nil {
  1117. // outlineItem.parent?.outline.insertChild(outlineItem.outline, at: UInt(outlineItem.toIndex))
  1118. // } else {
  1119. // let outline = outlineItem.parent?.outline.insertChild(at: UInt(outlineItem.toIndex))
  1120. // outline?.label = outlineItem.label
  1121. // outline?.destination = outlineItem.destination
  1122. // outlineItem.outline = outline!
  1123. // }
  1124. // outlineItem.parent?.children.insert(outlineItem, at: outlineItem.toIndex)
  1125. // }
  1126. // if tempOutlineView.data?.children.count == 0 || tempOutlineView.data == nil {
  1127. // tempOutlineView.inputData = self.handdler.outlineRoot()
  1128. // } else {
  1129. // tempOutlineView.outlineView.reloadData()
  1130. // }
  1131. //
  1132. // //展开
  1133. //// DispatchQueue.main.async {
  1134. // for outlineItem in tempOutlineItems {
  1135. // var tempParent = outlineItem
  1136. // while tempParent.parent != nil {
  1137. // tempParent.isItemExpanded = true
  1138. // tempParent = tempParent.parent!
  1139. // tempOutlineView.outlineView.expandItem(tempParent)
  1140. // }
  1141. // tempOutlineView.outlineView.expandItem(tempParent.parent)
  1142. // }
  1143. //// }
  1144. //
  1145. // self.updateExtempViewState()
  1146. // self.listView.undoManager?.registerUndo(withTarget: self) { [weak self] targetType in
  1147. // self?.deleteOutline(outlineItems: tempOutlineItems)
  1148. // }
  1149. }
  1150. @IBAction func undo(_ sender: Any) {
  1151. handdler.undo()
  1152. }
  1153. @IBAction func redo(_ sender: Any) {
  1154. handdler.redo()
  1155. }
  1156. }
  1157. //MARK: - ComponentDropdownDelegate
  1158. extension KMOutlineViewController: ComponentDropdownDelegate {
  1159. func componentDropdownDidShowMenuItem(dropdown: ComponentDropdown) {
  1160. showGroupView()
  1161. }
  1162. }
  1163. //MARK: - ComponentGroupDelegate
  1164. extension KMOutlineViewController: ComponentGroupDelegate {
  1165. func componentGroupDidDismiss(group: ComponentGroup?) {
  1166. if group == groupView_ {
  1167. removeGroupView()
  1168. } else if group == menuGroupView_ {
  1169. group?.removeFromSuperview()
  1170. menuGroupView_ = nil
  1171. }
  1172. }
  1173. func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) {
  1174. if group == groupView_ {
  1175. if let selItem = menuItemProperty {
  1176. let index = group?.menuItemArr.firstIndex(of: selItem)
  1177. if index == 0 {
  1178. expandAllComments(item: NSMenuItem())
  1179. } else if index == 1 {
  1180. collapseAllComments(item: NSMenuItem())
  1181. } else if index == 2 {
  1182. removeAllOutlineItem(item: NSMenuItem())
  1183. }
  1184. }
  1185. } else if group == menuGroupView_ {
  1186. if let selItem = menuItemProperty {
  1187. let index = group?.menuItemArr.firstIndex(of: selItem)
  1188. if index == 0 {
  1189. addItemAction()
  1190. } else if index == 1 {
  1191. addChildItemAction()
  1192. } else if index == 2 {
  1193. addHigherItemAction()
  1194. } else if index == 4 {
  1195. deleteItemAction()
  1196. } else if index == 6 {
  1197. group?.removeFromSuperview()
  1198. editItemAction()
  1199. } else if index == 7 {
  1200. renameItemAction()
  1201. } else if index == 8 {
  1202. changeItemAction()
  1203. } else if index == 10 {
  1204. promoteItemAction()
  1205. } else if index == 11 {
  1206. demoteItemAction()
  1207. }
  1208. group?.removeFromSuperview()
  1209. }
  1210. }
  1211. }
  1212. }