Преглед на файлове

【2025】【BOTA】搜索列表UI处理

tangchao преди 3 месеца
родител
ревизия
e4671ed591

+ 192 - 1
PDF Office/PDF Master/Class/PDFWindowController/Side/LeftSide/Search/KMBotaSearchViewController.swift

@@ -29,6 +29,17 @@ class KMBotaSearchViewController: NSViewController {
     @IBOutlet weak var searchTips: NSTextField!
     @IBOutlet weak var pageLabel: NSTextField!
     
+    @IBOutlet var scrollView: NSScrollView!
+    @IBOutlet weak var tableView: KMBotaTableView!
+    
+    var handdler = KMNSearchHanddler()
+    
+    var searchResults : [KMSearchMode] = [] {
+        didSet {
+//            self.updataLeftSideFindView()
+        }
+    }
+    
     deinit {
         KMPrint("KMBotaSearchViewController deinit.")
         
@@ -76,11 +87,32 @@ class KMBotaSearchViewController: NSViewController {
         }
         
         self.searchBox.isHidden = true
+        
+        contentView = tableView.enclosingScrollView
+        
+        let menu = NSMenu()
+        _ = menu.addItem(title: KMLocalizedString("Whole Words Only"), action: #selector(toggleWholeWordSearch), target: self)
+        _ = menu.addItem(title: KMLocalizedString("Ignore Case"), action: #selector(toggleCaseInsensitiveSearch), target: self)
+        (self.searchField.cell as? NSSearchFieldCell)?.searchMenuTemplate = menu
+        (self.searchField.cell as? NSSearchFieldCell)?.placeholderString = KMLocalizedString("Search PDF")
+        
+        self.searchField.target = self
+        self.searchField.action = #selector(searchAction)
     }
     
     override func viewDidLoad() {
         super.viewDidLoad()
-        // Do view setup here.
+        
+        self.tableView.delegate = self
+        self.tableView.dataSource = self
+        self.tableView.botaDelegate = self
+//        self.tableView.menu?.delegate = self
+        
+//        self.mwcFlags.wholeWordSearch = KMDataManager.ud_integer(forKey: SKWholeWordSearchKey)
+//        self.mwcFlags.caseInsensitiveSearch = KMDataManager.ud_integer(forKey: SKCaseInsensitiveSearchKey)
+        
+        self.tableView.backgroundColor = KMAppearance.Layout.l0Color()
+        self.tableView.tableColumn(withIdentifier: kPageColumnId)?.headerCell.title = KMLocalizedString("Page")
     }
     
     override func viewDidAppear() {
@@ -110,4 +142,163 @@ class KMBotaSearchViewController: NSViewController {
         self.searchDomeButton.isHidden = true
         self.searchBox.isHidden = false
     }
+    
+    @objc func toggleWholeWordSearch(_ sender: AnyObject?) {
+//        if self.mwcFlags.wholeWordSearch == 1 {
+//            self.mwcFlags.wholeWordSearch = 0
+//        } else {
+//            self.mwcFlags.wholeWordSearch = 1
+//        }
+//        if self.searchField.stringValue.isEmpty == false {
+//            self.search(self.searchField)
+//        }
+//        KMDataManager.ud_set(self.mwcFlags.wholeWordSearch, forKey: SKWholeWordSearchKey)
+    }
+    
+    @objc func toggleCaseInsensitiveSearch(_ sender: AnyObject?) {
+//        if self.mwcFlags.caseInsensitiveSearch == 0 {
+//            self.mwcFlags.caseInsensitiveSearch = 1
+//        } else {
+//            self.mwcFlags.caseInsensitiveSearch = 0
+//        }
+//
+//        if self.searchField.stringValue.isEmpty == false {
+//            self.search(self.searchField)
+//        }
+//        KMDataManager.ud_set(self.mwcFlags.caseInsensitiveSearch, forKey: SKCaseInsensitiveSearchKey)
+    }
+    
+    @objc func goToSelectedFindResults(_ sender: AnyObject?) {
+//        guard let olView = sender as? NSTableView, olView.clickedRow != -1 else {
+//            NSSound.beep()
+//            return
+//        }
+//        self.updateFindResultHighlightsForDirection(.directSelection)
+    }
+    
+    @objc func searchAction(_ sender: NSSearchField) {
+//        if sender.stringValue.isEmpty {
+//            self.applySearchTableHeader("")
+//        }
+//        self.delegate?.searchAction?(searchString: sender.stringValue, isCase: self.mwcFlags.caseInsensitiveSearch == 1)
+        
+        handdler.search(keyword: sender.stringValue, isCase: false, isWholeWord: false) { [weak self] results in
+            self?.tableView.reloadData()
+        }
+    }
+}
+
+// MARK: - NSTableViewDelegate, NSTableViewDataSource
+
+extension KMBotaSearchViewController: NSTableViewDelegate, NSTableViewDataSource {
+    func numberOfRows(in tableView: NSTableView) -> Int {
+        return self.handdler.searchResults.count
+    }
+    
+    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
+        let cell = tableView.makeView(withIdentifier: KMFindTableviewCell.km_identifier, owner: self) as! KMFindTableviewCell
+        if handdler.searchResults.count > row {
+            let selection = handdler.searchResults[row]
+            if let data = tableColumn?.identifier.rawValue, data == kResultsColumnId.rawValue {
+                cell.resultLabel.attributedStringValue = selection.attributedString
+                cell.resultLabel.textColor = KMAppearance.Layout.h0Color()
+            } else if let data = tableColumn?.identifier.rawValue, data == kPageColumnId.rawValue {
+                cell.resultLabel.stringValue = "\(Int(selection.selectionPageIndex) + 1)"
+                cell.resultLabel.textColor = KMAppearance.Layout.h2Color()
+            }
+        }
+        return cell
+    }
+    
+    func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
+        return 40.0
+    }
+    
+    func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
+        let rowView = KMBotaTableRowView()
+        return rowView
+    }
+    
+    func tableViewSelectionDidChange(_ notification: Notification) {
+//        if self.stopRepeatLoad == true {
+//
+//        } else {
+//            self.delegate?.controller?(controller: self, listViewSelectionDidChange: notification.object, info: nil)
+//        }
+        
+        
+            //            [self updateFindResultHighlightsForDirection:NSDirectSelection];
+        let row = self.tableView.selectedRow
+        if row >= 0 {
+            let model = handdler.searchResults[row]
+//            let isEditing =  self.listView?.isEditing() ?? false
+//            if isEditing {
+//                self.mainViewController?.srHanddler.showSelection(model.selection)
+//                return
+//            }
+            
+//            self.listView?.go(to: model.selection, animated: true)
+            //                self.listView?.setHighlightedSelection(model.selection, animated: true)
+            DispatchQueue.main.asyncAfter(deadline: .now()+0.3) {
+//                self.listView?.setHighlightedSelections([model.selection])
+//                self.listView?.setNeedsDisplayAnnotationViewForVisiblePages()
+            }
+        }
+    }
+    
+    func tableView(_ aTableView: NSTableView, copyRowsWithIndexes rowIndexes: IndexSet) {
+        if IAPProductsManager.default().isAvailableAllFunction() == false {
+            KMPurchaseCompareWindowController.sharedInstance().showWindow(nil)
+            return
+        }
+        var string = ""
+        for idx in rowIndexes {
+            let match = handdler.searchResults[idx].selection
+            string.append("* ")
+            //                [string appendFormat:NSLocalizedString(@"Page %@", @""), [match firstPageLabel]];
+            string = string.appendingFormat(KMLocalizedString("Page %@"), "\(match.safeFirstPage()?.pageIndex() ?? 0)")
+            //                [string appendFormat:@"", [[match contextString] string]];
+            string = string.appendingFormat(": %@\n", match.string() ?? "")
+        }
+        let pboard = NSPasteboard.general
+        pboard.clearContents()
+        pboard.writeObjects([string as NSPasteboardWriting])
+    }
+}
+
+
+// MARK: - KMBotaTableViewDelegate
+
+extension KMBotaSearchViewController: KMBotaTableViewDelegate {
+    func tableView(_ aTableView: NSTableView, canCopyRowsWithIndexes rowIndexes: IndexSet) -> Bool {
+        return rowIndexes.count > 0
+    }
+    
+    func tableViewMoveRight(_ aTableView: NSTableView) {
+//        self.updateFindResultHighlightsForDirection(.selectingNext)
+    }
+    
+    func tableViewMoveUp(_ aTableView: NSTableView) {
+        self.tableView.km_safe_selectRowIndexes(.init(integer: self.tableView.selectedRow-1), byExtendingSelection: false)
+        self.tableView.scrollRowToVisible(self.tableView.selectedRow)
+    }
+    
+    func tableViewMoveDown(_ aTableView: NSTableView) {
+        self.tableView.km_safe_selectRowIndexes(.init(integer: self.tableView.selectedRow+1), byExtendingSelection: false)
+        self.tableView.scrollRowToVisible(self.tableView.selectedRow)
+    }
+    
+    func tableView(_ aTableView: NSTableView, imageContextForRow rowIndex: Int) -> AnyObject? {
+        if rowIndex >= self.searchResults.count {
+            return nil
+        }
+        let model = self.searchResults[rowIndex]
+        let selection = model.selection
+        let x = selection.bounds.origin.x + NSWidth(selection.bounds) * 0.5
+        let y = selection.bounds.origin.y + NSHeight(selection.bounds) * 0.5
+        let point = NSPoint(x: x, y: y)
+//        return CPDFDestination(document: self.pdfDocument(), pageIndex: Int(model.selectionPageIndex), at: point, zoom: self.scaleFactor().cgFloat)
+        return nil
+    }
+    
 }

