123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- //
- // KMOutlineViewController.swift
- // PDF Reader Pro
- //
- // Created by lxy on 2022/10/10.
- //
- import Cocoa
- class KMOutlineViewController: NSViewController {
-
- @IBOutlet var contendView: NSView!
- @IBOutlet weak var topView: NSView!
- @IBOutlet weak var titleLabel: NSTextField!
-
- @IBOutlet weak var lineView: NSView!
-
- @IBOutlet weak var addButton: NSButton!
- @IBOutlet weak var moreButton: NSButton!
- @IBOutlet var topSepline: NSView!
-
- @IBOutlet weak var emptyView: NSView!
- @IBOutlet weak var bigTipLabel: NSTextField!
- @IBOutlet weak var tipLabel: NSTextField!
-
- @IBOutlet weak var BOTAOutlineView: KMBOTAOutlineView!
-
- var dragPDFOutline : KMBOTAOutlineItem!
- var renameTextField : NSTextField!
- var listView : CPDFListView!
- var renamePDFOutline : KMBOTAOutlineItem!
- let moreMenu = NSMenu()
- var isLocalEvent = false
-
- func dealloc() {
-
- NotificationCenter.default.removeObserver(self)
- }
-
- deinit {
- NotificationCenter.default.removeObserver(self)
- self.BOTAOutlineView.delegate = nil
- }
-
- override func viewWillDisappear() {
- super.viewWillDisappear()
- self.cancelSelect()
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- self.emptyView.wantsLayer = true
- // self.emptyView.layer?.backgroundColor = NSColor.red.cgColor
-
- self.addOutlineMenu()
- self.titleLabel.stringValue = NSLocalizedString("Outline", comment: "")
- self.topView.wantsLayer = true
- self.BOTAOutlineView.delegate = self
- self.BOTAOutlineView.inputData = self.listView.document.outlineRoot()
- self.BOTAOutlineView.outlineView.doubleAction = #selector(outlineViewDoubleAction)
-
- self.refreshUI()
-
- self.initNotification()
- }
-
- func refreshUI() {
- self.contendView.wantsLayer = true
- self.contendView.layer?.backgroundColor = NSColor.km_init(hex: "#F7F8FA").cgColor
-
- self.topSepline.wantsLayer = true
- self.topSepline.layer?.backgroundColor = NSColor(red: 0, green: 0, blue: 0, alpha: 0.1).cgColor
-
- self.titleLabel.textColor = NSColor.km_init(hex: "#252629")
- self.titleLabel.font = NSFont.SFProTextSemiboldFont(14.0)
-
- self.bigTipLabel.font = NSFont.SFProTextRegularFont(14.0)
- self.bigTipLabel.textColor = NSColor.km_init(hex: "#616469")
- self.bigTipLabel.stringValue = NSLocalizedString("No Outlines", comment: "")
-
- self.lineView.backgroundColor(NSColor.km_init(hex: "#EDEEF0"))
-
-
- let title = NSLocalizedString("To create an outline, please right-click on the selected page and choose \"Add Outline\", or click \"Add\" in the upper right corner.", comment: "")
- let paragraphStyle = NSMutableParagraphStyle()
- paragraphStyle.lineHeightMultiple = 1.32
- paragraphStyle.alignment = .center
- self.tipLabel.attributedStringValue = NSMutableAttributedString(string: title, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle, .foregroundColor : NSColor.km_init(hex: "#94989C")])
-
-
- self.addButton.toolTip = NSLocalizedString("Add Outline", comment: "")
- self.moreButton.toolTip = NSLocalizedString("More", comment: "")
-
- }
-
- private func addOutlineMenu(){
- moreMenu.addItem(withTitle: NSLocalizedString("Expand All", comment: ""), action: #selector(expandAllComments), target: self, tag: 0)
- moreMenu.addItem(withTitle: NSLocalizedString("Collapse All", comment: ""), action: #selector(collapseAllComments), target: self, tag: 1)
- moreMenu.addItem(withTitle: NSLocalizedString("Remove All Outlines", comment: ""), action: #selector(removeAllOutlineItem), target: self, tag: 2)
- }
-
- func addRightMenu(view: NSView, event: NSEvent) {
- let menus : NSMenu = NSMenu(title: "")
- let addItem = self.menuItemWithTitle(title: NSLocalizedString("Add Item", comment: ""), action: #selector(addItemAction))
- let addChildItem = self.menuItemWithTitle(title: NSLocalizedString("Add Sub-Item", comment: ""), action: #selector(addChildItemAction))
- let addHigherItem = self.menuItemWithTitle(title: NSLocalizedString("Add A Higher Level", comment: ""), action: #selector(addHigherItemAction))
- let deleteItem = self.menuItemWithTitle(title: NSLocalizedString("Delete", comment: ""), action: #selector(deleteItemAction))
- // let editItem = self.menuItemWithTitle(title: NSLocalizedString("Edit", comment: ""), action: #selector(editItemAction))
- let renameItem = self.menuItemWithTitle(title: NSLocalizedString("Rename", comment: ""), action: #selector(renameItemAction))
- let changeItem = self.menuItemWithTitle(title: NSLocalizedString("Change Destination", comment: ""), action: #selector(changeItemAction))
- let promoteItem = self.menuItemWithTitle(title: NSLocalizedString("Promote", comment: ""), action: #selector(promoteItemAction))
- let demoteItem = self.menuItemWithTitle(title: NSLocalizedString("Demote", comment: ""), action: #selector(demoteItemAction))
- menus.addItem(addItem)
- menus.addItem(addChildItem)
- menus.addItem(addHigherItem)
- menus.addItem(NSMenuItem.separator())
- menus.addItem(deleteItem)
- menus.addItem(NSMenuItem.separator())
- // menus.addItem(editItem)
- menus.addItem(renameItem)
- menus.addItem(changeItem)
- menus.addItem(NSMenuItem.separator())
- menus.addItem(promoteItem)
- menus.addItem(demoteItem)
-
- let point = view.convert(event.locationInWindow, from: nil)
- menus.popUp(positioning: nil, at: point, in: view)
- }
-
- func menuItemWithTitle(title:String, action:Selector?) -> NSMenuItem {
- let menuItem = NSMenuItem.init(title: title as String, action: action, keyEquivalent: "")
- menuItem.target = self
- return menuItem
- }
-
- func initNotification() {
- NotificationCenter.default.addObserver(self, selector: #selector(KMPDFViewCurrentPageDidChangedNotification), name: NSNotification.Name.init(rawValue: "KMPDFViewCurrentPageDidChanged"), object: nil)
- }
-
- func removeNotification() {
- NotificationCenter.default.removeObserver(self)
- }
-
- func reloadData() {
- self.BOTAOutlineView.reloadData(expandItemType: .none)
- }
-
- func editOutlineUI(editVC : KMOutlineEditViewController!) {
- if editVC.pageButton.state == NSControl.StateValue.on {
- let index = Int(editVC.outlineTargetPageIndexTextField.stringValue)!
- if editVC.originalDestination?.pageIndex != index {
- let page = editVC.pdfView?.document.page(at: UInt(index))
- if page != nil {
- let destination = CPDFDestination.init(document: editVC.pdfView!.document, pageIndex: index)
- editVC.outline?.destination = destination
- } else {
- __NSBeep()
- }
- }
- } else if editVC.urlButton.state == NSControl.StateValue.on {
- if editVC.originalURLString != editVC.outlineURLTextField.stringValue {
- var urlString = editVC.outlineURLTextField.stringValue
- let tLowerUrl = urlString.lowercased()
- if !tLowerUrl.hasPrefix("https://") && !tLowerUrl.hasPrefix("pf]://") && !urlString.hasPrefix("https://") &&
- urlString.lengthOfBytes(using: String.Encoding(rawValue: String.Encoding.utf16.rawValue)) > 0 {
- urlString = "http://\(urlString)"
- }
- let action = CPDFURLAction.init(url: urlString)
- editVC.outline?.action = action
- }
- } else if editVC.mailButton.state == NSControl.StateValue.on {
- var mailString = editVC.mailAddressTextField.stringValue
- let tLowerStr = mailString.lowercased()
- if !tLowerStr.hasPrefix("mailto:") {
- mailString = "mailto:\(mailString)"
- }
- if mailString != editVC.originalURLString {
- var action = CPDFURLAction.init(url: mailString)
- if action?.url == nil {
- action = CPDFURLAction.init(url: "mailto:")
- }
- editVC.outline?.action = action
- }
- }
- // self.mainWindowController.document?.undo()
- // if editVC.outlineNameTextView.string != editVC.originalLabel {
- // self.renamePDFOutline(outline: editVC.outline, label: editVC.outlineNameTextView.string)
- // }
- }
- }
- //Data
- extension KMOutlineViewController {
- func updateExtempViewState() {
- if(self.listView.document.outlineRoot() == nil || self.listView.document.outlineRoot().numberOfChildren == 0) { //无数据时的图
- self.emptyView.isHidden = false
- } else {
- self.emptyView.isHidden = true
- }
- }
- }
- //MARK: - Notification
- extension KMOutlineViewController {
- @objc func KMPDFViewCurrentPageDidChangedNotification(notification: NSNotification) {
- if notification.object is CPDFDocument {
- let pdfdocument : CPDFDocument = notification.object as! CPDFDocument
- if pdfdocument.isEqual(self.listView.document) {
- if !isLocalEvent {
- self.updateOutlineSelection()
- }
- self.isLocalEvent = false
- }
- }
- }
- }
- //MARK: - Menu 右键菜单
- extension KMOutlineViewController {
- @objc func outlineViewDoubleAction() {
- if(self.BOTAOutlineView.outlineView.clickedRow >= 0) {
- self.renameItemAction()
- }
- }
-
- @objc func addItemAction() {
- let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
- let selectRowIndexs = outlineView.selectedRowIndexes
- let dataCount = self.BOTAOutlineView.data?.children.count
- var index: Int
- var parent: KMBOTAOutlineItem = KMBOTAOutlineItem()
- var outlineItem: KMBOTAOutlineItem = KMBOTAOutlineItem()
- if selectRowIndexs.count == 0 {
- var lastOulineItem = KMBOTAOutlineItem()
- if dataCount == nil || dataCount == 0 {
- let item = KMBOTAOutlineItem()
- item.outline = self.listView.document.setNewOutlineRoot()
- item.parent = nil
- parent = item
-
- lastOulineItem = item
- } else {
- outlineItem = outlineView.item(atRow: outlineView.numberOfRows - 1) as! KMBOTAOutlineItem
- lastOulineItem = outlineItem
- while lastOulineItem.parent != nil {
- lastOulineItem = lastOulineItem.parent!
- }
- parent = lastOulineItem
- }
- index = Int(lastOulineItem.outline.numberOfChildren)
- } else {
- outlineItem = outlineView.item(atRow: selectRowIndexs.last ?? 0) as! KMBOTAOutlineItem
- parent = outlineItem.parent ?? KMBOTAOutlineItem()
- index = Int(outlineItem.outline.index + 1)
- }
-
- self.addOutlineToIndex(index: index, parent: parent)
- }
-
- @objc func addChildItemAction() {
- let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
- let selectRowIndexs = outlineView.selectedRowIndexes
- if selectRowIndexs.count != 0 {
- let outlineItem: KMBOTAOutlineItem = outlineView.item(atRow: selectRowIndexs.last!) as! KMBOTAOutlineItem
- let index = outlineItem.outline.numberOfChildren
- self.addOutlineToIndex(index: NSInteger(index), parent: outlineItem)
- }
- }
-
- @objc func addHigherItemAction() {
- let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
- let selectRowIndexs = outlineView.selectedRowIndexes
- if selectRowIndexs.count != 0 {
- let outlineItem: KMBOTAOutlineItem = outlineView.item(atRow: selectRowIndexs.last!) as! KMBOTAOutlineItem
- var parent = outlineItem.parent
- let index = NSInteger(parent!.outline.index) + 1
- parent = parent?.parent
- if parent != nil {
- self.addOutlineToIndex(index: index, parent: parent!)
- }
- }
- }
-
- @objc func deleteItemAction() {
- let outlineView: KMOutlineView = self.BOTAOutlineView.outlineView
- let selectRowIndexs = outlineView.selectedRowIndexes
- if selectRowIndexs.count != 0 {
- var outlineItems: [KMBOTAOutlineItem] = []
- for index in selectRowIndexs {
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: index) as! KMBOTAOutlineItem
- outlineItem.toIndex = index
- outlineItem.parent = outlineItem.parent ?? KMBOTAOutlineItem()
- outlineItems.append(outlineItem)
- }
- self.deleteOutline(outlineItems: outlineItems)
- }
- }
-
- @objc func editItemAction() {
- if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
- if self.BOTAOutlineView.outlineView.rowView(atRow: self.BOTAOutlineView.outlineView.clickedRow, makeIfNecessary: true) != nil {
- let cell = self.BOTAOutlineView.outlineView.rowView(atRow: self.BOTAOutlineView.outlineView.clickedRow, makeIfNecessary: true)
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
- let outlineEditViewController = KMOutlineEditViewController.init(outline: outlineItem.outline, document: self.listView)
- let popover = NSPopover()
- popover.delegate = self
- popover.contentViewController = outlineEditViewController
- popover.animates = true
- popover.behavior = .transient
- popover.show(relativeTo: cell!.bounds, of: cell!, preferredEdge: .minX)
- }
- } else {
- __NSBeep()
- }
- }
-
- @objc func renameItemAction() {
- if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
- self.renameOutlineWithRow(row: self.BOTAOutlineView.outlineView.clickedRow)
- } else {
- __NSBeep()
- }
- }
-
- @objc func changeItemAction() {
- if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
- let alter = NSAlert()
- alter.alertStyle = NSAlert.Style.informational
- alter.messageText = NSLocalizedString("Are you sure you want to set the target location of the selected outline to the current page?", comment: "")
- alter.addButton(withTitle: NSLocalizedString("Yes", comment:""))
- alter.addButton(withTitle: NSLocalizedString("No", comment:""))
- let modlres = alter.runModal()
- if modlres == NSApplication.ModalResponse.alertFirstButtonReturn {
- self.changeLocation(outlineItem: outlineItem, destination: self.fetchCurrentDestination())
- }
- } else {
- __NSBeep()
- }
- }
-
- @objc func promoteItemAction() {
- if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
- var parent = outlineItem.parent
- let index = NSInteger(parent!.outline.index) + 1
- parent = parent?.parent
- if parent != nil {
- self.moveOutline(outlineItem: outlineItem, index: index, parent: parent)
- }
- }
- }
-
- @objc func demoteItemAction() {
- if self.BOTAOutlineView.outlineView.clickedRow >= 0 {
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
- let parent = outlineItem.parent
- let newParent = parent?.children[Int(outlineItem.outline.index) - 1]
- let index = newParent?.children.count
- if (index != nil) {
- self.moveOutline(outlineItem: outlineItem, index: NSInteger(index ?? 0), parent: newParent)
- }
- }
- }
-
- @objc private func expandAllComments(item: NSMenuItem) {
- self.BOTAOutlineView.expandAllComments(item: item)
- }
-
- @objc private func collapseAllComments(item: NSMenuItem) {
-
- self.BOTAOutlineView.collapseAllComments(item: item)
- }
-
- @objc private func removeAllOutlineItem(item: NSMenuItem) {
- let alter = NSAlert()
- alter.alertStyle = NSAlert.Style.informational
- alter.messageText = NSLocalizedString("This will permanently remove all outlines. Are you sure to continue?", comment: "")
- alter.addButton(withTitle: NSLocalizedString("Yes", comment:""))
- alter.addButton(withTitle: NSLocalizedString("No", comment:""))
- let modlres = alter.runModal()
- if modlres == NSApplication.ModalResponse.alertFirstButtonReturn {
- self.removeAllOutline()
- }
- }
-
-
- @objc private func removeAllOutline() {
- guard let data = self.BOTAOutlineView.data else { return }
-
- for item in data.children {
- item.toIndex = Int(item.outline.index)
- }
- self.deleteOutline(outlineItems: data.children)
- self.BOTAOutlineView.reloadData(expandItemType: .none)
- }
- }
- //MARK: - Action
- extension KMOutlineViewController {
- @IBAction func addNewOutline(_ sender: Any) {
- self.addItemAction()
- }
-
- @IBAction func moreButton_click(_ sender: NSButton) {
- let rect = sender.convert(sender.bounds, to: self.view)
- moreMenu.popUp(positioning: nil, at: NSPoint(x: rect.origin.x, y: rect.origin.y-10), in: self.view)
- }
-
-
- @IBAction func escButtonAction(_ sender: Any) {
- self.cancelSelect()
- }
-
- func cancelSelect() {
- self.BOTAOutlineView.cancelSelect()
- }
-
- func renameOutlineWithRow(row: NSInteger) {
- DispatchQueue.main.async {
- self.renamePDFOutline = self.BOTAOutlineView.outlineView.item(atRow: row) as? KMBOTAOutlineItem
- let cell : KMBOTAOutlineCellView = self.BOTAOutlineView.outlineView.view(atColumn: 0, row: row, makeIfNecessary: true) as! KMBOTAOutlineCellView
- self.renameTextField = cell.titleLabel
- self.renameTextField.delegate = self
- self.renameTextField.isEditable = true
- self.renameTextField.becomeFirstResponder()
- }
- }
-
- func addOutlineToIndex(index: Int, parent: KMBOTAOutlineItem) {
- let pageIndex: Int = self.listView.currentPageIndex
- let label: String = self.fetchCurrentLabel(pageIndex: pageIndex)
- let destination: CPDFDestination = self.fetchCurrentDestination()
-
- self.addOutlineToIndex(index: index, pageIndex: pageIndex, destination: destination, lable: label, parent: parent)
- }
-
- func addOutlineToIndex(index: Int, pageIndex: Int, destination: CPDFDestination, lable: String, parent: KMBOTAOutlineItem) {
- let outlineItem = KMBOTAOutlineItem()
- outlineItem.destination = destination
- outlineItem.label = lable
- outlineItem.parent = parent
- outlineItem.toIndex = index
- self.addOutline(outlineItems: [outlineItem])
-
- let tempOutlineView = self.BOTAOutlineView!
- var index = -1
- if tempOutlineView.outlineView.numberOfRows == 1 || tempOutlineView.data == nil {
- index = 0
- } else {
- index = tempOutlineView.outlineView.row(forItem: outlineItem)
- }
- tempOutlineView.selectIndex(index: index)
- //滑动到指定位置
- if(tempOutlineView.outlineView.selectedRow >= 0) {
- self.renameOutlineWithRow(row: tempOutlineView.outlineView.selectedRow)
- }
-
- let row = tempOutlineView.outlineView.row(forItem: outlineItem)
- if Thread.current.isMainThread {
- tempOutlineView.outlineView.scrollToVisible(tempOutlineView.outlineView.rect(ofRow: row))
- } else {
- DispatchQueue.main.async {
- tempOutlineView.outlineView.scrollToVisible(tempOutlineView.outlineView.rect(ofRow: row))
- }
- }
- }
-
- func updateOutlineSelection() {
- KMPrint("updateOutlineSelection")
- let currentPageIndex = self.listView.currentPageIndex
- let numRows = self.BOTAOutlineView.outlineView.numberOfRows
- if numRows > 0 {
- for i in 0...numRows - 1 {
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: i) as! KMBOTAOutlineItem
- if (outlineItem.outline.destination == nil) {
- continue
- }
-
- if outlineItem.outline.destination.pageIndex == currentPageIndex {
- self.BOTAOutlineView.selectIndex(index: currentPageIndex)
- break
- }
- }
- }
- }
-
- func fetchCurrentDestination() -> CPDFDestination {
- //destination
- var destination: CPDFDestination
- let pageIndex: Int
- if self.listView.currentSelection != nil {
- 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)
- destination = des
- pageIndex = Int(self.listView.currentSelection.page.pageIndex())
- } else {
- 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)
- destination = des
- pageIndex = Int(self.listView.currentPageIndex)
- }
-
- if "\(destination.point.x )" == "nan" {
- destination = CPDFDestination(document: self.listView.document, pageIndex: pageIndex, at: CGPoint(x: 0, y: 0), zoom: self.listView.scaleFactor)
- }
- return destination
- }
-
- func fetchCurrentLabel(pageIndex: Int) -> String{
- //label
- var label = "\(NSLocalizedString("Page", comment: ""))\(pageIndex + 1)"
- if self.listView.currentSelection != nil && self.listView.currentSelection.selectionsByLine != nil {
- for currentSelection in self.listView.currentSelection.selectionsByLine {
- label = currentSelection.string()
- }
- }
- return label
- }
- }
- //MARK: - KMBOTAOutlineViewDelegate
- extension KMOutlineViewController: KMBOTAOutlineViewDelegate {
- func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, rightDidMoseDown: KMBOTAOutlineItem, event: NSEvent) {
- let row = outlineView.outlineView.row(forItem: rightDidMoseDown)
- if outlineView.outlineView.rowView(atRow: row, makeIfNecessary: false) != nil {
- let rowView = outlineView.outlineView.rowView(atRow: row, makeIfNecessary: false)
- self.addRightMenu(view: rowView!, event: event)
- }
- }
- func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, didReloadData: KMBOTAOutlineItem) {
- self.updateExtempViewState()
- }
-
- func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, didSelectItem: [KMBOTAOutlineItem]) {
- if self.BOTAOutlineView.outlineView.selectedRowIndexes.count == 1 {
- self.isLocalEvent = true
-
- let outlineItem: KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow:self.BOTAOutlineView.outlineView.selectedRow) as! KMBOTAOutlineItem
-
- if outlineItem.outline.destination != nil {
- if outlineItem.outline.destination.page() != nil {
- self.listView.go(toTargetPoint: outlineItem.outline.destination.point, on: outlineItem.outline.destination.page() , at: .top)
- } else {
- let alter = NSAlert()
- alter.alertStyle = NSAlert.Style.informational
- alter.messageText = NSLocalizedString("The target page is invalid, please relocate it.", comment: "")
- alter.addButton(withTitle: NSLocalizedString("OK", comment:""))
- alter.beginSheetModal(for: self.view.window ?? NSWindow())
- }
- } else if outlineItem.outline.action != nil {
- let alter = NSAlert()
- alter.alertStyle = NSAlert.Style.informational
- alter.messageText = NSLocalizedString("The target page is invalid, please relocate it.", comment: "")
- alter.addButton(withTitle: NSLocalizedString("OK", comment:""))
- alter.beginSheetModal(for: self.view.window ?? NSWindow())
- // self.listView.perform(outlineItem.outline.action)
- }
- }
- }
-
- func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, writeItems items: [Any], to pasteboard: NSPasteboard) -> Bool {
- if outlineView.outlineView.selectedRowIndexes.count > 1 || outlineView.outlineView.selectedRow == -1 {
- return false
- }
-
- self.dragPDFOutline = items.first as? KMBOTAOutlineItem
-
- let indexSet = [outlineView.outlineView.clickedRow]
- let indexSetData: Data = try!NSKeyedArchiver.archivedData(withRootObject: indexSet, requiringSecureCoding: true)
- pasteboard.declareTypes([NSPasteboard.PasteboardType(rawValue: "kKMPDFViewOutlineDragDataType")], owner: self)
- pasteboard.setData(indexSetData, forType: NSPasteboard.PasteboardType(rawValue: NSPasteboard.PasteboardType.RawValue("kKMPDFViewOutlineDragDataType")))
- return true
- }
-
- func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
- var dragOperation = NSDragOperation.init(rawValue: 0)
- if index >= 0 {
- dragOperation = NSDragOperation.move
- }
- return dragOperation
- }
-
- func BOTAOutlineView(_ outlineView: KMBOTAOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
- guard let dragOutlineItem = self.dragPDFOutline else { return false }
- let outlineItem: KMBOTAOutlineItem = (item ?? KMBOTAOutlineItem()) as! KMBOTAOutlineItem
- if index < 0 {
- return false
- }
-
- if outlineItem.parent == nil {
- var root = dragOutlineItem.parent
- while root?.parent?.children != nil {
- root = root?.parent!
- }
- if dragOutlineItem.parent!.isEqual(root) {
- if dragOutlineItem.outline.index > index {
- self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: root)
- } else {
- self.moveOutline(outlineItem: dragOutlineItem, index: index - 1, parent: root)
- }
- } else {
- self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: root)
- }
- } else {
- if dragOutlineItem.parent!.isEqual(item) {
- // if dragOutlineItem.outline.index != 0 {
- if dragOutlineItem.outline.index > index {
- self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: item as? KMBOTAOutlineItem)
- } else {
- self.moveOutline(outlineItem: dragOutlineItem, index: index - 1, parent: item as? KMBOTAOutlineItem)
- }
- // } else {
- // return false
- // }
- } else {
- var tOutline = outlineItem
- var isContains = false
- while (tOutline.parent != nil) {
- if tOutline.outline.isEqual(dragOutlineItem.outline) {
- isContains = true
- break
- }
- tOutline = tOutline.parent!
- }
- if isContains == false {
- self.moveOutline(outlineItem: dragOutlineItem, index: index, parent: item as? KMBOTAOutlineItem)
- }
- }
- }
- self.BOTAOutlineView.selectItem(outlineItem: dragOutlineItem)
-
- return true
- }
- }
- //MARK: - NSTextFieldDelegate
- extension KMOutlineViewController: NSTextFieldDelegate {
- func controlTextDidEndEditing(_ obj: Notification) {
- if (self.renameTextField.isEqual(obj.object)) {
- let textField : NSTextField = obj.object as! NSTextField
- self.renamePDFOutline(outlineItem: self.renamePDFOutline, label: textField.stringValue)
- }
- }
- }
- //MARK: - NSPopoverDelegate
- extension KMOutlineViewController: NSPopoverDelegate {
- func popoverWillClose(_ notification: Notification) {
- let popover : NSPopover = notification.object as! NSPopover
- if popover.contentViewController!.isKind(of: KMOutlineEditViewController.self) {
-
- }
- }
- }
- //MARK: - NSMenuItemValidation
- extension KMOutlineViewController: NSMenuDelegate, NSMenuItemValidation {
- func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
- let action = menuItem.action
- if action == #selector(addItemAction) ||
- action == #selector(addChildItemAction) ||
- action == #selector(addHigherItemAction) ||
- action == #selector(deleteItemAction) ||
- action == #selector(editItemAction) ||
- action == #selector(changeItemAction) ||
- action == #selector(renameItemAction) ||
- action == #selector(promoteItemAction) ||
- action == #selector(demoteItemAction) {
- if self.BOTAOutlineView.outlineView.selectedRowIndexes.count > 1 {
- if action == #selector(deleteItemAction) {
- return true
- }
- return false
- } else if self.BOTAOutlineView.outlineView.selectedRowIndexes.count > 0 {
- if action == #selector(addChildItemAction) || action == #selector(changeItemAction) {
- return true
- }
- }
- if self.BOTAOutlineView.outlineView.clickedRow == -1 {
- if action == #selector(addItemAction) {
- return true
- } else {
- return false
- }
- } else {
- let outlineItem : KMBOTAOutlineItem = self.BOTAOutlineView.outlineView.item(atRow: self.BOTAOutlineView.outlineView.clickedRow) as! KMBOTAOutlineItem
- if outlineItem.outline.index > 0 {
- if action == #selector(demoteItemAction) {
- return true
- }
- } else {
- if action == #selector(demoteItemAction) {
- return false
- }
- }
-
- let parentOutline = outlineItem.outline.parent
- let grandparentOutline = parentOutline?.parent
- if grandparentOutline != nil {
- if action == #selector(addHigherItemAction) {
- return true
- } else if action == #selector(promoteItemAction) {
- return true
- }
- } else {
- if action == #selector(addHigherItemAction) {
- return false
- } else if action == #selector(promoteItemAction) {
- return false
- }
- }
- }
- return true
- }
-
- if (action == #selector(undo)) {
- return self.listView.undoManager?.canUndo ?? false
- }
- if (action == #selector(redo)) {
- return self.listView.undoManager?.canRedo ?? false
- }
-
- if (action == #selector(expandAllComments)) {
- var canExpand = false
- for row in 0..<self.BOTAOutlineView.outlineView.numberOfRows {
- // 检查当前项目是否可以展开
- let item = self.BOTAOutlineView.outlineView.item(atRow: row)
- if self.BOTAOutlineView.outlineView.isExpandable(item) {
- if !self.BOTAOutlineView.outlineView.isItemExpanded(item) {
- canExpand = true
- break
- }
- }
- }
- return canExpand
- }
-
- if (action == #selector(collapseAllComments)) {
- var canCollapse = false
- for row in 0..<self.BOTAOutlineView.outlineView.numberOfRows {
- let item = self.BOTAOutlineView.outlineView.item(atRow: row)
- if self.BOTAOutlineView.outlineView.isExpandable(item) {
- if self.BOTAOutlineView.outlineView.isItemExpanded(item) {
- canCollapse = true
- break
- }
- }
- }
- return canCollapse
- }
-
- if (action == #selector(removeAllOutlineItem)) {
- if self.BOTAOutlineView.outlineView.item(atRow: 0) != nil {
- return true
- } else {
- return false
- }
- }
- return true
- }
- }
- //MARK: - 快捷键
- extension KMOutlineViewController {
- @IBAction func delete(_ sender: Any) {
- self.deleteItemAction()
- }
- }
- //MARK: - undoRedo
- extension KMOutlineViewController {
- func moveOutline(outlineItem: KMBOTAOutlineItem, index: NSInteger, parent: KMBOTAOutlineItem!) {
- let tempOutlineView = self.BOTAOutlineView!
-
- let indexTemp = outlineItem.outline.index
- let parentTemp = outlineItem.parent
-
- //元数据移除
- outlineItem.outline.removeFromParent()
- parent.outline.insertChild(outlineItem.outline, at: UInt(index))
-
- //显示数据刷新
- outlineItem.parent?.children.removeObject(outlineItem)
- parent?.children.insert(outlineItem, at: index)
- outlineItem.parent = parent
- tempOutlineView.outlineView.reloadData()
- tempOutlineView.cancelSelect()
-
- //展开
- outlineItem.isItemExpanded = true
- outlineItem.parent?.isItemExpanded = true
- tempOutlineView.outlineView.expandItem(outlineItem)
- tempOutlineView.outlineView.expandItem(outlineItem.parent)
-
- self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
- self.moveOutline(outlineItem: outlineItem, index: NSInteger(indexTemp), parent: parentTemp)
- }
- }
-
- func changeLocation(outlineItem: KMBOTAOutlineItem, destination: CPDFDestination) {
- let tempOutlineView = self.BOTAOutlineView!
-
- let temp = outlineItem.outline.destination
- outlineItem.outline.destination = CPDFDestination(document: destination.document, pageIndex: destination.pageIndex, at: destination.point, zoom: destination.zoom)
- tempOutlineView.outlineView.reloadItem(outlineItem)
-
- self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
- self.changeLocation(outlineItem: outlineItem, destination: temp!)
- }
- }
-
- func renamePDFOutline(outlineItem: KMBOTAOutlineItem!, label: String) {
- let tempOutlineView = self.BOTAOutlineView!
-
- self.view.window?.makeFirstResponder(tempOutlineView.outlineView)
- self.renameTextField.isEditable = false
- if outlineItem.outline.label == label {
- return
- }
- let temp: String = outlineItem.outline.label
- outlineItem.outline.label = label
- tempOutlineView.outlineView.reloadItem(outlineItem)
-
- self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
- self.renamePDFOutline(outlineItem: outlineItem, label: temp)
- }
- }
-
- func deleteOutline(outlineItems: [KMBOTAOutlineItem]) {
- NSApp.mainWindow?.makeFirstResponder(self.BOTAOutlineView)
- let tempOutlineView = self.BOTAOutlineView!
-
- var tempOutlineItems: [KMBOTAOutlineItem] = outlineItems
- tempOutlineItems.sort(){$0.toIndex > $1.toIndex}
-
- for outlineItem in tempOutlineItems {
- outlineItem.outline.removeFromParent()
- let index = outlineItem.parent?.children.firstIndex(of: outlineItem)
- outlineItem.toIndex = index!
- outlineItem.parent?.children.removeObject(outlineItem)
- }
-
- //展开
- for outlineItem in tempOutlineItems {
- outlineItem.parent?.isItemExpanded = true
- tempOutlineView.outlineView.expandItem(outlineItem.parent)
- }
-
- tempOutlineView.outlineView.reloadData()
- //删除需要取消选中
- tempOutlineView.cancelSelect()
-
- //刷新nil数据
- self.updateExtempViewState()
- self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
- self.addOutline(outlineItems: tempOutlineItems)
- }
- }
-
- func addOutline(outlineItems: [KMBOTAOutlineItem]) {
- NSApp.mainWindow?.makeFirstResponder(self.BOTAOutlineView)
- let tempOutlineView = self.BOTAOutlineView!
- //先取消选中
- tempOutlineView.cancelSelect()
-
- var tempOutlineItems: [KMBOTAOutlineItem] = outlineItems
- tempOutlineItems.sort(){$0.toIndex < $1.toIndex}
-
- for outlineItem in tempOutlineItems {
- if outlineItem.outline.label != nil {
- outlineItem.parent?.outline.insertChild(outlineItem.outline, at: UInt(outlineItem.toIndex))
- } else {
- let outline = outlineItem.parent?.outline.insertChild(at: UInt(outlineItem.toIndex))
- outline?.label = outlineItem.label
- outline?.destination = outlineItem.destination
- outlineItem.outline = outline!
- }
- outlineItem.parent?.children.insert(outlineItem, at: outlineItem.toIndex)
- }
-
- if tempOutlineView.data?.children.count == 0 || tempOutlineView.data == nil {
- tempOutlineView.inputData = self.listView.document.outlineRoot()
- } else {
- tempOutlineView.outlineView.reloadData()
- }
-
- //展开
- // DispatchQueue.main.async {
- for outlineItem in tempOutlineItems {
- var tempParent = outlineItem
- while tempParent.parent != nil {
- tempParent.isItemExpanded = true
- tempParent = tempParent.parent!
- tempOutlineView.outlineView.expandItem(tempParent)
- }
- tempOutlineView.outlineView.expandItem(tempParent.parent)
- }
- // }
-
- self.updateExtempViewState()
- self.listView.undoManager?.registerUndo(withTarget: self) { [unowned self] targetType in
- self.deleteOutline(outlineItems: tempOutlineItems)
- }
- }
-
- @IBAction func undo(_ sender: Any) {
- if (self.listView.undoManager?.canUndo ?? false) {
- self.listView.undoManager?.undo()
- }
- }
-
- @IBAction func redo(_ sender: Any) {
- if (self.listView.undoManager?.canRedo ?? false) {
- self.listView.undoManager?.redo()
- }
- }
- }
|