Browse Source

【2025】【BOTA】大纲搜索补充完整单词条件

tangchao 3 months ago
parent
commit
5bb0bb8aa0

+ 73 - 8
PDF Office/PDF Master/KMClass/Left/Outline/Controller/KMOutlineViewController.swift

@@ -8,6 +8,14 @@
 import Cocoa
 import KMComponentLibrary
 
+extension KMNSearchKey.wholeWords {
+    static let outline = "OutlineSearchWholeWordsKey"
+}
+
+extension KMNSearchKey.caseSensitive {
+    static let outline = "OutlineSearchCaseSensitiveKey"
+}
+
 class KMOutlineViewController: KMNBaseViewController {
     @IBOutlet var contendView: NSView!
     @IBOutlet weak var topView: NSView!
@@ -31,10 +39,10 @@ class KMOutlineViewController: KMNBaseViewController {
     let moreMenu = NSMenu()
     var isLocalEvent = false
     
+    var model = KMNOutlineModel()
     var handdler = KMNOutlineHanddler()
     
     private weak var popover_: NSPopover?
-    private var ignoreCase_ = false
     
     private lazy var searchButton_: ComponentButton = {
         let view = ComponentButton()
@@ -50,7 +58,6 @@ class KMOutlineViewController: KMNBaseViewController {
     
     private lazy var moreDropdown_: ComponentButton = {
         let view = ComponentButton()
-//        view.properties = ComponentDropdownProperty(type: .split_primary, size: .xxs, state: .normal, split: false, disabled: false)
         view.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, state: .normal, isDisable: false, onlyIcon: true, icon: NSImage(named: "KMImageNameOutlineMore"))
         return view
     }()
@@ -68,6 +75,8 @@ class KMOutlineViewController: KMNBaseViewController {
     
     private var groupView_: ComponentGroup?
     private var menuGroupView_: ComponentGroup?
+    private var searchGroupView_: ComponentGroup?
+    private var searchGroupTarget_: ComponentButton?
     
     deinit {
         self.BOTAOutlineView.delegate = nil
@@ -113,10 +122,12 @@ class KMOutlineViewController: KMNBaseViewController {
             headerSearchView_?.autoresizingMask = [.width, .height]
         }
         _hideHeaderSearch()
-        headerSearchView_?.itemClick = { [weak self] idx, _ in
-            if idx == 1 { // 忽略大小写
-                let ignoreCase = self?.ignoreCase_ ?? false
-                self?.ignoreCase_ = !ignoreCase
+        headerSearchView_?.itemClick = { [weak self] idx, params in
+            if idx == 1 { // 显示搜索限制条件
+                guard let button = params.first as? ComponentButton else {
+                    return
+                }
+                self?.showSearchGroupView(sender: button)
             } else if idx == 2 { // 关闭搜索
                 self?._hideHeaderSearch()
                 
@@ -367,8 +378,6 @@ class KMOutlineViewController: KMNBaseViewController {
     
     private func _showHeaderSearch() {
         BOTAOutlineView.isSearchMode = true
-        
-        headerSearchView_?.ignoreCase = ignoreCase_
         headerSearchView_?.isHidden = false
     }
     
@@ -448,6 +457,39 @@ class KMOutlineViewController: KMNBaseViewController {
         moreDropdown_.reloadData()
     }
     
+    func showSearchGroupView(sender: ComponentButton) {
+        var viewHeight: CGFloat = 8
+        var menuItemArr: [ComponentMenuitemProperty] = []
+        let titles = ["Whole Words","Case Sensitive"]
+        for i in titles {
+            let menuI = ComponentMenuitemProperty(text: KMLocalizedString(i))
+            menuItemArr.append(menuI)
+            viewHeight += 36
+        }
+        
+        if let info = menuItemArr.first {
+            if KMDataManager.ud_bool(forKey: KMNSearchKey.wholeWords.outline) {
+                info.righticon = NSImage(named: "KMNImageNameMenuSelect")
+            }
+        }
+        if let info = menuItemArr.last {
+            if KMDataManager.ud_bool(forKey: KMNSearchKey.caseSensitive.outline) {
+                info.righticon = NSImage(named: "KMNImageNameMenuSelect")
+            }
+        }
+        
+        let groupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
+        searchGroupView_ = groupView
+        groupView?.groupDelegate = self
+        groupView?.frame = CGRectMake(310, 0, 200, viewHeight)
+        groupView?.updateGroupInfo(menuItemArr)
+        
+        var point = sender.convert(sender.frame.origin, to: nil)
+        point.y -= viewHeight
+        groupView?.showWithPoint(point, relativeTo: sender)
+        searchGroupTarget_ = sender
+    }
+    
     func removeGroupView() {
         if groupView_ != nil {
             groupView_?.removeFromSuperview()
@@ -1114,6 +1156,11 @@ extension KMOutlineViewController: ComponentGroupDelegate {
         } else if group == menuGroupView_ {
             group?.removeFromSuperview()
             menuGroupView_ = nil
+        } else if group == searchGroupView_ {
+//            searchGroupView_ = nil
+            searchGroupTarget_?.properties.state = .normal
+            searchGroupTarget_?.reloadData()
+            searchGroupTarget_ = nil
         }
     }
     
@@ -1156,6 +1203,24 @@ extension KMOutlineViewController: ComponentGroupDelegate {
                 
                 group?.removeFromSuperview()
             }
+        } else if group == searchGroupView_ {
+            guard let menuI = menuItemProperty else {
+                return
+            }
+            let idx = group?.menuItemArr.firstIndex(of: menuI)
+            if idx == 0 {
+                let key = KMNSearchKey.wholeWords.outline
+                let value = KMDataManager.ud_bool(forKey: key)
+                KMDataManager.ud_set(!value, forKey: key)
+                
+                BOTAOutlineView.wholeWords = !value
+            } else if idx == 1 {
+                let key = KMNSearchKey.caseSensitive.outline
+                let value = KMDataManager.ud_bool(forKey: key)
+                KMDataManager.ud_set(!value, forKey: key)
+                
+                BOTAOutlineView.caseSensitive = !value
+            }
         }
     }
 }

+ 0 - 1
PDF Office/PDF Master/KMClass/Left/Outline/Model/KMBOTAOutlineItem.swift

@@ -18,6 +18,5 @@ class KMBOTAOutlineItem: NSObject {
     var hover: Bool = false
     var isItemExpanded: Bool = false
     
-    var isSearchMode = false
     var searchChildren: [KMBOTAOutlineItem] = []
 }

+ 24 - 0
PDF Office/PDF Master/KMClass/Left/Outline/Model/KMNOutlineModel.swift

@@ -0,0 +1,24 @@
+//
+//  KMNOutlineModel.swift
+//  PDF Reader Pro
+//
+//  Created by User-Tangchao on 2024/11/26.
+//
+
+import Cocoa
+
+struct KMNSearchKey {
+    struct wholeWords {}
+    struct caseSensitive {}
+}
+
+class KMNSearchModel: NSObject {
+    // 完整单词
+    var wholeWords = false
+    // 区分大小写
+    var caseSensitive = false
+}
+
+class KMNOutlineModel: NSObject {
+    var searchModel = KMNSearchModel()
+}

+ 0 - 19
PDF Office/PDF Master/KMClass/Left/Outline/View/KMBOTAOutlineCellView.swift

@@ -78,25 +78,6 @@ class KMBOTAOutlineCellView: NSTableCellView {
     
     func reloadData() {
         guard let data = self.model else { return }
-        
-        self.titleLabel.stringValue = data.outline.label ?? ""
-        if data.isItemExpanded {
-            self.iconButton.image = NSImage(named: "KMImageNameArrowDown")
-        } else {
-            self.iconButton.image = NSImage(named: "KMImageNameArrowRight")
-        }
-        
-        if data.isSearchMode {
-            iconButton.isHidden = data.searchChildren.isEmpty
-        } else {
-            if data.outline.numberOfChildren > 0 {
-                self.iconButton.isHidden = false
-                //            self.iconImageWidthConstrailnt.constant = 22
-            } else {
-                self.iconButton.isHidden = true
-                //            self.iconImageWidthConstrailnt.constant = 0
-            }
-        }
     }
     
     func updateUI() {

+ 69 - 73
PDF Office/PDF Master/KMClass/Left/Outline/View/KMBOTAOutlineView.swift

@@ -35,6 +35,31 @@ class KMBOTAOutlineView: BaseXibView {
     
     var isSearchMode = false
     var searchKey = ""
+    var wholeWords = false {
+        didSet {
+            if isSearchMode == false {
+                return
+            }
+            if searchKey.isEmpty {
+                return
+            }
+            reloadData()
+            outlineView.expandItem(nil, expandChildren: true)
+        }
+    }
+    
+    var caseSensitive = false {
+        didSet {
+            if isSearchMode == false {
+                return
+            }
+            if searchKey.isEmpty {
+                return
+            }
+            reloadData()
+            outlineView.expandItem(nil, expandChildren: true)
+        }
+    }
     
     override func draw(_ dirtyRect: NSRect) {
         super.draw(dirtyRect)
@@ -89,25 +114,26 @@ class KMBOTAOutlineView: BaseXibView {
         self.delegate?.BOTAOutlineView(self, didReloadData: self.data ?? KMBOTAOutlineItem())
     }
     
+    // 递归处理
+    
     func reloadSearchChildren(item: KMBOTAOutlineItem?) {
         guard let theItem = item else {
             return
         }
         
-        if theItem.children.isEmpty {
-            return
-        }
-        
-        theItem.isSearchMode = true
+        // 处理当前 item
         let models = self.fetchOutlines(for: theItem, searchString: searchKey)
-        theItem.isSearchMode = true
+        // 搜索数据
         theItem.searchChildren = models
         
+        theItem.isItemExpanded = true
+        
+        if theItem.children.isEmpty { // 递归退出条件
+            return
+        }
+        
+        // 处理 childItem
         for childM in theItem.children {
-            let models = self.fetchOutlines(for: childM, searchString: searchKey)
-            childM.isSearchMode = true
-            childM.searchChildren = models
-            
             self.reloadSearchChildren(item: childM)
         }
     }
@@ -145,12 +171,17 @@ class KMBOTAOutlineView: BaseXibView {
     func hasContainString(_ searchString: String, rootOutline outline: CPDFOutline) -> Bool {
         var label = outline.label ?? ""
         var searchLabel = searchString
-//        if self.outlineIgnoreCaseFlag {
-//            label = label.lowercased()
-//            searchLabel = searchLabel.lowercased()
-//        }
+        if caseSensitive == false {
+            label = label.lowercased()
+            searchLabel = searchLabel.lowercased()
+        }
+        
+        
         if label.contains(searchLabel) {
-//        if ([outline.label rangeOfString:searchString options:self.outlineIgnoreCaseFlag?NSCaseInsensitiveSearch:0].location != NSNotFound){
+            if wholeWords {
+                let words = label.words()
+                return words.contains(searchLabel)
+            }
             return true
         } else {
             var subHas = false
@@ -194,48 +225,15 @@ extension KMBOTAOutlineView : NSOutlineViewDataSource,NSOutlineViewDelegate {
                 }
                 
 //                self.showSearchOutlineBlankState(false)
-                rootModel.isItemExpanded = true
-                rootModel.isSearchMode = true
-                
-//                let models = self.fetchOutlines(for: rootModel, searchString: searchKey)
-//                for model in models {
-//                    model.isItemExpanded = true
-//                    model.isSearchMode = true
-//                }
-
-//                rootModel.searchChildren = models
-//                return models.count
                 return rootModel.searchChildren.count
             }
 
-            rootModel.isSearchMode = false
-//            rootModel.searchChildren = []
-//            for model in rootModel.children {
-//                model.isItemExpanded = true
-//                model.isSearchMode = false
-//            }
             return Int(rootModel.outline.numberOfChildren)
         }
         if isSearchMode {
-            model.isItemExpanded = true
-            model.isSearchMode = true
-            
-//            let models = self.fetchOutlines(for: model, searchString: searchKey)
-//            for model in models {
-//                model.isItemExpanded = true
-//                model.isSearchMode = true
-//            }
-//            model.searchChildren = models
-//            return models.count
             return model.searchChildren.count
         }
         
-        model.isSearchMode = false
-//        model.searchChildren = []
-//        for childM in model.children {
-//                model.isItemExpanded = true
-//            childM.isSearchMode = false
-//        }
         return model.children.count
     }
     
@@ -251,35 +249,13 @@ extension KMBOTAOutlineView : NSOutlineViewDataSource,NSOutlineViewDelegate {
                     return ""
                 }
 //                self.showSearchOutlineBlankState(false)
-                let models = self.fetchOutlines(for: rootModel, searchString: searchKey)
-                for model in models {
-                    model.isItemExpanded = true
-                    model.isSearchMode = true
-                }
-//                rootModel.searchChildren = models
-//                return models.safe_element(for: index) as Any
                 return rootModel.searchChildren.safe_element(for: index) as Any
             }
-            for model in rootModel.children {
-                model.isSearchMode = false
-            }
-            rootModel.searchChildren = []
             return rootModel.children[index] as Any
         }
         if isSearchMode {
-            let models = self.fetchOutlines(for: model, searchString: searchKey)
-            for model in models {
-                model.isItemExpanded = true
-                model.isSearchMode = true
-            }
-//            model.searchChildren = models
-//            return models.safe_element(for: index) as Any
             return model.searchChildren.safe_element(for: index) as Any
         }
-        for childM in model.children {
-            childM.isSearchMode = false
-        }
-        model.searchChildren = []
         return model.children[index] as Any
     }
     
@@ -318,11 +294,14 @@ extension KMBOTAOutlineView : NSOutlineViewDataSource,NSOutlineViewDelegate {
     }
     
     func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
+        guard let model = item as? KMBOTAOutlineItem else {
+            return nil
+        }
+        
         let cell : KMBOTAOutlineCellView = KMBOTAOutlineCellView.init()
-        let model = item as? KMBOTAOutlineItem
-        cell.model = model
+        
         if isSearchMode {
-            let label = model?.outline.label ?? ""
+            let label = model.outline.label ?? ""
             var attri = NSMutableAttributedString(string: label, attributes: [
                 .font : NSFont.SFProTextRegularFont(13),
                 .foregroundColor : KMNColorTools.colorText_1()])
@@ -332,6 +311,23 @@ extension KMBOTAOutlineView : NSOutlineViewDataSource,NSOutlineViewDelegate {
                 attri.addAttributes([.font : NSFont.SFProTextBoldFont(13), .foregroundColor: KMNColorTools.colorPrimary_textLight()], range: range)
             }
             cell.titleLabel.attributedStringValue = attri
+            
+            cell.iconButton.isHidden = model.searchChildren.isEmpty
+        } else {
+            cell.titleLabel.stringValue = model.outline.label ?? ""
+            
+            if model.outline.numberOfChildren > 0 {
+                cell.iconButton.isHidden = false
+            } else {
+                cell.iconButton.isHidden = true
+            }
+        }
+        
+        let isItemExpanded  = model.isItemExpanded
+        if isItemExpanded {
+            cell.iconButton.image = NSImage(named: "KMImageNameArrowDown")
+        } else {
+            cell.iconButton.image = NSImage(named: "KMImageNameArrowRight")
         }
         
         cell.iconAction = { [unowned self] view in

+ 2 - 22
PDF Office/PDF Master/KMClass/Left/Outline/View/KMNBotaHeaderSearchView.swift

@@ -63,28 +63,7 @@ class KMNBotaHeaderSearchView: NSView, NibLoadable {
     }
     
     @objc private func _searchAction() {
-        var viewHeight: CGFloat = 8
-        var menuItemArr: [ComponentMenuitemProperty] = []
-        let titles = ["Ignore Case"]
-        for i in titles {
-            let menuI: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: true, itemSelected: ignoreCase, isDisabled: false, keyEquivalent: nil, text: KMLocalizedString(i))
-            menuItemArr.append(menuI)
-            viewHeight += 36
-        }
-        
-        if groupView_ == nil {
-            groupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
-        }
-        groupView_?.groupDelegate = self
-        groupView_?.frame = CGRectMake(310, 0, 200, viewHeight)
-        groupView_?.updateGroupInfo(menuItemArr)
-        
-        var point = searchButton_.convert(searchButton_.frame.origin, to: nil)
-        point.y -= viewHeight
-        groupView_?.showWithPoint(point, relativeTo: searchButton_)
-        
-        searchButton_.properties.state = .pressed
-        searchButton_.reloadData()
+        itemClick?(1, searchButton_)
     }
     
     @objc private func _closeAction() {
@@ -101,6 +80,7 @@ extension KMNBotaHeaderSearchView: ComponentInputDelegate {
 extension KMNBotaHeaderSearchView: ComponentGroupDelegate {
     func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) {
         ignoreCase = !ignoreCase
+        KMPrint("componentGroupDidSelect \(ignoreCase)")
         itemClick?(1)
     }
     

+ 16 - 0
PDF Office/PDF Master/KMClass/Tools/Category/Foundation/String+KMExtensions.swift

@@ -171,5 +171,21 @@ extension String {
         }
         return nil
     }
+    
+    // 获取单词
+    
+    func words() -> [String] {
+        let pattern = "\\b[\\w']+\\b"
+        do {
+            let regex = try NSRegularExpression(pattern: pattern)
+            let results = regex.matches(in: self, range: NSRange(self.startIndex..., in: self))
+            return results.map {
+                String(self[Range($0.range, in: self)!])
+            }
+        } catch {
+            print("Invalid regex: \(error.localizedDescription)")
+            return []
+        }
+    }
 }
 

+ 15 - 7
PDF Office/PDF Reader Pro.xcodeproj/project.pbxproj

@@ -187,6 +187,9 @@
 		654A5A8C2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654A5A8B2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift */; };
 		654A5A8D2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654A5A8B2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift */; };
 		654A5A8E2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654A5A8B2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift */; };
+		654E63312CF5993C00F6323F /* KMNOutlineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654E63302CF5993C00F6323F /* KMNOutlineModel.swift */; };
+		654E63322CF5993C00F6323F /* KMNOutlineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654E63302CF5993C00F6323F /* KMNOutlineModel.swift */; };
+		654E63332CF5993C00F6323F /* KMNOutlineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654E63302CF5993C00F6323F /* KMNOutlineModel.swift */; };
 		6554450B2C88483C00BD9010 /* KMDiscountToSaveWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 655445082C88483B00BD9010 /* KMDiscountToSaveWindowController.xib */; };
 		6554450C2C88483C00BD9010 /* KMDiscountToSaveWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 655445082C88483B00BD9010 /* KMDiscountToSaveWindowController.xib */; };
 		6554450D2C88483C00BD9010 /* KMDiscountToSaveWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 655445082C88483B00BD9010 /* KMDiscountToSaveWindowController.xib */; };