+ 114 - 12
PDF Office/PDF Master/Class/PDFWindowController/Side/LeftSide/Search/KMBotaSearchViewController.xib

@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
     <dependencies>
         <deployment identifier="macosx"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -12,6 +12,7 @@
                 <outlet property="emptyBox" destination="YP3-hM-jIu" id="76W-OU-rpD"/>
                 <outlet property="emptySearchLabel" destination="RZV-VM-ubG" id="P1g-lE-xp0"/>
                 <outlet property="pageLabel" destination="DG6-KM-fPE" id="WCW-t2-N6y"/>
+                <outlet property="scrollView" destination="uYq-U5-IA0" id="42p-Xm-ruW"/>
                 <outlet property="searchBox" destination="m5j-WZ-WP4" id="cvH-DW-gmp"/>
                 <outlet property="searchDomeButton" destination="Sot-lU-418" id="nTG-J5-bHW"/>
                 <outlet property="searchField" destination="Exf-lV-10v" id="HAb-dG-HXv"/>
@@ -20,6 +21,7 @@
                 <outlet property="searchResultsView" destination="hP4-NA-Ala" id="srK-Ds-q65"/>
                 <outlet property="searchTips" destination="LV8-kC-pPy" id="vhL-vd-TBZ"/>
                 <outlet property="segmentedControl" destination="2OM-I5-WuT" id="hoB-xe-Aav"/>
