Browse Source

【书签】数据保存,右击菜单

lizhe 1 year ago
parent
commit
e8e26bfae2

+ 22 - 0
PDF Office/PDF Master/Class/Common/Category/View/NSMenu+KMExtension.swift

@@ -67,6 +67,18 @@ extension NSMenu {
     func addItem_r(title: String, imageNamed: String?, action: Selector?, target: AnyObject?, tag: Int) -> NSMenuItem? {
         return self.insertItem(title: title, imageNamed: imageNamed, action: action, target: target, tag: tag, atIndex: self.numberOfItems)
     }
+    
+    func insertItemWithSubmenuAndTitle(_ aString: String, atIndex anIndex: Int) -> NSMenuItem {
+        let item = NSMenuItem(title: aString, action: nil, keyEquivalent: "")
+        let submenu = NSMenu(title: aString)
+        item.submenu = submenu
+        self.insertItem(item, at: anIndex)
+        return item
+    }
+
+    func addItemWithSubmenuAndTitle(_ aString: String) -> NSMenuItem {
+        return insertItemWithSubmenuAndTitle(aString, atIndex: numberOfItems)
+    }
 }
 
 /*
@@ -119,6 +131,16 @@ extension NSMenu {
             self.image = newImage
         }
     }
+    
+    static func menuItemWithSubmenuAndTitle(_ aString: String) -> NSMenuItem {
+        return NSMenuItem(title: aString, action: nil, keyEquivalent: "")
+    }
+    
+    convenience init(submenuAndTitle aString: String) {
+        self.init(title: aString, action: nil, keyEquivalent: "")
+        let menu = NSMenu(title: aString)
+        self.submenu = menu
+    }
 }
 
 /*

+ 1 - 0
PDF Office/PDF Master/Class/Document/KMMainDocument.swift

@@ -759,6 +759,7 @@ typealias KMMainDocumentCloudUploadHanddler = (@escaping(Bool, String)->()) -> (
             if let bookmark = bookmark {
                 folder?.children.append(bookmark)
             }
+            KMBookmarkManager.manager.saveData()
         }
     }
     

+ 438 - 421
PDF Office/PDF Master/Class/PDFTools/KMBookmark/Controller/KMBookmarkController.swift

@@ -49,12 +49,8 @@ class KMBookmarkController: NSWindowController {
     override func windowDidLoad() {
         super.windowDidLoad()
         setupToolbar()
-        
-//        outlineView.delegate = self
-//        outlineView.dataSource = self
-//        outlineView.registerForDraggedTypes([kPasteboardTypeBookmarkRows, .fileURL, .string])
-//        bookmarkOutlineView.outlineView.doubleAction = #selector(doubleClickBookmark(_:))
-        
+        bookmarkOutlineView.outlineView.menu = NSMenu()
+        bookmarkOutlineView.outlineView.menu?.delegate = self
         
         bookmarkOutlineView.data = self.bookmarkRoot
         bookmarkOutlineView.doubleClickAction = { [unowned self] view in
@@ -189,12 +185,14 @@ class KMBookmarkController: NSWindowController {
     }
 
     
-    func deleteBookmarks(bookmarks: [KMBookmark]) {
+    @objc func deleteBookmarks(bookmarks: [KMBookmark]) {
         for item in minimumCoverForBookmarks(bookmarks).reversed() {
             guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue }
             parent.removeObjectFromChildren(index: itemIndex)
         }
         bookmarkOutlineView.reloadData()
+        
+        KMBookmarkManager.manager.saveData()
     }
     
     
@@ -269,119 +267,38 @@ class KMBookmarkController: NSWindowController {
 //        statusBar.toggle(below: outlineView.enclosingScrollView, animate: sender != nil)
 //    }
 //
-//    func clickedBookmarks() -> [Any]? {
-//        let row = outlineView.clickedRow
-//        guard row != -1 else { return nil }
-//        var indexes = outlineView.selectedRowIndexes
-//        if !indexes.contains(row) {
-//            indexes = IndexSet(integer: row)
-//        }
-//        return indexes.compactMap { outlineView.item(atRow: $0) }
-//    }
-//
-//    @IBAction func deleteBookmarks(_ sender: Any) {
-//        guard let items = clickedBookmarks() as? [KMBookmark] else { return }
-//        for item in items.reversed() {
-//            if let parent = item.parent, let itemIndex = parent.children.index(of: item) {
-//                parent.removeObject(fromChildrenAtIndex: itemIndex)
-//            }
-//        }
-//    }
 //
-//    @IBAction func openBookmarks(_ sender: Any) {
-//        guard let items = clickedBookmarks() as? [KMBookmark] else { return }
-//        for item in items.reversed() {
-//            item.open()
-//        }
-//    }
-//
-//    @IBAction func previewBookmarks(_ sender: Any) {
-//        if QLPreviewPanel.sharedPreviewPanelExists() && QLPreviewPanel.shared().isVisible {
-//            QLPreviewPanel.shared().orderOut(nil)
-//        } else if let row = outlineView.clickedRow {
-//            outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
-//            QLPreviewPanel.shared().makeKeyAndOrderFront(nil)
-//        }
-//    }
-//
-//    
-//    // MARK: - NSMenu delegate methods
+    @IBAction func deleteMenuBookmarks(_ sender: Any) {
+        guard let items = clickedBookmarks() as? [KMBookmark] else { return }
+        self.deleteBookmarks(bookmarks: items)
+    }
+
+    @IBAction func openBookmarks(_ sender: Any) {
+        guard let items = clickedBookmarks() as? [KMBookmark] else { return }
+        for item in items.reversed() {
+            item.open()
+        }
+    }
+
+    @IBAction func previewBookmarks(_ sender: Any) {
+        if QLPreviewPanel.sharedPreviewPanelExists() && QLPreviewPanel.shared().isVisible {
+            QLPreviewPanel.shared().orderOut(nil)
+        } else {
+            let row = bookmarkOutlineView.outlineView.clickedRow
+            if row > 0 {
+                bookmarkOutlineView.outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
+                QLPreviewPanel.shared().makeKeyAndOrderFront(nil)
+            }
+        }
+    }
 
-//    func addItemForBookmark(_ bookmark: KMBookmark, toMenu menu: NSMenu, isFolder: Bool, isAlternate: Bool) {
-//        var item: NSMenuItem?
-//        if isFolder {
-//            item = menu.addItem(withSubmenuAndTitle: bookmark.label)
-//            item?.submenu?.delegate = self
-//        } else {
-//            item = menu.addItem(withTitle: bookmark.label, action: #selector(openBookmark(_:)), target: self)
-//        }
-//        item?.representedObject = bookmark
-//        if isAlternate {
-//            item?.keyEquivalentModifierMask = .alternate
-//            item?.isAlternate = true
-//            item?.setImageAndSize(bookmark.alternateIcon)
-//        } else {
-//            item?.setImageAndSize(bookmark.icon)
-//        }
-//    }
-//
-//    func menuNeedsUpdate(_ menu: NSMenu) {
-//        if menu == outlineView.menu {
-//            let row = outlineView.clickedRow
-//            menu.removeAllItems()
-//            if row != -1 {
-//                menu.addItem(withTitle: NSLocalizedString("Remove", comment: "Menu item title"), action: #selector(deleteBookmarks(_:)), target: self)
-//                menu.addItem(withTitle: NSLocalizedString("Open", comment: "Menu item title"), action: #selector(openBookmarks(_:)), target: self)
-//                menu.addItem(withTitle: NSLocalizedString("Quick Look", comment: "Menu item title"), action: #selector(previewBookmarks(_:)), target: self)
-//                menu.addItem(.separator())
-//            }
-//            menu.addItem(withTitle: NSLocalizedString("New Folder", comment: "Menu item title"), action: #selector(insertBookmarkFolder(_:)), target: self)
-//            menu.addItem(withTitle: NSLocalizedString("New Separator", comment: "Menu item title"), action: #selector(insertBookmarkSeparator(_:)), target: self)
-//        } else {
-//            guard let supermenu = menu.supermenu, let idx = supermenu.indexOfItem(withSubmenu: menu), let bm = (supermenu == NSApp.mainMenu) ? bookmarkRoot : supermenu.item(at: idx)?.representedObject as? KMBookmark else { return }
-//            
-//            let bookmarks = bm.children
-//            var i = menu.numberOfItems
-//            
-//            while i > 0 {
-//                if let menuItem = menu.item(at: i - 1), menuItem.isSeparatorItem || menuItem.representedObject != nil {
-//                    menu.removeItem(menuItem)
-//                }
-//                i -= 1
-//            }
-//            
-//            if supermenu == NSApp.mainMenu, let previousSession = previousSession {
-//                menu.addItem(.separator())
-//                addItemForBookmark(previousSession, toMenu: menu, isFolder: false, isAlternate: false)
-//                addItemForBookmark(previousSession, toMenu: menu, isFolder: true, isAlternate: true)
-//            }
-//            
-//            if menu.numberOfItems > 0, bookmarks.count > 0 {
-//                menu.addItem(.separator())
-//            }
-//            
-//            for bm in bookmarks {
-//                switch bm.bookmarkType {
-//                case .folder:
-//                    addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: false)
-//                    addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: true)
-//                case .session:
-//                    addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false)
-//                    addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: true)
-//                case .separator:
-//                    menu.addItem(.separator())
-//                default:
-//                    addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false)
-//                }
-//            }
-//        }
-//    }
-//
 //    // avoid rebuilding the bookmarks menu on every key event
-//    func menuHasKeyEquivalent(_ menu: NSMenu, for event: NSEvent, target: AutoreleasingUnsafeMutablePointer<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool { false }
-//    
-//    // MARK: - Toolbar
-//
+    func menuHasKeyEquivalent(_ menu: NSMenu, for event: NSEvent, target: AutoreleasingUnsafeMutablePointer<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool { 
+        return false
+    }
+
+    // MARK: - Toolbar
+
     func setupToolbar() {
         // Create a new toolbar instance, and attach it to our document window
         let toolbar = NSToolbar(identifier: kBookmarksToolbarIdentifier)
@@ -508,315 +425,315 @@ class KMBookmarkController: NSWindowController {
 
 }
 
-extension KMBookmarkController: NSOutlineViewDelegate, NSOutlineViewDataSource {
-    //MARK: NSOutlineViewDataSource
-    
-    func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] {
-        var lastBm: KMBookmark?
-        var minimalCover = [KMBookmark]()
-
-        for bm in items {
-            if !(bm.isDescendant(of: lastBm)) {
-                minimalCover.append(bm)
-                lastBm = bm
-            }
-        }
-        return minimalCover
-    }
-    
-    func outlineView(_ ov: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
-        let bookmark = item as? KMBookmark ?? bookmarkRoot
-        return bookmark.bookmarkType == .folder ? bookmark.children.count : 0
-    }
-
-    func outlineView(_ ov: NSOutlineView, isItemExpandable item: Any) -> Bool {
-        let bookmark = item as! KMBookmark
-        return bookmark.bookmarkType == .folder
-    }
-
-    func outlineView(_ ov: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
-        let bookmark = (item as? KMBookmark) ?? bookmarkRoot
-        return bookmark.objectOfChidren(index: index)
-    }
-
-    func outlineView(_ ov: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
-        guard let column = tableColumn else { return nil }
-        guard let bm = item as? KMBookmark else { return nil }
-        let tcID = column.identifier
-        
-        switch tcID {
-        case kLabelIdentifier:
-            return [kTextWithIconStringKey: bm.label, kTextWithIconImageKey: bm.icon]
-        case kFileIdentifier:
-            if bm.bookmarkType == .folder || bm.bookmarkType == .session {
-                let count = bm.children.count
-                return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
-            } else {
-                return bm.fileURL?.path ?? ""
-            }
-        case kPageIdentifier:
-            return bm.pageNumber
-        default:
-            return nil
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, byItem item: Any?) {
-        guard let column = tableColumn else { return }
-        guard let bm = item as? KMBookmark else { return }
-        let tcID = column.identifier
-        
-        switch tcID {
-        case kLabelIdentifier:
-            if let newLabel = (object as? [String: Any])?[kTextWithIconStringKey] as? String, newLabel != bm.label {
-                bm.label = newLabel
-            }
-        case kPageIdentifier:
-            if let newPageNumber = object as? Int, newPageNumber != bm.pageNumber.intValue {
-                bm.pageNumber = newPageNumber as NSNumber
-            }
-        default:
-            break
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, writeItems items: [Any], to pboard: NSPasteboard) -> Bool {
-        draggedBookmarks = minimumCoverForBookmarks(items as! [KMBookmark])
-        pboard.clearContents()
-        pboard.setData(Data(), forType: kPasteboardTypeBookmarkRows)
-        return true
-    }
-
-    func outlineView(_ ov: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
-        guard index != NSOutlineViewDropOnItemIndex else { return [] }
-        
-        let pboard = info.draggingPasteboard
-
-        if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
-            return .move
-        } else if NSURL.canReadFileURL(from: pboard) {
-            return .every
-        }
-        return []
-    }
-
-    func outlineView(_ ov: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
-        let pboard = info.draggingPasteboard
-
-        if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
-            var movedBookmarks = [KMBookmark]()
-            var indexes = IndexSet()
-            var insertionIndex = index
-
-            let targetItem = item as? KMBookmark ?? bookmarkRoot
-
-            for bookmark in draggedBookmarks {
-                guard let parent = bookmark.parent else { continue }
-                guard let bookmarkIndex = parent.children.firstIndex(of: bookmark) else { continue }
-
-                if targetItem == parent {
-                    if insertionIndex > bookmarkIndex {
-                        insertionIndex -= 1
-                    }
-                    if insertionIndex == bookmarkIndex {
-                        continue
-                    }
-                }
-                parent.removeObjectFromChildren(index: bookmarkIndex)
-                targetItem.insert(child: bookmark, atIndex: insertionIndex)
-                movedBookmarks.append(bookmark)
-                insertionIndex += 1
-            }
-
-            for bookmark in movedBookmarks {
-                let row = ov.row(forItem: bookmark)
-                if row != -1 {
-                    indexes.insert(row)
-                }
-            }
-            if !indexes.isEmpty {
-                ov.selectRowIndexes(indexes, byExtendingSelection: false)
-            }
-            return true
-        } else {
-            let urls = NSURL.readFileURLs(from: pboard)
-
-            let newBookmarks = KMBookmark.bookmarks(urls: urls)
-            if !newBookmarks.isEmpty {
-                var indexes = IndexSet(integersIn: index..<(index + newBookmarks.count))
-                (item as? KMBookmark ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
-                if (item as? KMBookmark ?? bookmarkRoot) === bookmarkRoot || ov.isItemExpanded(item) {
-                    if (item as? KMBookmark ?? bookmarkRoot) !== bookmarkRoot {
-                        indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
-                    }
-                    ov.selectRowIndexes(indexes, byExtendingSelection: false)
-                }
-                return true
-            }
-            return false
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, dragEndedWith operation: NSDragOperation) {
-        draggedBookmarks.removeAll()
-    }
-
-
-    //    MARK: NSOutlineViewDelegate
-
-    func outlineView(_ ov: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> Any? {
-        if tableColumn == nil {
-            return (item as? KMBookmark)?.bookmarkType == .separator ? KMSeparatorCell() : nil
-        }
-        return tableColumn?.dataCell(forRow: ov.row(forItem: item))
-    }
-    
-    func outlineView(_ ov: NSOutlineView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, item: Any) {
-        guard let column = tableColumn else { return }
-        guard let cell = cell as? NSCell else { return }
-
-        if column.identifier == kFileIdentifier {
-            if let bm = item as? KMBookmark {
-//                if bm.bookmarkType == .folder || bm.bookmarkType == .session {
-//                    cell.textColor = .disabledControlTextColor
-//                } else {
-//                    cell.textColor = .controlTextColor
-//                }
-            }
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, shouldEdit tableColumn: NSTableColumn?, item: Any) -> Bool {
-        guard let column = tableColumn else { return false }
-        guard let bm = item as? KMBookmark else { return false }
-
-        let tcID = column.identifier
-        switch tcID {
-        case kLabelIdentifier:
-            return bm.bookmarkType != .separator
-        case kPageIdentifier:
-            return bm.pageIndex != NSNotFound
-        default:
-            return false
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, toolTipFor cell: NSCell, rect: UnsafeMutablePointer<NSRect>, tableColumn tc: NSTableColumn?, item: Any, mouseLocation: NSPoint) -> String {
-        guard let column = tc else { return "" }
-        guard let bm = item as? KMBookmark else { return "" }
-
-        let tcID = column.identifier
-        switch tcID {
-        case kLabelIdentifier:
-            return bm.label
-        case kFileIdentifier:
-            if bm.bookmarkType == .session {
-                return ""
-//                return bm.children.map { $0.path ?? "" }.joined(separator: "\n")
-            } else if bm.bookmarkType == .folder {
-                let count = bm.children.count
-                return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
-            } else {
-                return bm.fileURL?.path ?? ""
-            }
-        case kPageIdentifier:
-            return bm.pageNumber.stringValue
-        default:
-            return ""
-        }
-    }
-
-    func outlineViewSelectionDidChange(_ notification: Notification) {
-        updateStatus()
-        if QLPreviewPanel.sharedPreviewPanelExists(), let previewPanel = QLPreviewPanel.shared(), previewPanel.isVisible, previewPanel.dataSource === self {
-            previewPanel.reloadData()
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, deleteItems items: [Any]) {
-        for item in minimumCoverForBookmarks(items as! [KMBookmark]).reversed() {
-            guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue }
-            parent.removeObjectFromChildren(index: itemIndex)
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, canDeleteItems items: [Any]) -> Bool {
-        return !items.isEmpty
-    }
-
-    func outlineView(_ ov: NSOutlineView, copyItems items: [Any]) {
-        var urls = [URL]()
-        addBookmarkURLsToArray(minimumCoverForBookmarks(items as! [KMBookmark]), &urls)
-        if !urls.isEmpty {
-            let pboard = NSPasteboard.general
-            pboard.clearContents()
-            pboard.writeObjects(urls as [NSPasteboardWriting])
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, canCopyItems items: [Any]) -> Bool {
-        return !items.isEmpty
-    }
-
-    func outlineView(_ ov: NSOutlineView, pasteFromPasteboard pboard: NSPasteboard) {
-        let urls = NSURL.readFileURLs(from: pboard)
-
-        let newBookmarks = KMBookmark.bookmarks(urls: urls)
-        if !newBookmarks.isEmpty {
-            var item: KMBookmark?
-            var anIndex = 0
-            getInsertionFolder(&item, childIndex: &anIndex)
-            var indexes = IndexSet(integersIn: anIndex..<(anIndex + newBookmarks.count))
-            (item ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
-            if item === bookmarkRoot || ov.isItemExpanded(item) {
-                if item !== bookmarkRoot {
-                    indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
-                }
-                ov.selectRowIndexes(indexes, byExtendingSelection: false)
-            }
-        }
-    }
-
-    func outlineView(_ ov: NSOutlineView, canPasteFromPasteboard pboard: NSPasteboard) -> Bool {
-        return NSURL.canReadFileURL(from: pboard)
-    }
-
-    func outlineView(_ ov: NSOutlineView, typeSelectHelperSelectionStrings typeSelectHelper: SKTypeSelectHelper) -> [String] {
-        let count = ov.numberOfRows
-        var labels = [String]()
-        for i in 0..<count {
-            if let label = ov.item(atRow: i) {
-                labels.append(label as! String)
-            }
-        }
-        return labels
-    }
-
-//    func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String) {
-//        statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("No match: \"%@\"", comment: "Status message"), searchString))
+//extension KMBookmarkController: NSOutlineViewDelegate, NSOutlineViewDataSource {
+//    //MARK: NSOutlineViewDataSource
+//    
+//    func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] {
+//        var lastBm: KMBookmark?
+//        var minimalCover = [KMBookmark]()
+//
+//        for bm in items {
+//            if !(bm.isDescendant(of: lastBm)) {
+//                minimalCover.append(bm)
+//                lastBm = bm
+//            }
+//        }
+//        return minimalCover
+//    }
+//    
+//    func outlineView(_ ov: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
+//        let bookmark = item as? KMBookmark ?? bookmarkRoot
+//        return bookmark.bookmarkType == .folder ? bookmark.children.count : 0
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, isItemExpandable item: Any) -> Bool {
+//        let bookmark = item as! KMBookmark
+//        return bookmark.bookmarkType == .folder
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
+//        let bookmark = (item as? KMBookmark) ?? bookmarkRoot
+//        return bookmark.objectOfChidren(index: index)
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
+//        guard let column = tableColumn else { return nil }
+//        guard let bm = item as? KMBookmark else { return nil }
+//        let tcID = column.identifier
+//        
+//        switch tcID {
+//        case kLabelIdentifier:
+//            return [kTextWithIconStringKey: bm.label, kTextWithIconImageKey: bm.icon]
+//        case kFileIdentifier:
+//            if bm.bookmarkType == .folder || bm.bookmarkType == .session {
+//                let count = bm.children.count
+//                return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
+//            } else {
+//                return bm.fileURL?.path ?? ""
+//            }
+//        case kPageIdentifier:
+//            return bm.pageNumber
+//        default:
+//            return nil
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, byItem item: Any?) {
+//        guard let column = tableColumn else { return }
+//        guard let bm = item as? KMBookmark else { return }
+//        let tcID = column.identifier
+//        
+//        switch tcID {
+//        case kLabelIdentifier:
+//            if let newLabel = (object as? [String: Any])?[kTextWithIconStringKey] as? String, newLabel != bm.label {
+//                bm.label = newLabel
+//            }
+//        case kPageIdentifier:
+//            if let newPageNumber = object as? Int, newPageNumber != bm.pageNumber.intValue {
+//                bm.pageNumber = newPageNumber as NSNumber
+//            }
+//        default:
+//            break
+//        }
 //    }
 //
-//    func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String?) {
-//        if let searchString = searchString {
-//            statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("Finding: \"%@\"", comment: "Status message"), searchString))
+//    func outlineView(_ ov: NSOutlineView, writeItems items: [Any], to pboard: NSPasteboard) -> Bool {
+//        draggedBookmarks = minimumCoverForBookmarks(items as! [KMBookmark])
+//        pboard.clearContents()
+//        pboard.setData(Data(), forType: kPasteboardTypeBookmarkRows)
+//        return true
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
+//        guard index != NSOutlineViewDropOnItemIndex else { return [] }
+//        
+//        let pboard = info.draggingPasteboard
+//
+//        if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
+//            return .move
+//        } else if NSURL.canReadFileURL(from: pboard) {
+//            return .every
+//        }
+//        return []
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
+//        let pboard = info.draggingPasteboard
+//
+//        if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
+//            var movedBookmarks = [KMBookmark]()
+//            var indexes = IndexSet()
+//            var insertionIndex = index
+//
+//            let targetItem = item as? KMBookmark ?? bookmarkRoot
+//
+//            for bookmark in draggedBookmarks {
+//                guard let parent = bookmark.parent else { continue }
+//                guard let bookmarkIndex = parent.children.firstIndex(of: bookmark) else { continue }
+//
+//                if targetItem == parent {
+//                    if insertionIndex > bookmarkIndex {
+//                        insertionIndex -= 1
+//                    }
+//                    if insertionIndex == bookmarkIndex {
+//                        continue
+//                    }
+//                }
+//                parent.removeObjectFromChildren(index: bookmarkIndex)
+//                targetItem.insert(child: bookmark, atIndex: insertionIndex)
+//                movedBookmarks.append(bookmark)
+//                insertionIndex += 1
+//            }
+//
+//            for bookmark in movedBookmarks {
+//                let row = ov.row(forItem: bookmark)
+//                if row != -1 {
+//                    indexes.insert(row)
+//                }
+//            }
+//            if !indexes.isEmpty {
+//                ov.selectRowIndexes(indexes, byExtendingSelection: false)
+//            }
+//            return true
 //        } else {
-//            updateStatus()
+//            let urls = NSURL.readFileURLs(from: pboard)
+//
+//            let newBookmarks = KMBookmark.bookmarks(urls: urls)
+//            if !newBookmarks.isEmpty {
+//                var indexes = IndexSet(integersIn: index..<(index + newBookmarks.count))
+//                (item as? KMBookmark ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
+//                if (item as? KMBookmark ?? bookmarkRoot) === bookmarkRoot || ov.isItemExpanded(item) {
+//                    if (item as? KMBookmark ?? bookmarkRoot) !== bookmarkRoot {
+//                        indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
+//                    }
+//                    ov.selectRowIndexes(indexes, byExtendingSelection: false)
+//                }
+//                return true
+//            }
+//            return false
 //        }
 //    }
-    
-    func addBookmarkURLsToArray(_ items: [KMBookmark], _ array: inout [URL]) {
-        for bm in items {
-            if bm.bookmarkType == .bookmark {
-                if let url = bm.fileURL {
-                    array.append(url)
-                }
-            } else if bm.bookmarkType != .separator {
-                addBookmarkURLsToArray(bm.children, &array)
-            }
-        }
-    }
-    
-}
+//
+//    func outlineView(_ ov: NSOutlineView, dragEndedWith operation: NSDragOperation) {
+//        draggedBookmarks.removeAll()
+//    }
+//
+//
+//    //    MARK: NSOutlineViewDelegate
+//
+//    func outlineView(_ ov: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> Any? {
+//        if tableColumn == nil {
+//            return (item as? KMBookmark)?.bookmarkType == .separator ? KMSeparatorCell() : nil
+//        }
+//        return tableColumn?.dataCell(forRow: ov.row(forItem: item))
+//    }
+//    
+//    func outlineView(_ ov: NSOutlineView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, item: Any) {
+//        guard let column = tableColumn else { return }
+//        guard let cell = cell as? NSCell else { return }
+//
+//        if column.identifier == kFileIdentifier {
+//            if let bm = item as? KMBookmark {
+////                if bm.bookmarkType == .folder || bm.bookmarkType == .session {
+////                    cell.textColor = .disabledControlTextColor
+////                } else {
+////                    cell.textColor = .controlTextColor
+////                }
+//            }
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, shouldEdit tableColumn: NSTableColumn?, item: Any) -> Bool {
+//        guard let column = tableColumn else { return false }
+//        guard let bm = item as? KMBookmark else { return false }
+//
+//        let tcID = column.identifier
+//        switch tcID {
+//        case kLabelIdentifier:
+//            return bm.bookmarkType != .separator
+//        case kPageIdentifier:
+//            return bm.pageIndex != NSNotFound
+//        default:
+//            return false
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, toolTipFor cell: NSCell, rect: UnsafeMutablePointer<NSRect>, tableColumn tc: NSTableColumn?, item: Any, mouseLocation: NSPoint) -> String {
+//        guard let column = tc else { return "" }
+//        guard let bm = item as? KMBookmark else { return "" }
+//
+//        let tcID = column.identifier
+//        switch tcID {
+//        case kLabelIdentifier:
+//            return bm.label
+//        case kFileIdentifier:
+//            if bm.bookmarkType == .session {
+//                return ""
+////                return bm.children.map { $0.path ?? "" }.joined(separator: "\n")
+//            } else if bm.bookmarkType == .folder {
+//                let count = bm.children.count
+//                return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
+//            } else {
+//                return bm.fileURL?.path ?? ""
+//            }
+//        case kPageIdentifier:
+//            return bm.pageNumber.stringValue
+//        default:
+//            return ""
+//        }
+//    }
+//
+//    func outlineViewSelectionDidChange(_ notification: Notification) {
+//        updateStatus()
+//        if QLPreviewPanel.sharedPreviewPanelExists(), let previewPanel = QLPreviewPanel.shared(), previewPanel.isVisible, previewPanel.dataSource === self {
+//            previewPanel.reloadData()
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, deleteItems items: [Any]) {
+//        for item in minimumCoverForBookmarks(items as! [KMBookmark]).reversed() {
+//            guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue }
+//            parent.removeObjectFromChildren(index: itemIndex)
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, canDeleteItems items: [Any]) -> Bool {
+//        return !items.isEmpty
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, copyItems items: [Any]) {
+//        var urls = [URL]()
+//        addBookmarkURLsToArray(minimumCoverForBookmarks(items as! [KMBookmark]), &urls)
+//        if !urls.isEmpty {
+//            let pboard = NSPasteboard.general
+//            pboard.clearContents()
+//            pboard.writeObjects(urls as [NSPasteboardWriting])
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, canCopyItems items: [Any]) -> Bool {
+//        return !items.isEmpty
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, pasteFromPasteboard pboard: NSPasteboard) {
+//        let urls = NSURL.readFileURLs(from: pboard)
+//
+//        let newBookmarks = KMBookmark.bookmarks(urls: urls)
+//        if !newBookmarks.isEmpty {
+//            var item: KMBookmark?
+//            var anIndex = 0
+//            getInsertionFolder(&item, childIndex: &anIndex)
+//            var indexes = IndexSet(integersIn: anIndex..<(anIndex + newBookmarks.count))
+//            (item ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
+//            if item === bookmarkRoot || ov.isItemExpanded(item) {
+//                if item !== bookmarkRoot {
+//                    indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
+//                }
+//                ov.selectRowIndexes(indexes, byExtendingSelection: false)
+//            }
+//        }
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, canPasteFromPasteboard pboard: NSPasteboard) -> Bool {
+//        return NSURL.canReadFileURL(from: pboard)
+//    }
+//
+//    func outlineView(_ ov: NSOutlineView, typeSelectHelperSelectionStrings typeSelectHelper: SKTypeSelectHelper) -> [String] {
+//        let count = ov.numberOfRows
+//        var labels = [String]()
+//        for i in 0..<count {
+//            if let label = ov.item(atRow: i) {
+//                labels.append(label as! String)
+//            }
+//        }
+//        return labels
+//    }
+//
+////    func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String) {
+////        statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("No match: \"%@\"", comment: "Status message"), searchString))
+////    }
+////
+////    func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String?) {
+////        if let searchString = searchString {
+////            statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("Finding: \"%@\"", comment: "Status message"), searchString))
+////        } else {
+////            updateStatus()
+////        }
+////    }
+//    
+//    func addBookmarkURLsToArray(_ items: [KMBookmark], _ array: inout [URL]) {
+//        for bm in items {
+//            if bm.bookmarkType == .bookmark {
+//                if let url = bm.fileURL {
+//                    array.append(url)
+//                }
+//            } else if bm.bookmarkType != .separator {
+//                addBookmarkURLsToArray(bm.children, &array)
+//            }
+//        }
+//    }
+//    
+//}
 
 extension KMBookmarkController: NSToolbarDelegate, NSToolbarItemValidation {
     func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
@@ -869,6 +786,81 @@ extension KMBookmarkController: NSMenuDelegate, NSMenuItemValidation {
 //        }
         return true
     }
+    
+    // MARK: - NSMenu delegate methods
+    func addItemForBookmark(_ bookmark: KMBookmark, toMenu menu: NSMenu, isFolder: Bool, isAlternate: Bool) {
+        var item: NSMenuItem?
+        if isFolder {
+            item = menu.addItemWithSubmenuAndTitle(bookmark.label)
+            item?.submenu?.delegate = self
+        } else {
+            item = menu.addItem(withTitle: bookmark.label, action: #selector(openBookmark(_:)), target: self)
+        }
+        item?.representedObject = bookmark
+        if isAlternate {
+            item?.keyEquivalentModifierMask = NSEvent.ModifierFlags.option
+            item?.isAlternate = true
+            item?.setImageAndSize(bookmark.alternateIcon)
+        } else {
+            item?.setImageAndSize(bookmark.icon)
+        }
+    }
+//
+    func menuNeedsUpdate(_ menu: NSMenu) {
+        if menu == bookmarkOutlineView.outlineView.menu {
+            let row = bookmarkOutlineView.outlineView.clickedRow
+            menu.removeAllItems()
+            if row != -1 {
+                menu.addItem(withTitle: NSLocalizedString("Remove", comment: "Menu item title"), action: #selector(deleteMenuBookmarks), target: self)
+                menu.addItem(withTitle: NSLocalizedString("Open", comment: "Menu item title"), action: #selector(openBookmarks), target: self)
+                menu.addItem(withTitle: NSLocalizedString("Quick Look", comment: "Menu item title"), action: #selector(previewBookmarks), target: self)
+                menu.addItem(.separator())
+            }
+            menu.addItem(withTitle: NSLocalizedString("New Folder", comment: "Menu item title"), action: #selector(insertBookmarkFolder), target: self)
+            menu.addItem(withTitle: NSLocalizedString("New Separator", comment: "Menu item title"), action: #selector(insertBookmarkSeparator), target: self)
+        } else {
+           let supermenu = menu.supermenu
+            if supermenu != nil {
+                let idx = supermenu!.indexOfItem(withSubmenu: menu)
+                let bm = (supermenu == NSApp.mainMenu) ? bookmarkRoot : supermenu!.item(at: idx)?.representedObject as? KMBookmark
+                
+                let bookmarks = bm!.children
+                var i = menu.numberOfItems
+                
+                while i > 0 {
+                    if let menuItem = menu.item(at: i - 1), menuItem.isSeparatorItem || menuItem.representedObject != nil {
+                        menu.removeItem(menuItem)
+                    }
+                    i -= 1
+                }
+                
+                if supermenu == NSApp.mainMenu {
+                    menu.addItem(.separator())
+    //                addItemForBookmark(previousSession, toMenu: menu, isFolder: false, isAlternate: false)
+    //                addItemForBookmark(previousSession, toMenu: menu, isFolder: true, isAlternate: true)
+                }
+                
+                if menu.numberOfItems > 0, bookmarks.count > 0 {
+                    menu.addItem(.separator())
+                }
+                
+                for bm in bookmarks {
+                    switch bm.bookmarkType {
+                    case .folder:
+                        addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: false)
+                        addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: true)
+                    case .session:
+                        addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false)
+                        addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: true)
+                    case .separator:
+                        menu.addItem(.separator())
+                    default:
+                        addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false)
+                    }
+                }
+            }
+        }
+    }
 }
 
 extension NSURL {
@@ -891,3 +883,28 @@ extension NSURL {
         return []
     }
 }
+
+extension KMBookmarkController {
+    func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] {
+        var lastBm: KMBookmark?
+        var minimalCover = [KMBookmark]()
+
+        for bm in items {
+            if !(bm.isDescendant(of: lastBm)) {
+                minimalCover.append(bm)
+                lastBm = bm
+            }
+        }
+        return minimalCover
+    }
+    
+    func clickedBookmarks() -> [Any]? {
+        let row = bookmarkOutlineView.outlineView.clickedRow
+        guard row != -1 else { return nil }
+        var indexes = bookmarkOutlineView.outlineView.selectedRowIndexes
+        if !indexes.contains(row) {
+            indexes = IndexSet(integer: row)
+        }
+        return indexes.compactMap { bookmarkOutlineView.outlineView.item(atRow: $0) }
+    }
+}

+ 2 - 3
PDF Office/PDF Master/Class/PDFTools/KMBookmark/Manager/KMBookmarkManager.swift

@@ -35,12 +35,11 @@ class KMBookmarkManager {
     
     func saveData() {
         let bookmarksDictionary: [String: Any] = [
-            "bookmarks": (self.rootBookmark.children as NSArray).value(forKey: kProperties) as Any,
+            "bookmarks": self.rootBookmark.children.map { $0.properties },
             "recentDocuments": recentDocuments as Any
         ]
+        UserDefaults.standard.setPersistentDomain(bookmarksDictionary, forName: bookmarksIdentifier)
 
-//        UserDefaults.standard.setPersistentDomain(bookmarksDictionary, forName: SKBookmarksIdentifier)
-//
 //        NSDictionary *bookmarksDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[[bookmarkRoot children] valueForKey:@"properties"], BOOKMARKS_KEY, recentDocuments, RECENTDOCUMENTS_KEY, nil];
 //        [[NSUserDefaults standardUserDefaults] setPersistentDomain:bookmarksDictionary forName:SKBookmarksIdentifier];
     }

+ 35 - 6
PDF Office/PDF Master/Class/PDFTools/KMBookmark/Model/KMBookmark.swift

@@ -23,7 +23,22 @@ enum KMBookmarkType: String {
 }
 
 class KMBookmark: NSObject {
-    var properties: NSDictionary?
+    var properties: [String: Any]? {
+        get {
+            var data: [String: Any] = documentSetup 
+            let tempSetup = [kType: bookmarkType.rawValue,
+                             kBDAlias: self.aliasData ?? SKAlias.init(url: self.fileURL).data,
+                             kPageIndex: pageIndex.description,
+                             kLabel: self.label
+            ] as [String : Any]
+            data.merge(tempSetup) { (_, new) in new }
+            return data
+        }
+        set {
+            
+        }
+    }
+
     var bookmarkType: KMBookmarkType = .bookmark
     var label: String = ""
     var alternateIcon: NSImage =  NSImage()
@@ -31,10 +46,21 @@ class KMBookmark: NSObject {
     var pageIndex: UInt = 0
     var pageNumber: NSNumber = 0
     
-    var documentSetup: [String: Any]?
+    var documentSetup: [String: Any] = [:] {
+        didSet {
+            if documentSetup[kType] != nil {
+                self.bookmarkType = KMBookmarkType(rawValue: documentSetup[kType] as! String ) ?? .bookmark
+            }
+            self.aliasData = documentSetup[kBDAlias] as? NSData
+            self.pageIndex = documentSetup[kPageIndex] as? UInt ?? 0
+            if documentSetup[kLabel] != nil {
+                self.label = documentSetup[kLabel] as! String
+            }
+        }
+    }
     var parent: KMBookmark?
     var children: [KMBookmark] = [] //子
-    
+    var aliasData: NSData?
     var icon: NSImage {
         get {
             if let fileURL = self.fileURL {
@@ -98,7 +124,7 @@ class KMBookmark: NSObject {
     static func bookmark(properties: [String: Any]) -> KMBookmark? {
         guard let type: KMBookmarkType = KMBookmarkType(rawValue: properties[kType] as! String) else { return nil}
         
-        var bookmark: KMBookmark
+        var bookmark: KMBookmark = KMBookmark()
         if type == .separator {
             bookmark = KMSeparatorBookmark()
         } else if type == .folder || type == .session {
@@ -123,7 +149,9 @@ class KMBookmark: NSObject {
             let label = properties[kLabel] as? String
             let aliasData = properties[kBDAlias] as? Data
 
-            bookmark = KMFileBookmark.bookmark(aliasData: aliasData! as NSData, pageIndex: Int(pageIndex), label: label!)
+            if aliasData != nil {
+                bookmark = KMFileBookmark.bookmark(aliasData: aliasData! as NSData, pageIndex: Int(pageIndex), label: label!)
+            }
         }
         return bookmark
     }
@@ -146,6 +174,7 @@ class KMBookmark: NSObject {
         let alias = SKAlias.init(data: aliasData as Data)
         let url = alias?.fileURL
         bookmark.fileURL = url
+        bookmark.aliasData = aliasData
         return bookmark
     }
     
@@ -310,7 +339,7 @@ class KMRootBookmark: KMFolderBookmark {
         var childs: [KMBookmark] = []
         for setup in childrenProperties {
             let bookmark = KMBookmark.bookmark(properties: setup as! [String : Any])
-            bookmark?.documentSetup = setup as? [String : Any]
+            bookmark?.documentSetup = setup as! [String : Any]
             bookmark?.parent = rootBookmark
             if bookmark != nil {
                 childs.append(bookmark!)

+ 3 - 2
PDF Office/PDF Master/Class/PDFTools/KMBookmark/View/OutlineView/View/KMBookmarkOutlineFileCellView.xib

@@ -19,8 +19,8 @@
             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
             <subviews>
                 <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ymy-gW-lXL">
-                    <rect key="frame" x="6" y="12" width="37" height="16"/>
-                    <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="zyJ-bQ-Ieg">
+                    <rect key="frame" x="6" y="12" width="88" height="16"/>
+                    <textFieldCell key="cell" lineBreakMode="truncatingHead" title="Label" id="zyJ-bQ-Ieg">
                         <font key="font" metaFont="system"/>
                         <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                         <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -29,6 +29,7 @@
             </subviews>
             <constraints>
                 <constraint firstItem="Ymy-gW-lXL" firstAttribute="centerY" secondItem="c22-O7-iKe" secondAttribute="centerY" id="90a-HL-C3i"/>
+                <constraint firstAttribute="trailing" secondItem="Ymy-gW-lXL" secondAttribute="trailing" constant="8" id="Wzt-FM-TfX"/>
                 <constraint firstItem="Ymy-gW-lXL" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="8" id="X1J-Ns-qZv"/>
             </constraints>
             <point key="canvasLocation" x="95" y="147.5"/>

+ 3 - 2
PDF Office/PDF Master/Class/PDFTools/KMBookmark/View/OutlineView/View/KMBookmarkOutlinePageCellView.xib

@@ -19,8 +19,8 @@
             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
             <subviews>
                 <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6rd-c6-xiO">
-                    <rect key="frame" x="6" y="17" width="37" height="16"/>
-                    <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="y9R-V3-HMJ">
+                    <rect key="frame" x="6" y="17" width="220" height="16"/>
+                    <textFieldCell key="cell" lineBreakMode="truncatingTail" title="Label" id="y9R-V3-HMJ">
                         <font key="font" metaFont="system"/>
                         <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                         <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -28,6 +28,7 @@
                 </textField>
             </subviews>
             <constraints>
+                <constraint firstAttribute="trailing" secondItem="6rd-c6-xiO" secondAttribute="trailing" constant="8" id="Isb-C5-jXb"/>
                 <constraint firstItem="6rd-c6-xiO" firstAttribute="centerY" secondItem="c22-O7-iKe" secondAttribute="centerY" id="aiv-2l-ujJ"/>
                 <constraint firstItem="6rd-c6-xiO" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="8" id="pZe-W9-osc"/>
             </constraints>

+ 3 - 2
PDF Office/PDF Master/Class/PDFTools/KMBookmark/View/OutlineView/View/KMBookmarkOutlineTitleCellView.xib

@@ -28,8 +28,8 @@
                     <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="k8e-0B-Ovx"/>
                 </imageView>
                 <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="O2g-MZ-HgZ">
-                    <rect key="frame" x="34" y="14" width="37" height="16"/>
-                    <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="dZr-Df-1xG">
+                    <rect key="frame" x="34" y="14" width="129" height="16"/>
+                    <textFieldCell key="cell" lineBreakMode="truncatingTail" title="Label" id="dZr-Df-1xG">
                         <font key="font" metaFont="system"/>
                         <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                         <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -40,6 +40,7 @@
                 <constraint firstItem="O2g-MZ-HgZ" firstAttribute="leading" secondItem="QOJ-Np-rGX" secondAttribute="trailing" constant="8" id="7im-Gb-1ak"/>
                 <constraint firstItem="QOJ-Np-rGX" firstAttribute="centerY" secondItem="c22-O7-iKe" secondAttribute="centerY" id="SIX-gb-TeH"/>
                 <constraint firstItem="O2g-MZ-HgZ" firstAttribute="centerY" secondItem="c22-O7-iKe" secondAttribute="centerY" id="Ycj-22-abn"/>
+                <constraint firstAttribute="trailing" secondItem="O2g-MZ-HgZ" secondAttribute="trailing" constant="8" id="c4o-1b-QQh"/>
                 <constraint firstItem="QOJ-Np-rGX" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="8" id="fB6-QE-pjp"/>
             </constraints>
             <point key="canvasLocation" x="-117.5" y="91"/>