Browse Source

【2025】【注释列表】补充右键菜单功能

dinglingui 2 months ago
parent
commit
1c4601e34b

+ 9 - 0
PDF Office/PDF Master/Class/PDFWindowController/Side/LeftSide/Tools/KMNoteReplyHanddler.swift

@@ -309,6 +309,15 @@ class KMNoteReplyHanddler: NSObject {
         model.annoModel?.footerModel?.replyModel = model
     }
     
+    func editAnnotation(annotationModel: KMBotaAnnotationModel?) {
+        guard let model = annotationModel else {
+            return
+        }
+        
+        model.footerModel?.isExpand = true
+        model.footerModel?.editAnnoModel = annotationModel
+    }
+    
     func removeReplyAnnotation(_ anno: CPDFAnnotation?) {
         guard let theAnno = anno else {
             return

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

@@ -5143,7 +5143,6 @@ extension KMMainViewController: CPDFViewDelegate,CPDFListViewDelegate {
         
         //
         pdfToolbarController?.pdfViewActiveAnnotationsChanged()
-        botaViewController?.annoController.note_reloadDataIfNeed()
     }
     
     func pdfListViewMenu(forEvent pdfListView: CPDFListView!, for theEvent: NSEvent!, click menu: AutoreleasingUnsafeMutablePointer<NSMenu?>!, isMoveSelectAnno: Bool) {

+ 12 - 0
PDF Office/PDF Master/KMClass/KMPDFViewController/KMPDFMenuConfig.swift

@@ -192,6 +192,18 @@ let BOTAMenuIdentifier_Annotation_Export = "BOTAMenuIdentifier_Annotation_Export
 let BOTAMenuIdentifier_Annotation_RemoveAll = "BOTAMenuIdentifier_Annotation_RemoveAll"
 let BOTAMenuIdentifier_Annotation_DeleteRep = "BOTAMenuIdentifier_Annotation_DeleteRep"
 
+let BOTAMenuIdentifier_Annotation_EditNote = "BOTAMenuIdentifier_Annotation_EditNote"
+let BOTAMenuIdentifier_Annotation_AddMark = "BOTAMenuIdentifier_Annotation_AddMark"
+let BOTAMenuIdentifier_Annotation_AddRep = "BOTAMenuIdentifier_Annotation_AddRep"
+let BOTAMenuIdentifier_Annotation_RepState = "BOTAMenuIdentifier_Annotation_RepState"
+let BOTAMenuIdentifier_Annotation_RepStateNone = "BOTAMenuIdentifier_Annotation_RepStateNone"
+let BOTAMenuIdentifier_Annotation_RepStateAccepted = "BOTAMenuIdentifier_Annotation_RepStateAccepted"
+let BOTAMenuIdentifier_Annotation_RepStateRejected = "BOTAMenuIdentifier_Annotation_RepStateRejected"
+let BOTAMenuIdentifier_Annotation_RepStateCancelled = "BOTAMenuIdentifier_Annotation_RepStateCancelled"
+let BOTAMenuIdentifier_Annotation_RepStateCompleted = "BOTAMenuIdentifier_Annotation_RepStateCompleted"
+let BOTAMenuIdentifier_Annotation_DeleteSignRep = "BOTAMenuIdentifier_Annotation_DeleteSignRep"
+let BOTAMenuIdentifier_Annotation_DeleteMuteRep = "BOTAMenuIdentifier_Annotation_DeleteMuteRep"
+
 @objcMembers class KMPDFMenuConfig: NSString {
     class func aiMenuItemProperty(theEvent:NSEvent?)->ComponentMenuitemProperty {
         let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,

+ 15 - 0
PDF Office/PDF Master/KMClass/Left/Annotaion/Controller/KMLeftSideViewController+Note.swift

@@ -1111,6 +1111,16 @@ extension KMLeftSideViewController {
         return selectedNotes
     }
     
+    func selectedObjcNotes() -> [Any] {
+        var selectedNotes: [Any] = []
+        let rowIndexes = self.noteOutlineView.selectedRowIndexes
+        for row in rowIndexes {
+            let item = self.noteOutlineView.item(atRow: row)
+            selectedNotes.append(item)
+        }
+        return selectedNotes
+    }
+    
     func clearAnnotationFilterData() {
         if let _key = self.pdfDocument()?.documentURL?.path {
             let userDefaults = UserDefaults.standard
@@ -1182,6 +1192,11 @@ extension KMLeftSideViewController: KMNoteOutlineViewDelegate {
 
 // MARK: - NSMenuDelegate
 extension KMLeftSideViewController: NSMenuDelegate {
+    
+    func menuNeedsUpdate(_ menu: NSMenu) {
+        menu.removeAllItems()
+    }
+    
     func menuDidClose(_ menu: NSMenu) {
         if(menu == self.noteFilterMenu) {
             headerView.sortButton.properties.state = .normal

+ 382 - 47
PDF Office/PDF Master/KMClass/Left/Annotaion/Controller/KMLeftSideViewController.swift

@@ -224,6 +224,8 @@ class KMLeftSideViewController: KMSideViewController {
     }()
     
     var isRenameNoteOutline = false
+    
+    var currentItem: Any?
 
     // 所有注释
     var allAnnotations: [CPDFAnnotation] = []
@@ -250,6 +252,7 @@ class KMLeftSideViewController: KMSideViewController {
     var searchGroupView: ComponentGroup?
     var searchGroupTarget: ComponentButton?
     var moreGroupView: ComponentGroup?
+    var rightGroupView: ComponentGroup?
 
     var emptyView: ComponentEmpty = {
         let view = ComponentEmpty()
@@ -364,6 +367,36 @@ class KMLeftSideViewController: KMSideViewController {
         toolHeaderBox.contentView = headerView
     }
     
+    func updateMarkState(model:KMBotaAnnotationModel){ // Markup
+        let anno = model.anno
+        guard let state = self.noteReplyHanddler.fetchAnnoState(anno), state == .marked else {
+            self.noteReplyHanddler.markAnnotation(anno)
+            self.noteOutlineView.reloadItem(model)
+            return
+        }
+        self.noteReplyHanddler.unMarkAnnotation(anno)
+        self.noteOutlineView.reloadItem(model)
+    }
+    
+    func updateReplaState(model:KMBotaAnnotationModel,state:CPDFAnnotationState){
+        let anno = model.anno
+        noteReplyHanddler.updateAnnoState(anno: anno, state: state)
+        self.noteOutlineView.reloadData()
+    }
+    
+    func updateExpand (model:KMBotaAnnotationModel,isExpand:Bool,item: Any) {
+        // 将折叠状态记录到模型
+        model.foldType = isExpand  ? .unfold : .fold
+        
+        model.footerModel?.isExpand = isExpand
+        model.isExpand = isExpand
+        self.noteOutlineView.reloadData()
+        DispatchQueue.main.async {
+            let row = self.noteOutlineView.row(forItem: item)
+            self.noteOutlineView.scrollRowToVisible(row)
+        }
+    }
+    
     // MARK: -  Filter
     func showFilterController() {
         noteFilterAction(nil)
@@ -428,6 +461,154 @@ class KMLeftSideViewController: KMSideViewController {
         groupView?.showWithPoint(point, relativeTo: headerView.moreButton)
     }
     
+    func showRightGropView(raw: Int,event:NSEvent,view:NSView?,item:Any) {
+        let groupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
+        
+        currentItem = item
+        
+        var menuItemArr: [ComponentMenuitemProperty] = []
+        let rowIndexes = self.selectedObjcNotes()
+        
+        var viewHeight = 0.0
+        if(rowIndexes.count == 1) {
+            let dataItem = rowIndexes.first
+            if let data = dataItem as? KMBotaAnnotationModel {
+                if  let an = data.anno as? CPDFAnnotation {
+                    if an.isKind(of: CPDFFreeTextAnnotation.self) == true ||
+                        an.isKind(of: CPDFTextAnnotation.self)  == true {
+                    } else  {
+                        let note_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Notes"),
+                                                                                                 identifier: BOTAMenuIdentifier_Annotation_EditNote,representedObject: [data])
+                        menuItemArr.append(note_Menuitem)
+                        viewHeight += 36.0
+                    }
+                    let reply_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Reply"),
+                                                                                              identifier: BOTAMenuIdentifier_Annotation_AddRep,representedObject: [data])
+                    menuItemArr.append(reply_Menuitem)
+                    viewHeight += 36.0
+
+                    let state = self.noteReplyHanddler.fetchAnnoState(an) ?? .unMarked
+
+                    var markString = ""
+                    if state == .unMarked {
+                        markString = KMLocalizedString("Marked")
+                    } else {
+                        markString = KMLocalizedString("Unmarked")
+                    }
+                    let mark_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: markString,
+                                                                                              identifier: BOTAMenuIdentifier_Annotation_AddMark,representedObject: [data])
+                    menuItemArr.append(mark_Menuitem)
+                    viewHeight += 36.0
+                    
+                    let state_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Status"),
+                                                                                                   identifier: BOTAMenuIdentifier_Annotation_RepState)
+                    
+                    var subMenuItemArr: [ComponentMenuitemProperty] = []
+                    let property0: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("None"),identifier: BOTAMenuIdentifier_Annotation_RepStateNone,representedObject: [data])
+                    let property1: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Accepted"),identifier: BOTAMenuIdentifier_Annotation_RepStateAccepted,representedObject: [data])
+                    let property2: ComponentMenuitemProperty = ComponentMenuitemProperty(
+                                                                                                text: KMLocalizedString("Rejected"),identifier: BOTAMenuIdentifier_Annotation_RepStateRejected,representedObject: [data])
+                    let property3: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Cancelled"),identifier: BOTAMenuIdentifier_Annotation_RepStateCancelled,representedObject: [data])
+                    let property4: ComponentMenuitemProperty = ComponentMenuitemProperty(
+                                                                                                text: KMLocalizedString("Completed"),identifier: BOTAMenuIdentifier_Annotation_RepStateCompleted,representedObject: [data])
+                    subMenuItemArr.append(property0)
+                    subMenuItemArr.append(property1)
+                    subMenuItemArr.append(property2)
+                    subMenuItemArr.append(property3)
+                    subMenuItemArr.append(property4)
+                    
+                    let reviewState = noteReplyHanddler.fetchReviewState(an) ?? .none
+                    if reviewState == .none {
+                        property0.righticon = NSImage(named: "KMNImageNameMenuSelect")
+                    } else if reviewState == .completed {
+                        property4.righticon = NSImage(named: "KMNImageNameMenuSelect")
+                    } else if reviewState == .canceled {
+                        property3.righticon = NSImage(named: "KMNImageNameMenuSelect")
+                    } else if reviewState == .accepted {
+                        property1.righticon = NSImage(named: "KMNImageNameMenuSelect")
+                    } else if reviewState == .rejected {
+                        property2.righticon = NSImage(named: "KMNImageNameMenuSelect")
+                    }
+                    
+                    state_Menuitem.subPropertys = subMenuItemArr
+                    menuItemArr.append(state_Menuitem)
+                    viewHeight += 36.0
+                    
+                    menuItemArr.append(ComponentMenuitemProperty.divider())
+                    viewHeight += 8.0
+
+                    var showString = ""
+                    if data.isExpand {
+                        showString = KMLocalizedString("Collapse")
+                    } else {
+                        showString = KMLocalizedString("Expand")
+                    }
+                    
+                    let show_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: showString,
+                                                                                              identifier: PDFViewMenuIdentifier_Normal_ShowPopUI,representedObject: [data])
+                    menuItemArr.append(show_Menuitem)
+                    viewHeight += 36.0
+                    
+                    menuItemArr.append(ComponentMenuitemProperty.divider())
+                    viewHeight += 8.0
+
+                    if an.isKind(of: CPDFFreeTextAnnotation.self) == true ||
+                        an.isKind(of: CPDFTextAnnotation.self)  == true ||
+                        an.isKind(of: CPDFMarkupAnnotation.self)  == true {
+                        let copy_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Copy Text"),
+                                                                                                  identifier: PDFViewMenuIdentifier_Normal_Copy,representedObject: [data])
+                        copy_Menuitem.keyEquivalent = "⌘ C"
+
+                        menuItemArr.append(copy_Menuitem)
+                        viewHeight += 36.0
+                    }
+                    
+                    let delete_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Delete"),
+                                                                                              identifier: PDFViewMenuIdentifier_Normal_Delete,representedObject: [data])
+                    delete_Menuitem.keyEquivalent = "⌘ " + "⌫"
+                    menuItemArr.append(delete_Menuitem)
+                    viewHeight += 36.0
+                }
+            } else if let replyModel = dataItem as? KMBotaAnnotationReplyModel {
+                let note_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Notes"),
+                                                                                         identifier: BOTAMenuIdentifier_Annotation_EditNote,representedObject: [replyModel])
+                menuItemArr.append(note_Menuitem)
+                viewHeight += 36.0
+                
+                let copy_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Copy Text"),
+                                                                                          identifier: PDFViewMenuIdentifier_Normal_CopyText,representedObject: [replyModel])
+                copy_Menuitem.keyEquivalent = "⌘ C"
+                menuItemArr.append(copy_Menuitem)
+                viewHeight += 36.0
+                
+                let delete_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Delete"),
+                                                                                          identifier: BOTAMenuIdentifier_Annotation_DeleteSignRep,representedObject: [replyModel])
+                delete_Menuitem.keyEquivalent = "⌘ " + "⌫"
+
+                menuItemArr.append(delete_Menuitem)
+                viewHeight += 36.0
+            }
+        } else if rowIndexes.count > 1 {
+            let delete_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(text: KMLocalizedString("Delete"),
+                                                                                      identifier: BOTAMenuIdentifier_Annotation_DeleteMuteRep,representedObject: rowIndexes)
+            delete_Menuitem.keyEquivalent = "⌘ " + "⌫"
+
+            menuItemArr.append(delete_Menuitem)
+            viewHeight += 36.0
+        }
+        
+        rightGroupView = groupView
+        groupView?.groupDelegate = self
+        groupView?.frame = CGRectMake(310, 0, 200, viewHeight)
+        groupView?.updateGroupInfo(menuItemArr)
+        
+        var point = NSPoint(x: CGRectGetMaxX(view?.frame ?? CGRectZero), y: CGRectGetMidY(view?.frame ?? CGRectZero))
+        point = noteOutlineView.convert(point, to: nil)
+        point.y -= (groupView?.frame.size.height ?? 0)/2
+        groupView?.showWithPoint(point, relativeTo: view)
+
+    }
+    
     func showSearchGroupView(sender: ComponentButton) {
         var viewHeight: CGFloat = 8
         var menuItemArr: [ComponentMenuitemProperty] = []
@@ -675,11 +856,11 @@ extension KMLeftSideViewController: NSOutlineViewDelegate, NSOutlineViewDataSour
                 }
                 cell?.countLabel.stringValue = "\(data.itemCount / 2)"
                 
-                cell?.itemClick = { idx, _ in
+                cell?.itemClick = {[weak self] idx, _ in
                     if idx == 1 { // 收取 & 展开
                         data.isExpand = !data.isExpand
                         
-                        self.noteOutlineView.reloadData()
+                        self?.noteOutlineView.reloadData()
                     }
                 }
                 return cell
@@ -710,6 +891,11 @@ extension KMLeftSideViewController: NSOutlineViewDelegate, NSOutlineViewDataSour
                     DispatchQueue.main.async {
                         self.view.window?.makeFirstResponder(cell?.inputTextF)
                     }
+                } else if let con = data.editAnnoModel?.anno?.contents, con.isEmpty == false {
+                    cell?.inputTextF.stringValue = con
+                    DispatchQueue.main.async {
+                        self.view.window?.makeFirstResponder(cell?.inputTextF)
+                    }
                 } else {
                     if let cont = data.inputContent {
                         cell?.inputTextF.stringValue = cont
@@ -761,6 +947,22 @@ extension KMLeftSideViewController: NSOutlineViewDelegate, NSOutlineViewDataSour
                             }
                             return
                         }
+                        
+                        if let con = data.editAnnoModel?.anno?.contents, con.isEmpty == false { // 编辑
+                            let model = data.editAnnoModel
+                            model?.anno?.contents = content
+                            model?.anno?.setUserName(KMPreference.shared.author)
+                            
+                            // 置空编辑状态
+                            data.replyModel = nil
+                            data.inputContent = nil
+                            data.editAnnoModel = nil
+                            self?.noteOutlineView.reloadData()
+                            if let row = self?.noteOutlineView.row(forItem: data) {
+                                self?.noteOutlineView.scrollRowToVisible(row)
+                            }
+                            return
+                        }
                         if let replyAnno = self?.noteReplyHanddler.createReplyAnnotation(data.anno, content: content, userName: KMPreference.shared.author) {
                             let model = KMBotaAnnotationReplyModel()
                             model.anno = data.anno
@@ -827,27 +1029,14 @@ extension KMLeftSideViewController: NSOutlineViewDelegate, NSOutlineViewDataSour
             }
             cell.itemClick = { [weak self] idx , _ in
                 if idx == 1 { // Markup
-                    let anno = model?.anno
-                    guard let state = self?.noteReplyHanddler.fetchAnnoState(anno), state == .marked else {
-                        self?.noteReplyHanddler.markAnnotation(anno)
-                        self?.noteOutlineView.reloadItem(model)
-                        return
+                    if model != nil {
+                        self?.updateMarkState(model: model!)
                     }
-                    self?.noteReplyHanddler.unMarkAnnotation(anno)
-                    self?.noteOutlineView.reloadItem(model)
                 }
             }
             cell.isUnFoldNote = { [weak self] cellNote, isUnfold in
-                // 将折叠状态记录到模型
-                model?.foldType = isUnfold  ? .unfold : .fold
-                
-                model?.footerModel?.isExpand = isUnfold
-                model?.isExpand = isUnfold
-                self?.noteOutlineView.reloadData()
-                DispatchQueue.main.async {
-                    if let row = self?.noteOutlineView.row(forItem: item) {
-                        self?.noteOutlineView.scrollRowToVisible(row)
-                    }
+                if model != nil {
+                    self?.updateExpand(model: model!, isExpand: isUnfold, item: item)
                 }
             }
             return cell
@@ -882,9 +1071,27 @@ extension KMLeftSideViewController: NSOutlineViewDelegate, NSOutlineViewDataSour
             let itemView = KMBotaTableRowView()
             if let data = item as? KMBotaAnnotationBaseModel {
                 itemView.isSelected = data.isSelected
-                
-                
             }
+            let rowIndexes = self.noteOutlineView.selectedRowIndexes
+
+            itemView.rightMouseCallback = { [weak self] (view, event) in
+                if let data = item as? KMBotaAnnotationFooterModel {
+                    
+                } else {
+                    if !KMOCToolClass.arrayContains(array: self?.selectedObjcNotes(), annotation: item) ||
+                        self?.selectedObjcNotes().count == 1 {
+                        let index = self?.noteOutlineView.row(forItem: item)
+                        self?.noteOutlineView.selectRowIndexes(IndexSet(integer: IndexSet.Element(index ?? 0)), byExtendingSelection: false)
+                    }
+                    
+                    let row = outlineView.row(forItem: item)
+                    if outlineView.rowView(atRow: row, makeIfNecessary: false) != nil {
+                        let rowView = outlineView.rowView(atRow: row, makeIfNecessary: false)
+                        self?.showRightGropView(raw: row, event: event, view: rowView,item: item)
+                    }
+                }
+            }
+            
             itemView.selectCallback = { theView in
                 let isSelected = theView.isSelected
                 
@@ -930,37 +1137,12 @@ extension KMLeftSideViewController: NSOutlineViewDelegate, NSOutlineViewDataSour
     
     func outlineView(_ outlineView: NSOutlineView, selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet) -> IndexSet {
         if outlineView.isEqual(to: self.noteOutlineView) {
-            var indexs = proposedSelectionIndexes
             for i in proposedSelectionIndexes {
                 let item = self.noteOutlineView.item(atRow: i)
-                var model: KMBotaAnnotationModel?
-                if let data = item as? KMBotaAnnotationSectionModel {
-                    
-                }
-                if let data = item as? KMBotaAnnotationModel {
-                    model = data
-                }
-                if let data = item as? KMBotaAnnotationReplyModel {
-                    model = data.annoModel
-                }
                 if let data = item as? KMBotaAnnotationFooterModel {
-                    model = data.annoModel
-                }
-                
-                if let data = model {
-                    let row = self.noteOutlineView.row(forItem: data)
-                    indexs.insert(row)
-                    var i = 1
-                    if data.isExpand {
-                        for item in data.replyAnnos {
-                            indexs.insert(row+i)
-                            i += 1
-                        }
-                    }
-                    indexs.insert(row+i)
+                    return IndexSet()
                 }
             }
-            return indexs
         }
         return proposedSelectionIndexes
     }
@@ -1321,6 +1503,159 @@ extension KMLeftSideViewController: ComponentGroupDelegate {
                 removeAllAnnotations(nil)
             } else if menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_DeleteRep {
                 removeAllReplyAnnotations(nil)
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_EditNote) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        let model = models.first
+                        if model != nil {
+                            updateExpand(model: model!, isExpand: true, item: currentItem)
+                            noteReplyHanddler.editAnnotation(annotationModel: model!)
+                            DispatchQueue.main.async {
+                                let row = self.noteOutlineView.row(forItem: model?.footerModel)
+                                self.noteOutlineView.scrollRowToVisible(row)
+                            }
+                            self.noteOutlineView.reloadData()
+                        }
+                    }
+                } else if let anModels = menuItemProperty?.representedObject as? [KMBotaAnnotationReplyModel] {
+                    if anModels.first != nil {
+                        let model = anModels.first
+                        noteReplyHanddler.editReplyAnnotation(replyModel: model)
+                        DispatchQueue.main.async {
+                             let row = self.noteOutlineView.row(forItem: model?.annoModel?.footerModel)
+                            self.noteOutlineView.scrollRowToVisible(row)
+                        }
+                        self.noteOutlineView.reloadData()
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_AddRep) {
+                if let anModels = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if anModels.first != nil {
+                        if let model = anModels.first {
+                            self.updateExpand(model: model, isExpand: true, item: currentItem)
+                            if let footMode = model.footerModel {
+                                let row = self.noteOutlineView.row(forItem: footMode)
+                                let rowView = self.noteOutlineView.rowView(atRow: row, makeIfNecessary: true)
+                                if(row != nil) {
+                                    for subview in rowView!.subviews {
+                                        if let cell = subview as? KMNoteFooterCellView {
+                                            cell.inputTextF.becomeFirstResponder()
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_AddMark) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        updateMarkState(model: models.first!)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_RepStateNone) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        updateReplaState(model:models.first! , state:.none)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_RepStateAccepted) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        updateReplaState(model:models.first! , state:.accepted)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_RepStateRejected) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        updateReplaState(model:models.first! , state:.rejected)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_RepStateCancelled) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        updateReplaState(model:models.first! , state:.canceled)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_RepStateCompleted) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        updateReplaState(model:models.first! , state:.completed)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == PDFViewMenuIdentifier_Normal_ShowPopUI) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        let model = models.first
+                        updateExpand(model: model!, isExpand: !(model?.isExpand == true), item: currentItem)
+                    }
+                }
+            } else if (menuItemProperty?.identifier == PDFViewMenuIdentifier_Normal_Copy) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationReplyModel] {
+                    if models.first != nil {
+                        let model = models.first
+                        let an = model?.anno
+                        var copyText:String = ""
+                        if an?.isKind(of: CPDFMarkupAnnotation.self) == true {
+                            if let markupAn = an as? CPDFMarkupAnnotation {
+                                copyText = markupAn.markupContent()
+                            }
+                        } else if an?.isKind(of: CPDFFreeTextAnnotation.self) == true ||
+                                  an?.isKind(of: CPDFTextAnnotation.self) == true {
+                            copyText = an?.contents ?? ""
+                            let pboard = NSPasteboard.general
+                            if copyText.isEmpty == false {
+                                pboard.clearContents()
+                                pboard.writeObjects([copyText as NSPasteboardWriting])
+                            }
+                        }
+                    }
+                }
+            } else if (menuItemProperty?.identifier == PDFViewMenuIdentifier_Normal_Delete) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationModel] {
+                    if models.first != nil {
+                        let model = models.first
+                        self.outlineView(self.noteOutlineView, deleteItems:[model!])
+                    }
+                }
+            } else if (menuItemProperty?.identifier == PDFViewMenuIdentifier_Normal_CopyText) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationReplyModel] {
+                    if models.first != nil {
+                        let model = models.first
+                        
+                        var copyText:String = ""
+                        copyText = model?.replyAnno?.contents ?? ""
+                        let pboard = NSPasteboard.general
+                        if copyText.isEmpty == false {
+                            pboard.clearContents()
+                            pboard.writeObjects([copyText as NSPasteboardWriting])
+                        }
+                    }
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_DeleteMuteRep) {
+                if let models = menuItemProperty?.representedObject as? [Any] {
+                    for i in 0 ..< models.count {
+                        let model = models[i]
+                        if let replyModel = model as? KMBotaAnnotationReplyModel {
+                            noteReplyHanddler.removeReplyAnnotation(replyModel.replyAnno)
+                            replyModel.annoModel?.replyAnnos.removeObject(replyModel)
+                        } else if let anModel = model as? KMBotaAnnotationModel {
+                            self.outlineView(self.noteOutlineView, deleteItems:[anModel])
+                        }
+                    }
+                    self.noteOutlineView.reloadData()
+                }
+            } else if (menuItemProperty?.identifier == BOTAMenuIdentifier_Annotation_DeleteSignRep) {
+                if let models = menuItemProperty?.representedObject as? [KMBotaAnnotationReplyModel] {
+                    if models.first != nil {
+                        let model = models.first
+                        if model != nil {
+                            noteReplyHanddler.removeReplyAnnotation(model?.replyAnno)
+                            model?.annoModel?.replyAnnos.removeObject(model!)
+                        }
+                        self.noteOutlineView.reloadData()
+                    }
+                }
             }
         }
     }