+                <outlet property="tableView" destination="QYw-8e-Jnj" id="TGk-gM-Ff7"/>
                 <outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
             </connections>
         </customObject>
@@ -29,7 +31,7 @@
             <rect key="frame" x="0.0" y="0.0" width="240" height="513"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <subviews>
-                <searchField wantsLayer="YES" focusRingType="none" verticalHuggingPriority="750" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Exf-lV-10v">
+                <searchField wantsLayer="YES" verticalHuggingPriority="750" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Exf-lV-10v">
                     <rect key="frame" x="16" y="452" width="164" height="20"/>
                     <searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="border" usesSingleLineMode="YES" id="So1-aF-t1m">
                         <font key="font" metaFont="system"/>
@@ -62,7 +64,7 @@
                                         </constraints>
                                         <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="KMImageNameEmptySearch" id="Fgf-hM-PPL"/>
                                     </imageView>
-                                    <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="RZV-VM-ubG">
+                                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="RZV-VM-ubG">
                                         <rect key="frame" x="8" y="0.0" width="234" height="17"/>
                                         <constraints>
                                             <constraint firstAttribute="width" constant="230" id="Mx1-pb-NMh"/>
@@ -100,7 +102,7 @@
                         <constraint firstAttribute="height" constant="25" id="LzF-7O-4Fm"/>
                     </constraints>
                 </customView>
