123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- //
- // KMLeftSideViewController+Outline.swift
- // PDF Master
- //
- // Created by tangchao on 2023/12/22.
- //
- import Foundation
- enum KMOutlineViewMenuItemTag: Int {
- case addEntry = 0
- case addChild
- case addAunt
- case remove
- case edit
- case setDestination
- case rename
- case promote
- case demote
- }
- extension KMLeftSideViewController {
- func updateOutlineSelection() {
- // if ([[pdfView document] outlineRoot] == nil || mwcFlags.updatingOutlineSelection)
- if self.listView.document.outlineRoot() == nil {
- return
- }
- // mwcFlags.updatingOutlineSelection = YES;
- let numRows = self.tocOutlineView.numberOfRows
-
- var arr = NSMutableArray()
- for i in 0 ..< numRows {
- guard let tPDFOutline = self.tocOutlineView.item(atRow: i) as? CPDFOutline else {
- continue
- }
- let tPage = tPDFOutline.destination.page()
- if (tPage == nil) {
- continue
- }
- let tDict = NSDictionary(object: tPage as Any, forKey: "\(i)" as NSCopying)
- arr.add(tDict)
- }
- let currentPage = self.listView.currentPage()
- var hasExistInOutlineView = false
- for dict in arr {
- guard let _dict = dict as? NSDictionary else {
- continue
- }
- let page = _dict.allValues.last as? CPDFPage
- // NSInteger index = [dict.allKeys.lastObject integerValue];
- let index = Int(_dict.allKeys.last as? String ?? "0") ?? 0
- if let data = page?.isEqual(to: currentPage), data {
- self.tocOutlineView.selectRowIndexes(IndexSet(integer: index), byExtendingSelection: false)
- self.tocOutlineView.scrollRowToVisible(index)
- hasExistInOutlineView = true
- break
- }
- }
- if (!hasExistInOutlineView) {
- self.tocOutlineView.deselectRow(self.tocOutlineView.selectedRow)
- }
- // mwcFlags.updatingOutlineSelection = NO;
- }
-
- func newAddOutlineEntryEditingMode(_ index: Int) {
- self.renamePDFOutline = self.tocOutlineView.item(atRow: self.tocOutlineView.selectedRow) as? CPDFOutline
- let row = self.tocOutlineView.selectedRow
- let viewS = self.tocOutlineView.view(atColumn: 0, row: row, makeIfNecessary: true)
- let targrtTextField = viewS?.subviews.first as? NSTextField
- self.renamePDFOutlineTextField = targrtTextField
- targrtTextField?.delegate = self
- targrtTextField?.isEditable = true
- targrtTextField?.becomeFirstResponder()
- }
-
- func loadUnfoldDate(_ foldType: KMFoldType) {
- self.allFoldNotes.removeAll()
-
- var mutableArray: [CPDFAnnotation] = []
- for note in self.notes {
- if note is CPDFMarkupAnnotation {
- mutableArray.append(note)
- }
- }
- self.canFoldNotes = mutableArray
- self.allFoldNotes = []
- }
-
- func selectedRowIndexes() -> IndexSet {
- var selectedIndexes = self.tocOutlineView.selectedRowIndexes
- let clickedRow = self.tocOutlineView.clickedRow
- if clickedRow != -1 && selectedIndexes.contains(clickedRow) == false {
- var indexes = IndexSet(integer: clickedRow)
- selectedIndexes = indexes
- }
- return selectedIndexes
- }
-
- func addoutline(parent parentOutline: CPDFOutline?, addOutline: CPDFOutline, index: Int, needExpand: Bool) {
- var tempO = addOutline
- if addOutline.label != nil {
- parentOutline?.insertChild(addOutline, at: UInt(index))
- } else {
- let outline = parentOutline?.insertChild(at: UInt(index))
- outline?.label = String(format: "%@ %ld", KMLocalizedString("Page", nil), self.listView.currentPageIndex+1)
- outline?.destination = self.listView.currentDestination
- tempO = outline!
- }
-
- // [[[self.document undoManager] prepareWithInvocationTarget:self] removeOutlineWithParent:parentOutline removeOutline:addOutline index:index needExpand:needExpand];
- self.view.window?.makeFirstResponder(nil)
- Task { @MainActor in
- self.tocOutlineView.reloadData()
-
- if (needExpand) {
- self.tocOutlineView.expandItem(parentOutline)
- }
- let idx = self.tocOutlineView.row(forItem: tempO)
- self.tocOutlineView.selectRowIndexes(IndexSet(integer: idx), byExtendingSelection: false)
-
- self.newAddOutlineEntryEditingMode(index)
- }
- // __block PDFOutline *taddOutline = [addOutline retain];
- // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- // [self.leftSideController.tocOutlineView scrollRowToVisible:[leftSideController.tocOutlineView rowForItem:taddOutline]];
- // [taddOutline release];
- // });
- }
-
- func removeOutline(parent parentOutline: CPDFOutline?, removeOutline: CPDFOutline, index: Int, needExpand: Bool) {
- // [[[self.document undoManager] prepareWithInvocationTarget:self] addoutlineWithParent:parentOutline addOutline:removeOutline index:index needExpand:YES];
- removeOutline.removeFromParent()
- if (needExpand) {
- self.tocOutlineView.expandItem(parentOutline)
- }
- Task { @MainActor in
- self.tocOutlineView.reloadData()
- }
- }
-
- func editOutlineUI(_ editVC: KMOutlineEditViewController) {
- if editVC.pageButton.state == .on {
- let numberString = editVC.outlineTargetPageIndexTextField.stringValue
- let idx = Int(numberString) ?? 1
- let newPage = editVC.pdfView.document.page(at: UInt(idx-1))
- let originalPage = editVC.originalDestination?.page()
- if let data = newPage?.isEqual(to: originalPage), data {
- //新page不存在
- if (newPage == nil) {
- } else {
- let pageSize = newPage?.bounds(for: .cropBox).size ?? .zero
- if let destination = CPDFDestination(page: newPage, at: CGPointMake(pageSize.width, pageSize.height)) {
- self.changePDFOutlineDestination(destination, PDFoutline: editVC.outline)
- }
- }
- }
- } else if editVC.urlButton.state == .on {
- var urlString = editVC.outlineURLTextField.stringValue
- let tLowerUrl = urlString.lowercased()
- if tLowerUrl.hasPrefix("https://") == false && tLowerUrl.hasPrefix("ftp://") == false && tLowerUrl.hasPrefix("http://") == false && urlString.isEmpty == false {
- urlString = "http://\(urlString)"
- }
- if let urlAction = CPDFURLAction(url: urlString) {
- if editVC.originalURLString != editVC.outlineURLTextField.stringValue {
- self.changePDFAction(urlAction, PDFOutline: editVC.outline)
- }
- }
- } else if editVC.mailButton.state == .on {
- var mailString = editVC.mailAddressTextField.stringValue
- let tLowerStr = mailString.lowercased()
- if tLowerStr.hasPrefix("mailto:") == false {
- mailString = "mailto:\(mailString)"
- }
- if var urlAction = CPDFURLAction(url: mailString) {
- if urlAction.url() == nil {
- urlAction = CPDFURLAction(url: "mailto:")
- }
- if mailString != editVC.originalURLString {
- self.changePDFAction(urlAction, PDFOutline: editVC.outline)
- }
- }
- }
-
- if editVC.outlineNameTextView.string == editVC.originalLabel {
- return
- }
- self.renamePDFOutline(editVC.outline, label: editVC.outlineNameTextView.string)
- }
- }
- // MARK: - Undo & Redo
- extension KMLeftSideViewController {
- @objc dynamic func changePDFOutlineDestination(_ destination: CPDFDestination, PDFoutline outline: CPDFOutline) {
- (self.listView.undoManager?.prepare(withInvocationTarget: self) as AnyObject).changePDFOutlineDestination(outline.destination, PDFoutline: outline)
- outline.destination = destination
- }
-
- @objc dynamic func changePDFAction(_ action: CPDFAction, PDFOutline outline: CPDFOutline) {
- (self.listView.undoManager?.prepare(withInvocationTarget: self) as AnyObject).changePDFAction(outline.action, PDFOutline: outline)
- outline.action = action
- }
-
- @objc dynamic func renamePDFOutline(_ outline: CPDFOutline, label: String) {
- if (self.isRenameNoteOutline) {
- if outline is CPDFAnnotation {
- // if([outline isKindOfClass:[PDFAnnotation class]]) {
- // PDFAnnotation *annotation = (PDFAnnotation *)outline;
- // annotation.string = label;
- // [rightSideController.noteOutlineView reloadData];
- // [rightSideController.noteOutlineView selectRowIndexes:[[[NSIndexSet alloc] initWithIndex:[rightSideController.noteOutlineView rowForItem:outline]] autorelease] byExtendingSelection:NO];
- }
- } else {
- (self.listView.undoManager?.prepare(withInvocationTarget: self) as AnyObject).renamePDFOutline(outline, label: outline.label)
- outline.label = label
- self.tocOutlineView.reloadData()
- self.tocOutlineView.km_selectItem(outline, byExtendingSelection: false)
- }
- }
- }
- // MARK: - Menu Actions
- extension KMLeftSideViewController {
- //添加子节点
-
- @objc func outlineContextMenuItemClicked_AddChildEntry(_ sender: AnyObject?) {
- let PDFOutlineArray = NSMutableArray()
- let rowSet = self.selectedRowIndexes()
-
- for idx in rowSet {
- PDFOutlineArray.add(self.tocOutlineView.item(atRow: idx))
- }
-
- let currentPDFline = PDFOutlineArray.lastObject as? CPDFOutline
-
- let addOutLine = CPDFOutline()
- addOutLine.label = String(format: "%@ %ld", KMLocalizedString("Page", nil), "\(self.listView.currentPageIndex + 1)")
- addOutLine.destination = self.listView.currentDestination
-
- self.addoutline(parent: currentPDFline, addOutline: addOutLine, index: Int(currentPDFline?.numberOfChildren ?? 0), needExpand: true)
- }
-
- //添加上一级节点
-
- @objc func outlineContextMenuItemClicked_AddAuntEntry(_ sender: AnyObject?) {
- let PDFOutlineArray = NSMutableArray()
- let rowSet = self.selectedRowIndexes()
-
- for idx in rowSet {
- PDFOutlineArray.add(self.tocOutlineView.item(atRow: idx))
- }
- let clickedOutline = PDFOutlineArray.lastObject as? CPDFOutline
-
- let fatherOutLine = clickedOutline?.parent
- let grandfatherOutLine = fatherOutLine?.parent
- if (grandfatherOutLine != nil) {
- let addOutLine = CPDFOutline()
- addOutLine.label = String(format: "%@ %ld", KMLocalizedString("Page", nil), "\(self.listView.currentPageIndex + 1)")
- addOutLine.destination = self.listView.currentDestination
- self.addoutline(parent: grandfatherOutLine, addOutline: addOutLine, index: Int(fatherOutLine?.numberOfChildren ?? 0) + 1, needExpand: false)
- }
- }
-
- //移除节点
-
- @objc func outlineContextMenuItemClicked_RemoveEntry(_ sender: AnyObject?) {
- let set = self.selectedRowIndexes()
- var selectedPDFOutlineArr = NSMutableArray()
-
- for idx in set {
- selectedPDFOutlineArr.add(self.tocOutlineView.item(atRow: idx))
- }
-
- //整体移除多选
- for tOutline in selectedPDFOutlineArr {
- guard let outL = tOutline as? CPDFOutline else {
- continue
- }
- self.removeOutline(parent: outL.parent , removeOutline: outL, index: Int(outL.index), needExpand: false)
- }
- }
-
- //重置目的
-
- @objc func outlineContextMenuItemClicked_SetDestination(_ sender: AnyObject?) {
- guard let setPDFOutline = self.tocOutlineView.item(atRow: self.tocOutlineView.clickedRow) as? CPDFOutline else {
- return
- }
- Task {
- let modalRes = await KMAlertTool.runModel(style: .informational, message: KMLocalizedString("Are you sure you want to set the destination as the current location?", nil), buttons: [KMLocalizedString("Yes", nil), KMLocalizedString("No", nil)])
- if (modalRes == .alertFirstButtonReturn) {
- self.changePDFOutlineDestination(self.listView.currentDestination, PDFoutline: setPDFOutline)
- self.tocOutlineView.reloadData()
- let idx = self.tocOutlineView.row(forItem: setPDFOutline)
- self.tocOutlineView.selectRowIndexes(IndexSet(integer: idx), byExtendingSelection: false)
- }
- }
- }
-
- //弹出菜单
-
- @objc func outlineContextMenuItemClicked_Edit(_ sender: AnyObject?) {
- let popover = NSPopover()
- popover.delegate = self
- let targetOutline: CPDFOutline? = self.tocOutlineView.km.clickedItem()
- let outlineEditViewController = KMOutlineEditViewController(outline: targetOutline, document: self.listView)
- let cell = self.tocOutlineView.rowView(atRow: self.tocOutlineView.clickedRow, makeIfNecessary: true)
- popover.contentViewController = outlineEditViewController
- popover.animates = true
- popover.behavior = .transient
- popover.show(relativeTo: cell?.bounds ?? .zero, of: cell!, preferredEdge: .minX)
- }
- }
|