+ 2 - 0
PDF Office/PDF Master/KMClass/Left/Annotaion/Model/KMAnnotationModel.swift

@@ -55,6 +55,8 @@ class KMBotaAnnotationFooterModel: KMBotaAnnotationBaseModel {
     
     weak var replyModel: KMBotaAnnotationReplyModel?
     
+    weak var editAnnoModel: KMBotaAnnotationModel?
+
     var inputContent: String?
     
     var isFirstResp = false

+ 24 - 0
PDF Office/PDF Master/KMClass/Left/Annotaion/View/KMBotaTableRowView.swift

@@ -8,9 +8,14 @@
 import Cocoa
 import KMComponentLibrary
 
+typealias KMAnnOutlineRowViewRightMouseCallback = (_ view: KMBotaTableRowView, _ event: NSEvent) -> Void
+
 class KMBotaTableRowView: NSTableRowView {
     var selectCallback: ((KMBotaTableRowView)->Void)?
+    var rightMouseCallback: KMAnnOutlineRowViewRightMouseCallback?
     
+    var contentBox: KMBox?
+
     convenience init() {
         self.init(frame: .zero)
         
@@ -19,6 +24,8 @@ class KMBotaTableRowView: NSTableRowView {
 
     override func draw(_ dirtyRect: NSRect) {
         super.draw(dirtyRect)
+     
+        addBox()
 
         // Drawing code here.
     }
@@ -28,6 +35,23 @@ class KMBotaTableRowView: NSTableRowView {
         self.addTrackingArea(trackingArea)
     }
     
+    func addBox() {
+        if self.contentBox == nil {
+            let rect = self.bounds
+            self.contentBox?.wantsLayer = true
+            self.contentBox = KMBox(frame: rect)
+            self.contentBox?.borderWidth = 0
+            self.contentBox?.boxType = .custom
+            self.contentBox?.autoresizingMask = [.width, .height]
+            self.contentBox?.rightDownCallback = { [unowned self] (downEntered, mouseBox, event) in
+                guard let callBack = rightMouseCallback else { return }
+                
+                callBack(self, event)
+            }
+        }
+        self.addSubview(contentBox!)
+    }
+    
     override func drawSelection(in dirtyRect: NSRect) {
         let selectionRect = self.bounds
         let color = ComponentLibrary.shared.getComponentColorFromKey("colorPrimary/bg-opacity-dark")

+ 1 - 1
PDF Office/PDF Master/KMClass/Left/Annotaion/View/KMNoteFooterCellView.swift

@@ -112,7 +112,7 @@ class KMNoteFooterCellView: NSTableCellView, NibLoadable {
         self.inputRespButton_.frame = self.inputBox.contentView?.bounds ?? .zero
         self.inputRespButton_.autoresizingMask = [.width, .height]
 
-        self.replyButton.title = KMLocalizedString("Reply")
+        self.replyButton.title = KMLocalizedString("Done")
         self.replyButton.wantsLayer = true
 
         self.replyButtonBox.cornerRadius = 1