-                <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZGS-QS-aFB">
+                <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZGS-QS-aFB">
                     <rect key="frame" x="14" y="484" width="40" height="17"/>
                     <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="Eil-0G-5lp">
                         <font key="font" metaFont="system" size="14"/>
@@ -125,7 +127,7 @@
                                         </constraints>
                                         <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="KMImageNameUXIconBtnSearchbarSearch" id="3va-Z6-CLg"/>
                                     </imageView>
-                                    <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LV8-kC-pPy">
+                                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LV8-kC-pPy">
                                         <rect key="frame" x="15" y="2" width="37" height="16"/>
                                         <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="8F8-Ba-XlP">
                                             <font key="font" metaFont="system"/>
@@ -155,7 +157,7 @@
                 <customView translatesAutoresizingMaskIntoConstraints="NO" id="hP4-NA-Ala">
                     <rect key="frame" x="16" y="430" width="208" height="14"/>
                     <subviews>
-                        <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="avX-Sl-7dw">
+                        <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="avX-Sl-7dw">
                             <rect key="frame" x="-2" y="0.0" width="33" height="14"/>
                             <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="aJC-Hn-dib">
                                 <font key="font" metaFont="smallSystem"/>
@@ -163,7 +165,7 @@
                                 <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
                             </textFieldCell>
                         </textField>
-                        <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DG6-KM-fPE">
+                        <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DG6-KM-fPE">
                             <rect key="frame" x="177" y="0.0" width="33" height="14"/>
                             <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="kMU-mK-L5o">
                                 <font key="font" metaFont="smallSystem"/>
@@ -182,14 +184,14 @@
                 </customView>
                 <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Sot-lU-418">
                     <rect key="frame" x="188" y="452" width="36" height="20"/>
-                    <buttonCell key="cell" type="square" title="Button" bezelStyle="shadowlessSquare" alignment="center" imageScaling="proportionallyDown" inset="2" id="ueG-bM-doV">
-                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                        <font key="font" metaFont="cellTitle"/>
-                    </buttonCell>
                     <constraints>
                         <constraint firstAttribute="height" constant="20" id="bAq-jA-d1x"/>
                         <constraint firstAttribute="width" constant="36" id="nWW-zz-pQ3"/>
                     </constraints>
+                    <buttonCell key="cell" type="square" title="Button" bezelStyle="shadowlessSquare" alignment="center" imageScaling="proportionallyDown" inset="2" id="ueG-bM-doV">
+                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                        <font key="font" metaFont="cellTitle"/>
+                    </buttonCell>
                     <connections>
                         <action selector="searchDomeButtonAtion:" target="-2" id="6wa-gN-8qu"/>
                     </connections>
@@ -225,6 +227,106 @@
             <point key="canvasLocation" x="-17" y="129.5"/>
         </customView>
         <userDefaultsController representsSharedInstance="YES" id="vA0-OE-D4s"/>