@@ -5771,6 +5774,7 @@
 		6536FDE62C9C49A6004A0FB9 /* KMNoteFooterCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNoteFooterCellView.swift; sourceTree = "<group>"; };
 		6536FDEA2C9C49C0004A0FB9 /* KMNoteFooterCellView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMNoteFooterCellView.xib; sourceTree = "<group>"; };
 		654A5A8B2C8AE200001FBD4B /* KMAnalytics+KMExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KMAnalytics+KMExtensions.swift"; sourceTree = "<group>"; };
+		654E63302CF5993C00F6323F /* KMNOutlineModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNOutlineModel.swift; sourceTree = "<group>"; };
 		655445082C88483B00BD9010 /* KMDiscountToSaveWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = KMDiscountToSaveWindowController.xib; sourceTree = "<group>"; };
 		655445092C88483C00BD9010 /* KMDiscountToSaveWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KMDiscountToSaveWindowController.h; sourceTree = "<group>"; };
 		6554450A2C88483C00BD9010 /* KMDiscountToSaveWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KMDiscountToSaveWindowController.m; sourceTree = "<group>"; };
@@ -8179,18 +8183,18 @@
 		651675B12CE3311F00019A20 /* View */ = {
 			isa = PBXGroup;
 			children = (
-				651675B22CE3311F00019A20 /* KMBOTAOutlineCellView.xib */,
-				651675B32CE3311F00019A20 /* KMCustomOutlineView.swift */,
-				651675B42CE3311F00019A20 /* KMBOTAOutlineView.xib */,
 				651675B52CE3311F00019A20 /* KMBOTAOutlineCellView.swift */,
-				651675B62CE3311F00019A20 /* KMTocTableCellView.swift */,
-				651675B72CE3311F00019A20 /* KMCustomTableRowView.swift */,
-				651675B82CE3311F00019A20 /* KMOutlineView.swift */,
+				651675B22CE3311F00019A20 /* KMBOTAOutlineCellView.xib */,
 				651675B92CE3311F00019A20 /* KMBOTAOutlineRowView.swift */,
-				651675BA2CE3311F00019A20 /* KMTocOutlineView.swift */,
 				651675BB2CE3311F00019A20 /* KMBOTAOutlineView.swift */,
+				651675B42CE3311F00019A20 /* KMBOTAOutlineView.xib */,
+				651675B32CE3311F00019A20 /* KMCustomOutlineView.swift */,
+				651675B72CE3311F00019A20 /* KMCustomTableRowView.swift */,
 				65202DF62CE4803500A204B5 /* KMNBotaHeaderSearchView.swift */,
 				65202DFB2CE4827900A204B5 /* KMNBotaHeaderSearchView.xib */,
+				651675B82CE3311F00019A20 /* KMOutlineView.swift */,
+				651675BA2CE3311F00019A20 /* KMTocOutlineView.swift */,
+				651675B62CE3311F00019A20 /* KMTocTableCellView.swift */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -8199,6 +8203,7 @@
 			isa = PBXGroup;
 			children = (
 				651675BD2CE3312000019A20 /* KMBOTAOutlineItem.swift */,
+				654E63302CF5993C00F6323F /* KMNOutlineModel.swift */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -17817,6 +17822,7 @@
 				BB897224294B07960045787C /* KMWatermarkAdjectiveTopBarItemView.swift in Sources */,
 				AD3AAD1B2B0B5B4400DE5FE7 /* KMCompareCoveringWindowController.swift in Sources */,
 				BBAC26A12AFDF54F00563A08 /* KMConvertOperationQueue.swift in Sources */,
+				654E63312CF5993C00F6323F /* KMNOutlineModel.swift in Sources */,
 				AD9527EA2955520C0039D2BC /* KMBaseTextFieldModel.swift in Sources */,
 				9FDCD80E2B6C904900E22166 /* KMFormListMenuPopWindowController.swift in Sources */,
 				BB8AA5432CC6711B0084F183 /* KMPDFConfig.swift in Sources */,
@@ -18190,6 +18196,7 @@
 				ADE3C1DF29A5AA0B00793B13 /* KMRequestServer.swift in Sources */,
 				BB46CF4D2AFBB34900281EDF /* AutoSaveManager.swift in Sources */,
 				F30B22862CB8D9630041002E /* KMNQuickToolCollectionViewItem.swift in Sources */,
+				654E63322CF5993C00F6323F /* KMNOutlineModel.swift in Sources */,
 				9FB220E02B10850400A5B208 /* KMAnnotationStampViewController.swift in Sources */,
 				BBD426802B4FCF1500AC8660 /* KMTextFieldCell.swift in Sources */,
 				BB7185392C2B0A1100C1156B /* KMEditPDFPopToolBarWindow.swift in Sources */,
@@ -20410,6 +20417,7 @@
 				BBFE6E5A2930724B00142C01 /* KMMergePageModel.swift in Sources */,
 				9F1FE50429406E4700E952CA /* CTTabStripModelOrderController.m in Sources */,
 				AD61B7AD2A9DC6F600D346C1 /* KMResourceDownloadManager.swift in Sources */,
+				654E63332CF5993C00F6323F /* KMNOutlineModel.swift in Sources */,
 				BB6013862AD3A0E300A76FB2 /* CPDFTextWidgetAnnotation+PDFListView.swift in Sources */,
 				BB3D07652CD0821F00EB94DF /* KMPDFSplitView.swift in Sources */,
 				65FABB332C9AFB0C00AA92E5 /* KMSectionCellView.swift in Sources */,