|
@@ -7,12 +7,634 @@
|
|
|
|
|
|
import Cocoa
|
|
import Cocoa
|
|
|
|
|
|
-class KMOutlineViewController: NSViewController {
|
|
|
|
-
|
|
|
|
|
|
+class KMOutlineViewController: NSViewController,NSMenuItemValidation {
|
|
|
|
+
|
|
|
|
+ @IBOutlet weak var outlineView: KMOutlineView!
|
|
|
|
+ var dragPDFOutline : CPDFOutline!
|
|
|
|
+ var renameTextField : NSTextField!
|
|
|
|
+ var mainWindowController : MainWindowController!
|
|
|
|
+ var renamePDFOutline : CPDFOutline!
|
|
override func viewDidLoad() {
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
super.viewDidLoad()
|
|
self.view.wantsLayer = true
|
|
self.view.wantsLayer = true
|
|
self.view.layer?.backgroundColor = NSColor.green.cgColor
|
|
self.view.layer?.backgroundColor = NSColor.green.cgColor
|
|
|
|
+
|
|
|
|
+ self.outlineView.registerForDraggedTypes([NSPasteboard.PasteboardType(rawValue: "kKMPDFViewOutlineDragDataType")])
|
|
|
|
+ self.outlineView.doubleAction = #selector(outlineViewDoubleAction)
|
|
|
|
+ self.outlineView.target = self
|
|
|
|
+
|
|
|
|
+ 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)
|
|
|
|
+ self.outlineView.menu = menus
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func outlineViewDoubleAction() {
|
|
|
|
+ if(self.outlineView.clickedRow >= 0) {
|
|
|
|
+ self.renameItemAction()
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func addItemAction() {
|
|
|
|
+ let selectRowIndexs = self.selectedRowIndexs()
|
|
|
|
+ if (selectRowIndexs.count == 0) {
|
|
|
|
+ var lastPDFOuline : CPDFOutline = self.outlineView.item(atRow: self.outlineView.numberOfRows - 1) as! CPDFOutline
|
|
|
|
+ var rootPDFOutline : CPDFOutline!
|
|
|
|
+ if(lastPDFOuline != nil) {
|
|
|
|
+ while ((lastPDFOuline.parent) != nil) {
|
|
|
|
+ lastPDFOuline = lastPDFOuline.parent
|
|
|
|
+ }
|
|
|
|
+ rootPDFOutline = lastPDFOuline
|
|
|
|
+ } else {
|
|
|
|
+ rootPDFOutline = self.mainWindowController.listView.document.outlineRoot()
|
|
|
|
+ if(rootPDFOutline == nil) {
|
|
|
|
+ rootPDFOutline = self.mainWindowController.listView.document.setNewOutlineRoot()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ let index = rootPDFOutline.numberOfChildren
|
|
|
|
+ self.addPDFOutlineToIndex(index: NSInteger(index), atParent: rootPDFOutline)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func addChildItemAction() {
|
|
|
|
+ let selectedRowIndexes : IndexSet! = self.selectedRowIndexs()
|
|
|
|
+ if selectedRowIndexes.count == 0 {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ } else {
|
|
|
|
+ let parent = self.outlineView.item(atRow: selectedRowIndexes.last!) as! CPDFOutline
|
|
|
|
+ let index = parent.numberOfChildren
|
|
|
|
+ self.addPDFOutlineToIndex(index: NSInteger(index), atParent: parent)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func addHigherItemAction() {
|
|
|
|
+ let selectedRowIndexes : IndexSet! = self.selectedRowIndexs()
|
|
|
|
+ if selectedRowIndexes.count == 0 {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ } else {
|
|
|
|
+ let currentPDFOutline = self.outlineView.item(atRow: selectedRowIndexes.last!) as! CPDFOutline
|
|
|
|
+ let parent = currentPDFOutline.parent
|
|
|
|
+ let index = NSInteger(parent!.index) + 1
|
|
|
|
+ if parent != nil {
|
|
|
|
+ self.addPDFOutlineToIndex(index: index, atParent: parent)
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func deleteItemAction() {
|
|
|
|
+ let selectedRowIndexes : IndexSet! = self.selectedRowIndexs()
|
|
|
|
+ if selectedRowIndexes.count == 0 {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ } else {
|
|
|
|
+ var selectedPDFOutlineArr = [CPDFOutline]();
|
|
|
|
+ for (index,_) in selectedRowIndexes.enumerated() {
|
|
|
|
+ var outline : CPDFOutline = self.outlineView.item(atRow: index) as! CPDFOutline
|
|
|
|
+ selectedPDFOutlineArr.append(outline)
|
|
|
|
+ }
|
|
|
|
+ for tOutline in selectedPDFOutlineArr {
|
|
|
|
+ self.removePDFOutline(outline: tOutline, toIndex: NSInteger(tOutline.index), atParent: tOutline.parent)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func editItemAction() {
|
|
|
|
+ if self.outlineView.clickedRow >= 0 {
|
|
|
|
+ let cell = self.outlineView.rowView(atRow: self.outlineView.clickedRow, makeIfNecessary: true)
|
|
|
|
+ let outline = self.outlineView.item(atRow: self.outlineView.clickedRow)
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func renameItemAction() {
|
|
|
|
+ if self.outlineView.clickedRow >= 0 {
|
|
|
|
+ self.renameOutlineWithRow(row: self.outlineView.clickedRow)
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func changeItemAction() {
|
|
|
|
+ if self.outlineView.clickedRow >= 0 {
|
|
|
|
+ let outline = self.outlineView.item(atRow: self.outlineView.clickedRow)
|
|
|
|
+ let alter = NSAlert()
|
|
|
|
+ alter.alertStyle = NSAlert.Style.informational
|
|
|
|
+ alter.messageText = NSLocalizedString("Are you sure you want to set the destination as the current location?", comment: "")
|
|
|
|
+ alter.addButton(withTitle: NSLocalizedString("Yes", comment:""))
|
|
|
|
+ alter.addButton(withTitle: NSLocalizedString("No", comment:""))
|
|
|
|
+ let modlres = alter.runModal()
|
|
|
|
+ if modlres == NSApplication.ModalResponse.alertFirstButtonReturn {
|
|
|
|
+ self.setPDFOutline(outline: outline as? CPDFOutline, destination: self.mainWindowController.listView.currentDestination)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func promoteItemAction() {
|
|
|
|
+ if self.outlineView.clickedRow >= 0 {
|
|
|
|
+ let outline = self.outlineView.item(atRow: self.outlineView.clickedRow) as! CPDFOutline
|
|
|
|
+ var parent = outline.parent
|
|
|
|
+ let index = NSInteger(parent!.index) + 1
|
|
|
|
+ parent = parent?.parent
|
|
|
|
+ if parent != nil {
|
|
|
|
+ self.movePDFOutline(outline: outline, toIndex: index, atParent: parent)
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func demoteItemAction() {
|
|
|
|
+ if self.outlineView.clickedRow >= 0 {
|
|
|
|
+ let outline = self.outlineView.item(atRow: self.outlineView.clickedRow) as! CPDFOutline
|
|
|
|
+ var parent = outline.parent
|
|
|
|
+ let newParent = parent?.child(at: UInt(outline.index - 1))
|
|
|
|
+ let index = newParent?.numberOfChildren
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //MARK: - Outline
|
|
|
|
+
|
|
|
|
+ func renameOutlineWithRow(row:NSInteger) {
|
|
|
|
+ self.renamePDFOutline = self.outlineView.item(atRow: row) as? CPDFOutline
|
|
|
|
+ let cell : KMOutlineCellView = self.outlineView.view(atColumn: 0, row: row, makeIfNecessary: true) as! KMOutlineCellView
|
|
|
|
+ self.renameTextField = cell.titleTextField
|
|
|
|
+ self.renameTextField.delegate = self
|
|
|
|
+ self.renameTextField.isEditable = true
|
|
|
|
+ self.renameTextField.becomeFirstResponder()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func renamePDFOutline(outline : CPDFOutline! , label:String) {
|
|
|
|
+ if outline.label == label {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ outline.label = label
|
|
|
|
+ self.outlineView.reloadData()
|
|
|
|
+
|
|
|
|
+ var indexSet = IndexSet()
|
|
|
|
+ indexSet.insert(self.outlineView.row(forItem: outline))
|
|
|
|
+ self.outlineView.selectRowIndexes(indexSet, byExtendingSelection: false)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func movePDFOutline(outline : CPDFOutline! , toIndex index : NSInteger , atParent parent : CPDFOutline!) {
|
|
|
|
+ outline.removeFromParent()
|
|
|
|
+ parent.insertChild(outline, at: UInt(index))
|
|
|
|
+ self.outlineView.reloadData()
|
|
|
|
+ self.outlineView.expandItem(parent)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func addPDFOutlineCurrentSelections() {
|
|
|
|
+ var string : String = ""
|
|
|
|
+ for currentSelection in self.mainWindowController.listView.currentSelection.selectionsByLine {
|
|
|
|
+ if string.count == 0 {
|
|
|
|
+ string = "\(string)+\("\n")"
|
|
|
|
+ string = "\(string)+\(String(describing: currentSelection.string()))"
|
|
|
|
+ } else {
|
|
|
|
+ string = currentSelection.string()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var parent : CPDFOutline?
|
|
|
|
+ var index : Int = 0
|
|
|
|
+ let selectRowIndexes = self.selectedRowIndexs()
|
|
|
|
+ if selectRowIndexes.count == 0 {
|
|
|
|
+ var lastOutline = self.outlineView.item(atRow: self.outlineView.numberOfRows - 1) as? CPDFOutline
|
|
|
|
+ if lastOutline != nil {
|
|
|
|
+ while ((lastOutline?.parent) != nil) {
|
|
|
|
+ lastOutline = lastOutline?.parent
|
|
|
|
+ }
|
|
|
|
+ parent = lastOutline
|
|
|
|
+ } else {
|
|
|
|
+ parent = self.mainWindowController.listView.document.outlineRoot()
|
|
|
|
+ if parent == nil {
|
|
|
|
+ parent = self.mainWindowController.listView.document.setNewOutlineRoot()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ index = Int(parent?.numberOfChildren ?? 0)
|
|
|
|
+ } else {
|
|
|
|
+ let currentPDFOutline = self.outlineView.item(atRow: selectRowIndexes.last ?? 0) as! CPDFOutline
|
|
|
|
+ parent = currentPDFOutline.parent
|
|
|
|
+ index = Int(currentPDFOutline.index + 1)
|
|
|
|
+ }
|
|
|
|
+ if parent != nil {
|
|
|
|
+ let outline = parent?.insertChild(at: UInt(index))
|
|
|
|
+ outline?.label = string
|
|
|
|
+ outline?.destination = self.mainWindowController.listView.currentDestination
|
|
|
|
+ self.addPDFOutline(outline: outline, toIndex: index, atParent: parent)
|
|
|
|
+ } else {
|
|
|
|
+ __NSBeep()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func updateOutlineSelection() {
|
|
|
|
+ let currentPageIndex = self.mainWindowController.listView.currentPageIndex
|
|
|
|
+ let currentPage : CPDFPage = self.mainWindowController.listView.document.page(at: UInt(currentPageIndex))
|
|
|
|
+ let numRows = self.outlineView.numberOfRows
|
|
|
|
+ var arr = [[String : CPDFPage]]()
|
|
|
|
+ for i in 0..<numRows {
|
|
|
|
+ let tPDFOutline = self.outlineView.item(atRow: i) as! CPDFOutline
|
|
|
|
+ let tPage = tPDFOutline.destination.pageIndex
|
|
|
|
+ var page = self.mainWindowController.listView.document.page(at: UInt(tPage))!
|
|
|
|
+ var tDict : [String : CPDFPage] = ["\(i)":page]
|
|
|
|
+ arr.append(tDict)
|
|
|
|
+ }
|
|
|
|
+ DispatchQueue.global(qos: .utility).async{
|
|
|
|
+ var hasExistInOutlineView = false
|
|
|
|
+ var selectIndex = 0
|
|
|
|
+ for (index,value) in arr.enumerated() {
|
|
|
|
+ let dict : [String : CPDFPage] = value
|
|
|
|
+ let page: CPDFPage = dict.values.first ?? CPDFPage()
|
|
|
|
+ let index = Int(index)
|
|
|
|
+ if page.isEqual(currentPage) {
|
|
|
|
+ selectIndex = index
|
|
|
|
+ hasExistInOutlineView = true
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ DispatchQueue.main.async {
|
|
|
|
+ if !hasExistInOutlineView {
|
|
|
|
+ self.outlineView.deselectRow(self.outlineView.selectedRow)
|
|
|
|
+ } else {
|
|
|
|
+ self.outlineView.selectRowIndexes([selectIndex], byExtendingSelection: false)
|
|
|
|
+ self.outlineView.scrollRowToVisible(selectIndex)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //MARK: - Accessors
|
|
|
|
+
|
|
|
|
+ func menuItemWithTitle(title:String, action:Selector?) -> NSMenuItem {
|
|
|
|
+ let menuItem = NSMenuItem.init(title: title as String, action: action, keyEquivalent: "")
|
|
|
|
+ menuItem.target = self
|
|
|
|
+ return menuItem
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func selectedRowIndexs() -> IndexSet {
|
|
|
|
+ let clickRow = self.outlineView.clickedRow
|
|
|
|
+ var selectedRowIndexs = self.outlineView.selectedRowIndexes
|
|
|
|
+ if(clickRow != -1 && !selectedRowIndexs.contains(clickRow)) {
|
|
|
|
+ selectedRowIndexs = [clickRow]
|
|
|
|
+ }
|
|
|
|
+ return selectedRowIndexs
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func reloadData() {
|
|
|
|
+ self.outlineView.reloadData()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func addPDFOutlineToIndex(index:NSInteger, atParent parent:CPDFOutline!) {
|
|
|
|
+ let currentPageIndex = self.mainWindowController.listView.currentPageIndex
|
|
|
|
+ var outline = parent.insertChild(at: UInt(index))
|
|
|
|
+ outline?.label = "\(NSLocalizedString("Page", comment: ""))\(currentPageIndex+1)"
|
|
|
|
+ let des = self.mainWindowController.listView.currentDestination
|
|
|
|
+ if "\(des?.point.x ?? 0)" != "nan" {
|
|
|
|
+ outline?.destination = self.mainWindowController.listView.currentDestination
|
|
|
|
+ } else {
|
|
|
|
+ let destination : CPDFDestination = CPDFDestination(document: self.mainWindowController.listView.document, pageIndex: currentPageIndex, at: CGPoint(x: 0, y: 0), zoom: self.mainWindowController.listView.scaleFactor)
|
|
|
|
+ outline?.destination = destination
|
|
|
|
+ }
|
|
|
|
+ self.addPDFOutline(outline:outline,toIndex: index,atParent: parent)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func addPDFOutline(outline:CPDFOutline! , toIndex index : NSInteger , atParent parent : CPDFOutline!) {
|
|
|
|
+ self.view.window?.makeFirstResponder(self.outlineView)
|
|
|
|
+ if outline.parent == nil {
|
|
|
|
+ parent.insertChild(outline, at: UInt(index))
|
|
|
|
+ }
|
|
|
|
+ self.outlineView.reloadData()
|
|
|
|
+ self.outlineView.expandItem(parent)
|
|
|
|
+ let indexSet : IndexSet = [self.outlineView.row(forItem: outline)]
|
|
|
|
+ self.outlineView.selectRowIndexes(indexSet, byExtendingSelection: false)
|
|
|
|
+ if(self.outlineView.selectedRow >= 0) {
|
|
|
|
+ self.renameOutlineWithRow(row: self.outlineView.selectedRow)
|
|
|
|
+ }
|
|
|
|
+ if Thread.current.isMainThread {
|
|
|
|
+ self.outlineView.scrollToVisible(self.outlineView.rect(ofRow: index))
|
|
|
|
+ } else {
|
|
|
|
+ DispatchQueue.main.async {
|
|
|
|
+ self.outlineView.scrollToVisible(self.outlineView.rect(ofRow: index))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func removePDFOutline(outline:CPDFOutline! , toIndex index : NSInteger , atParent parent : CPDFOutline!) {
|
|
|
|
+ outline.removeFromParent()
|
|
|
|
+ self.outlineView.reloadData()
|
|
|
|
+ self.outlineView.expandItem(parent)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func setPDFOutline(outline:CPDFOutline! , destination : CPDFDestination!) {
|
|
|
|
+ outline.destination = destination
|
|
|
|
+ self.outlineView.reloadData()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //MARK: 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.outlineView.selectedRowIndexes.count > 1 {
|
|
|
|
+ if action == #selector(deleteItemAction) {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ return false
|
|
|
|
+ } else if self.outlineView.selectedRowIndexes.count > 0 {
|
|
|
|
+ if action == #selector(addChildItemAction) || action == #selector(changeItemAction) {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if self.outlineView.clickedRow == -1 {
|
|
|
|
+ if action == #selector(addItemAction) {
|
|
|
|
+ return true
|
|
|
|
+ } else {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ let outline : CPDFOutline = self.outlineView.item(atRow: self.outlineView.clickedRow) as! CPDFOutline
|
|
|
|
+ if outline.index > 0 {
|
|
|
|
+ if action == #selector(demoteItemAction) {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if action == #selector(demoteItemAction) {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let parentOutline = 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
|
|
|
|
+ }
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// MARK - NSOutlineViewDataSource,NSOutlineViewDelegate
|
|
|
|
+
|
|
|
|
+extension KMOutlineViewController : NSOutlineViewDataSource,NSOutlineViewDelegate {
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
|
|
|
+ if (item == nil) {
|
|
|
|
+ var newitem : CPDFOutline? = self.mainWindowController.listView.document.outlineRoot()
|
|
|
|
+ if(newitem?.numberOfChildren == 0) { //无数据时的图
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return Int((item as? CPDFOutline)?.numberOfChildren ?? 0)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
|
|
|
+ var newItem : CPDFOutline = item as! CPDFOutline
|
|
|
|
+ if (newItem == nil) {
|
|
|
|
+ newItem = self.mainWindowController.listView.document.outlineRoot()
|
|
|
|
+ }
|
|
|
|
+ var child : CPDFOutline = newItem.child(at: UInt(index))
|
|
|
|
+ return child
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
|
|
|
+ var newItem : CPDFOutline = item as! CPDFOutline
|
|
|
|
+ if (newItem == nil) {
|
|
|
|
+ newItem = self.mainWindowController.listView.document.outlineRoot()
|
|
|
|
+ }
|
|
|
|
+ return newItem.numberOfChildren > 0
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
|
|
|
+ let cell : KMOutlineCellView = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMOutlineCellView"), owner: self) as! KMOutlineCellView
|
|
|
|
+ var outline : CPDFOutline = item as! CPDFOutline
|
|
|
|
+ cell.titleTextField.stringValue = outline.label
|
|
|
|
+ var destination = outline.destination
|
|
|
|
+ if destination == nil {
|
|
|
|
+ let action = outline.action
|
|
|
|
+ if (action != nil) && (action is CPDFGoToAction) {
|
|
|
|
+ destination = (action as? CPDFGoToAction)?.destination()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if destination != nil {
|
|
|
|
+ cell.pageTextField.stringValue = "\((destination?.pageIndex ?? 0)+1)"
|
|
|
|
+ } else {
|
|
|
|
+ cell.pageTextField.stringValue = ""
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let font : NSFont = NSFont.systemFont(ofSize: CGFloat(UserDefaults.standard.float(forKey: "SKOfficeTableFontSize")))
|
|
|
|
+ if (font != nil) {
|
|
|
|
+ cell.titleTextField.font = NSFont.init(name: cell.titleTextField.font!.fontName, size: font.pointSize)
|
|
|
|
+ cell.pageTextField.font = NSFont.init(name: cell.pageTextField.font!.fontName, size: font.pointSize)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return cell
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView? {
|
|
|
|
+ let rowView = KMCustomTableRowView()
|
|
|
|
+ return rowView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
|
|
|
|
+ let font : NSFont = NSFont.systemFont(ofSize: CGFloat(UserDefaults.standard.float(forKey: "SKOfficeTableFontSize")))
|
|
|
|
+ return 27 + font.pointSize
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool {
|
|
|
|
+ if self.outlineView.selectedRowIndexes.count > 1 {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ let outline : CPDFOutline = item as! CPDFOutline
|
|
|
|
+ if outline.destination != nil {
|
|
|
|
+ self.mainWindowController.listView.go(to: outline.destination)
|
|
|
|
+ } else if outline.action != nil {
|
|
|
|
+ self.mainWindowController.listView.perform(outline.action)
|
|
|
|
+ }
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, writeItems items: [Any], to pasteboard: NSPasteboard) -> Bool {
|
|
|
|
+ if self.outlineView.selectedRowIndexes.count > 1 {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.dragPDFOutline = items.first as? CPDFOutline
|
|
|
|
+
|
|
|
|
+ let indexSet = [self.outlineView.clickedRow]
|
|
|
|
+ let indexSetData : Data = NSKeyedArchiver.archivedData(withRootObject: indexSet) as Data
|
|
|
|
+ pasteboard.declareTypes([NSPasteboard.PasteboardType(rawValue: "kKMPDFViewOutlineDragDataType")], owner: self)
|
|
|
|
+ pasteboard.setData(indexSetData, forType: NSPasteboard.PasteboardType(rawValue: NSPasteboard.PasteboardType.RawValue("kKMPDFViewOutlineDragDataType")))
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func outlineView(_ outlineView: NSOutlineView, 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 outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
|
|
|
|
+ if ((self.dragPDFOutline == nil) || (index < 0)) {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ let outline = item as! CPDFOutline
|
|
|
|
+ if outline.parent == nil {
|
|
|
|
+ var root = self.dragPDFOutline
|
|
|
|
+ while root?.parent != nil {
|
|
|
|
+ root = root?.parent
|
|
|
|
+ }
|
|
|
|
+ if self.dragPDFOutline.parent.isEqual(root) {
|
|
|
|
+ if self.dragPDFOutline.index > index {
|
|
|
|
+ self.movePDFOutline(outline: self.dragPDFOutline, toIndex: index, atParent: root)
|
|
|
|
+ } else {
|
|
|
|
+ self.movePDFOutline(outline: self.dragPDFOutline, toIndex: index - 1, atParent: root)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ self.movePDFOutline(outline: self.dragPDFOutline, toIndex: index, atParent: root)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if self.dragPDFOutline.parent.isEqual(item) {
|
|
|
|
+ if self.dragPDFOutline.index != 0 {
|
|
|
|
+ if self.dragPDFOutline.index > index {
|
|
|
|
+ self.movePDFOutline(outline: self.dragPDFOutline, toIndex: index, atParent: outline)
|
|
|
|
+ } else {
|
|
|
|
+ self.movePDFOutline(outline: self.dragPDFOutline, toIndex: index - 1, atParent: outline)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ var tOutline = outline
|
|
|
|
+ var isContains = false
|
|
|
|
+ while tOutline != nil {
|
|
|
|
+ if tOutline.isEqual(self.dragPDFOutline) {
|
|
|
|
+ isContains = true
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ tOutline = tOutline.parent
|
|
|
|
+ }
|
|
|
|
+ if isContains == false {
|
|
|
|
+ self.movePDFOutline(outline: self.dragPDFOutline, toIndex: index, atParent: outline)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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(outline: self.renamePDFOutline, label: textField.stringValue)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// MARK - NSTextFieldDelegate
|
|
|
|
+
|
|
|
|
+extension KMOutlineViewController : NSPopoverDelegate {
|
|
|
|
+ func popoverWillClose(_ notification: Notification) {
|
|
|
|
+ let popover : NSPopover = notification.object as! NSPopover
|
|
|
|
+ if popover.contentViewController!.isKind(of: KMOutlineEditViewController.self) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|