+        <scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="42" horizontalPageScroll="10" verticalLineScroll="42" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="uYq-U5-IA0">
+            <rect key="frame" x="0.0" y="0.0" width="204" height="400"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <clipView key="contentView" drawsBackground="NO" id="7P5-FJ-Eig">
+                <rect key="frame" x="0.0" y="0.0" width="204" height="400"/>
+                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                <subviews>
+                    <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="40" viewBased="YES" id="QYw-8e-Jnj" customClass="KMBotaTableView" customModule="PDF_Reader_Pro" customModuleProvider="target">
+                        <rect key="frame" x="0.0" y="0.0" width="204" height="400"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <size key="intercellSpacing" width="0.0" height="2"/>
+                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+                        <color key="gridColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+                        <tableColumns>
+                            <tableColumn identifier="results" editable="NO" width="122" minWidth="46" maxWidth="1000" id="Xtg-ZV-tXQ">
+                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                    <color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
+                                </tableHeaderCell>
+                                <textFieldCell key="dataCell" lineBreakMode="charWrapping" selectable="YES" editable="YES" refusesFirstResponder="YES" alignment="left" id="kP2-3L-c8f">
+                                    <font key="font" metaFont="system"/>
+                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                    <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                </textFieldCell>
+                                <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+                                <prototypeCellViews>
+                                    <tableCellView identifier="KMFindTableviewCell" id="Muc-XZ-Cat" customClass="KMFindTableviewCell" customModule="PDF_Reader_Pro" customModuleProvider="target">
+                                        <rect key="frame" x="10" y="1" width="128" height="40"/>
+                                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                        <subviews>
+                                            <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="AUE-7I-G4W">
+                                                <rect key="frame" x="-2" y="5" width="132" height="30"/>
+                                                <constraints>
+                                                    <constraint firstAttribute="height" constant="30" id="JWo-Vj-8NS"/>
+                                                </constraints>
+                                                <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="1" id="jb2-GD-xvh">
+                                                    <font key="font" usesAppearanceFont="YES"/>
+                                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                                </textFieldCell>
+                                            </textField>
+                                        </subviews>
+                                        <constraints>
+                                            <constraint firstItem="AUE-7I-G4W" firstAttribute="centerY" secondItem="Muc-XZ-Cat" secondAttribute="centerY" id="Rme-Zv-qPL"/>
+                                            <constraint firstItem="AUE-7I-G4W" firstAttribute="leading" secondItem="Muc-XZ-Cat" secondAttribute="leading" id="dKA-zc-qoa"/>
+                                            <constraint firstAttribute="trailing" secondItem="AUE-7I-G4W" secondAttribute="trailing" id="eDF-F3-s7i"/>
+                                        </constraints>
+                                        <connections>
+                                            <outlet property="resultLabel" destination="AUE-7I-G4W" id="p3j-BB-vcW"/>
+                                        </connections>
+                                    </tableCellView>
+                                </prototypeCellViews>
+                            </tableColumn>
+                            <tableColumn identifier="page" editable="NO" width="50" minWidth="32" maxWidth="100" id="rlQ-aE-U2P">
+                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                    <color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
+                                </tableHeaderCell>
+                                <textFieldCell key="dataCell" lineBreakMode="charWrapping" selectable="YES" editable="YES" refusesFirstResponder="YES" alignment="center" id="hx5-Je-iDT">
+                                    <font key="font" metaFont="system"/>
+                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                    <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                </textFieldCell>
+                                <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+                                <prototypeCellViews>
+                                    <tableCellView identifier="KMFindTableviewCell" id="3ag-9X-rPG" customClass="KMFindTableviewCell" customModule="PDF_Reader_Pro" customModuleProvider="target">
+                                        <rect key="frame" x="138" y="1" width="56" height="40"/>
+                                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                        <subviews>
+                                            <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xeH-zO-w2B">
+                                                <rect key="frame" x="0.0" y="0.0" width="56" height="30"/>
+                                                <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
+                                                <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="right" title="10000" id="S9R-YO-39v">
+                                                    <font key="font" usesAppearanceFont="YES"/>
+                                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                                </textFieldCell>
+                                            </textField>
+                                        </subviews>
+                                        <connections>
+                                            <outlet property="resultLabel" destination="xeH-zO-w2B" id="8bo-yX-JAs"/>
+                                        </connections>
+                                    </tableCellView>
+                                </prototypeCellViews>
+                            </tableColumn>
+                        </tableColumns>
+                    </tableView>
+                </subviews>
+                <nil key="backgroundColor"/>
+            </clipView>
+            <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="ztW-Ji-5eu">
+                <rect key="frame" x="-100" y="-100" width="255" height="15"/>
+                <autoresizingMask key="autoresizingMask"/>
+            </scroller>
+            <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="e6o-tF-7SC">
+                <rect key="frame" x="-100" y="-100" width="15" height="454"/>
+                <autoresizingMask key="autoresizingMask"/>
+            </scroller>
+            <point key="canvasLocation" x="252" y="180"/>
+        </scrollView>
     </objects>
     <resources>
         <image name="KMImageNameEmptySearch" width="140" height="140"/>

+ 2 - 1
PDF Office/PDF Master/KMClass/KMPDFViewController/KMMainViewController.swift

@@ -611,7 +611,8 @@ struct KMNMWCFlags {
             infoContendSplitView.setPosition(MIN_SIDE_PANE_WIDTH.doubleValue, ofDividerAt: 0) //暂时无法记录上一次打开的宽度
         }
         if pdfSideBarType == .search {
-            KMPrint(" search")
+            botaViewController?.searchViewC.handdler.pdfView = listView
+            botaViewController?.leftsideType = .search
         } else if pdfSideBarType == .thumbnail {
             botaViewController?.leftsideType = pdfSideBarType
             KMPrint(" thumbnail")

+ 14 - 1
PDF Office/PDF Master/KMClass/Left/KMNLeftSideViewController.swift

@@ -45,6 +45,11 @@ class KMNLeftSideViewController: KMNBaseViewController {
         return contr
     }()
     
+    private lazy var searchViewC_: KMBotaSearchViewController = {
+        let con = KMBotaSearchViewController()
+        return con
+    }()
+    
     var outlineViewC: KMOutlineViewController {
         get {
             return outlineViewC_
@@ -57,6 +62,12 @@ class KMNLeftSideViewController: KMNBaseViewController {
         }
     }
     
+    var searchViewC: KMBotaSearchViewController {
+        get {
+            return searchViewC_
+        }
+    }
+    
     lazy var thumbnailHeaderViewController: KMNThumnailHeaderViewController = {
         let controller = KMNThumnailHeaderViewController(nibName: "KMNThumnailHeaderViewController", bundle: nil)
         controller.view.frame = headerBox.bounds
@@ -67,7 +78,9 @@ class KMNLeftSideViewController: KMNBaseViewController {
     public var leftsideType:KMPDFSidebarType = .none {
         didSet {
             switch leftsideType {
-            case .search: break
+            case .search:
+                headerBoxHeightConst.constant = 0
+                bottomBox.contentView = searchViewC_.view
             case .thumbnail:
                 headerBoxHeightConst.constant = 40
                 headerBox.contentView = thumbnailHeaderViewController.view

+ 60 - 0
PDF Office/PDF Master/KMClass/Left/Search/Tools/KMNSearchHanddler.swift

@@ -0,0 +1,60 @@
+//
+//  KMNSearchHanddler.swift
+//  PDF Reader Pro
+//
+//  Created by User-Tangchao on 2024/12/1.
+//
+
+import Cocoa
+
+class KMNSearchHanddler: NSObject {
+    
+    weak var pdfView: CPDFView?
+    
+    var searchResults: [KMSearchMode] = []
+    
+    func search(keyword: String, isCase: Bool, isWholeWord: Bool, callback: @escaping (([KMSearchMode]?) -> Void)) {
+        guard let document = self.pdfView?.document else {
+            NSSound.beep()
+            callback(nil)
+            return
+        }
+        if document.isFinding {
+            document.cancelFindString()
+        }
+        if keyword.isEmpty {
+            callback(nil)
+            return
+        }
+        
+        let theKeyword = keyword.decomposedStringWithCompatibilityMapping
+        var opt = CPDFSearchOptions()
+        if isCase {
+            opt.insert(.caseSensitive)
+        }
+        if isWholeWord {
+            opt.insert(.matchWholeWord)
+        }
+        DispatchQueue.global().async {
+            let result = document.findString(theKeyword, with: opt)
+            
+            self.searchResults.removeAll()
+            for sels in result ?? [] {
+                for sel in sels {
+                    let mode : KMSearchMode = KMSearchMode()
+                    mode.selection = sel
+                    mode.attributedString = KMOCToolClass.getAttributedString(selection: sel, keyword: theKeyword)
+                    mode.selectionPageIndex = document.index(for: sel.page)
+                    self.searchResults.insert(mode, at: self.searchResults.count)
+
+                    sel.setColor(NSColor(red: 236/255.0, green: 241/255.0, blue: 83/255.0, alpha: 0.5))
+                }
+            }
+            
+            DispatchQueue.main.async {
+                callback(self.searchResults)
+            }
+        }
+    }
+
+}

+ 24 - 0
PDF Office/PDF Reader Pro.xcodeproj/project.pbxproj

@@ -346,6 +346,9 @@
 		65F9F47F2CFB5C3500F187A8 /* KMNBotaBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9F47E2CFB5C3500F187A8 /* KMNBotaBaseViewController.swift */; };
 		65F9F4802CFB5C3500F187A8 /* KMNBotaBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9F47E2CFB5C3500F187A8 /* KMNBotaBaseViewController.swift */; };
 		65F9F4812CFB5C3500F187A8 /* KMNBotaBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9F47E2CFB5C3500F187A8 /* KMNBotaBaseViewController.swift */; };
+		65F9F4852CFC16A100F187A8 /* KMNSearchHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9F4842CFC16A100F187A8 /* KMNSearchHanddler.swift */; };
+		65F9F4862CFC16A100F187A8 /* KMNSearchHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9F4842CFC16A100F187A8 /* KMNSearchHanddler.swift */; };
+		65F9F4872CFC16A100F187A8 /* KMNSearchHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F9F4842CFC16A100F187A8 /* KMNSearchHanddler.swift */; };
 		65FABB312C9AFB0C00AA92E5 /* KMSectionCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FABB302C9AFB0C00AA92E5 /* KMSectionCellView.swift */; };
 		65FABB322C9AFB0C00AA92E5 /* KMSectionCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FABB302C9AFB0C00AA92E5 /* KMSectionCellView.swift */; };
 		65FABB332C9AFB0C00AA92E5 /* KMSectionCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FABB302C9AFB0C00AA92E5 /* KMSectionCellView.swift */; };
@@ -5666,6 +5669,7 @@
 		65D88ED12C85826A00DD06E0 /* KMRSAUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMRSAUtils.swift; sourceTree = "<group>"; };
 		65EF3A7C2C81C1F500CCFC8F /* KMVerificationRSA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KMVerificationRSA.swift; sourceTree = "<group>"; };
 		65F9F47E2CFB5C3500F187A8 /* KMNBotaBaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNBotaBaseViewController.swift; sourceTree = "<group>"; };
+		65F9F4842CFC16A100F187A8 /* KMNSearchHanddler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNSearchHanddler.swift; sourceTree = "<group>"; };
 		65FABB302C9AFB0C00AA92E5 /* KMSectionCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSectionCellView.swift; sourceTree = "<group>"; };
 		65FABB342C9AFB1F00AA92E5 /* KMSectionCellView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMSectionCellView.xib; sourceTree = "<group>"; };
 		8931681F296D73CC0073EA59 /* KMSignatureAnnotationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMSignatureAnnotationViewController.h; sourceTree = "<group>"; };
@@ -8243,6 +8247,22 @@
 			path = Base;
 			sourceTree = "<group>";
 		};
+		65F9F4822CFC162B00F187A8 /* Search */ = {
+			isa = PBXGroup;
+			children = (
+				65F9F4832CFC162B00F187A8 /* Tools */,
+			);
+			path = Search;
+			sourceTree = "<group>";
+		};
+		65F9F4832CFC162B00F187A8 /* Tools */ = {
+			isa = PBXGroup;
+			children = (
+				65F9F4842CFC16A100F187A8 /* KMNSearchHanddler.swift */,
+			);
+			path = Tools;
+			sourceTree = "<group>";
+		};
 		8931681E296D73C10073EA59 /* Signature */ = {
 			isa = PBXGroup;
 			children = (
@@ -14457,6 +14477,7 @@
 		F3EF17812CD5FC230007D364 /* Left */ = {
 			isa = PBXGroup;
 			children = (
+				65F9F4822CFC162B00F187A8 /* Search */,
 				65F9F47C2CFB5BF500F187A8 /* Base */,
 				651675A12CE302D400019A20 /* Outline */,
 				657865E82CE1E7DD00AFE2DB /* Bookmark */,
@@ -17357,6 +17378,7 @@
 				BBB9B32B299A5D6D004F3235 /* GTMOAuth2KeychainCompatibility.m in Sources */,
 				AD3AAD752B0DCEAA00DE5FE7 /* KMCompareSaveView.swift in Sources */,
 				BB66472B2C06DD9C00924EE0 /* KMToolbarConfigTBItemView.swift in Sources */,
+				65F9F4852CFC16A100F187A8 /* KMNSearchHanddler.swift in Sources */,
 				BB146FB7299DC0D100784A6A /* GTLRRuntimeCommon.m in Sources */,
 				BB3A429E2B4BF03A006D0642 /* KMSystemPDFMenu.swift in Sources */,
 				9FF0D0602B6A5DCF0018A732 /* KMPDFAnnotationTextWidgetSub.swift in Sources */,
@@ -18816,6 +18838,7 @@
 				BBB789AF2BE8BF2400F7E09C /* AIChatTranslateResultItem.swift in Sources */,
 				651675EA2CE3313500019A20 /* KMOutlineViewController.swift in Sources */,
 				BB7E59F72BBA427C0021E63D /* KMBrowserWindow.swift in Sources */,
+				65F9F4862CFC16A100F187A8 /* KMNSearchHanddler.swift in Sources */,
 				BBA922232B4E7D340061057A /* HyperLinkButton.swift in Sources */,
 				BBA922332B4E97540061057A /* KMPurchaseLimitWindowController.swift in Sources */,
 				BBC8A76E2B05EDDF00FA9377 /* KMThumbnail.swift in Sources */,
@@ -19803,6 +19826,7 @@
 				BB52F5532CC1FAB2007418DB /* KMLinkViewController.swift in Sources */,
 				651559102CCA6E2400C0F0D9 /* KMConvertBaseWindowController.swift in Sources */,
 				9F0ACC002C85CB22009574D5 /* KMDMGProductsManager.swift in Sources */,
+				65F9F4872CFC16A100F187A8 /* KMNSearchHanddler.swift in Sources */,
 				651675E52CE3313500019A20 /* KMOutlineEditViewController.swift in Sources */,
 				9FB221102B1AE35E00A5B208 /* NSBitmapImageRep_KMExtension.swift in Sources */,
 				ADDF83342B391A5C00A81A4E /* CPDFAnnotation+PDFListView.m in Sources */,