|
@@ -44,15 +44,23 @@ class KMSearchReplaceWindowController: NSWindowController {
|
|
|
@IBOutlet weak var nextButton: NSButton!
|
|
|
|
|
|
@IBOutlet weak var replaceBox: NSBox!
|
|
|
+ @IBOutlet weak var replaceTitleLabel: NSTextField!
|
|
|
+ @IBOutlet weak var replaceInputBox: NSBox!
|
|
|
+ @IBOutlet weak var replaceInputView: NSTextField!
|
|
|
+
|
|
|
@IBOutlet weak var bottomBarBox: NSBox!
|
|
|
@IBOutlet weak var replaceButton: NSButton!
|
|
|
@IBOutlet weak var replaceAllButton: NSButton!
|
|
|
|
|
|
+ var replaceCallback: (() -> Void)?
|
|
|
+
|
|
|
private var _modalSession: NSApplication.ModalSession?
|
|
|
|
|
|
private var handdler: KMSearchReplaceHanddler = KMSearchReplaceHanddler()
|
|
|
private var type_: KMSearchReplaceType = .search
|
|
|
|
|
|
+ private var currentSel: CPDFSelection?
|
|
|
+
|
|
|
deinit {
|
|
|
KMPrint("KMSearchReplaceWindowController deinit.")
|
|
|
}
|
|
@@ -112,8 +120,20 @@ class KMSearchReplaceWindowController: NSWindowController {
|
|
|
self.nextButton.target = self
|
|
|
self.nextButton.action = #selector(_nextAction)
|
|
|
|
|
|
+ self.replaceBox.borderWidth = 0
|
|
|
+ self.replaceTitleLabel.stringValue = NSLocalizedString("Replace", comment: "")
|
|
|
+ self.replaceInputBox.cornerRadius = 0
|
|
|
+ self.replaceInputView.drawsBackground = false
|
|
|
+ self.replaceInputView.isBordered = false
|
|
|
+ self.replaceInputView.delegate = self
|
|
|
+
|
|
|
+ self.bottomBarBox.borderWidth = 0
|
|
|
self.replaceButton.title = NSLocalizedString("Replace", comment: "")
|
|
|
+ self.replaceButton.target = self
|
|
|
+ self.replaceButton.action = #selector(_replaceAction)
|
|
|
self.replaceAllButton.title = NSLocalizedString("Replace All", comment: "")
|
|
|
+ self.replaceAllButton.target = self
|
|
|
+ self.replaceAllButton.action = #selector(_replaceAllAction)
|
|
|
}
|
|
|
|
|
|
// MARK: - Actions
|
|
@@ -123,19 +143,85 @@ class KMSearchReplaceWindowController: NSWindowController {
|
|
|
}
|
|
|
|
|
|
@objc private func _previousAction(_ sender: NSButton) {
|
|
|
- guard let model = self.handdler.searchResults.safe_element(for: self.handdler.showIdx+1) as? KMSearchMode else {
|
|
|
- return
|
|
|
+ let isEditing = self.handdler.pdfView?.isEditing() ?? false
|
|
|
+ if isEditing == false {
|
|
|
+ guard let model = self.handdler.searchResults.safe_element(for: self.handdler.showIdx+1) as? KMSearchMode else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.handdler.showIdx += 1
|
|
|
+ self.handdler.showSelection(model.selection)
|
|
|
+ } else {
|
|
|
+ if let _ = self.currentSel {
|
|
|
+ self.currentSel = self.handdler.pdfView?.document.findForwardEditText()
|
|
|
+ if let sel = self.currentSel {
|
|
|
+ self.handdler.showSelection(sel)
|
|
|
+ } else {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.messageText = NSLocalizedString("The search item was not found.", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
+ alert.runModal()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let searchS = self.searchInputView.stringValue
|
|
|
+ let opt = self.fetchSearchOptions()
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ let datas = self.handdler.pdfView?.document.startFindEditText(from: nil, with: searchS, options: opt)
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ let sel = datas?.first?.first
|
|
|
+ if sel == nil {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.messageText = NSLocalizedString("The search item was not found.", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.currentSel = sel
|
|
|
+ self.handdler.showSelection(sel)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- self.handdler.showIdx += 1
|
|
|
- self.handdler.showSelection(model.selection)
|
|
|
}
|
|
|
|
|
|
@objc private func _nextAction(_ sender: NSButton) {
|
|
|
- guard let model = self.handdler.searchResults.safe_element(for: self.handdler.showIdx-1) as? KMSearchMode else {
|
|
|
- return
|
|
|
+ let isEditing = self.handdler.pdfView?.isEditing() ?? false
|
|
|
+ if isEditing == false {
|
|
|
+ guard let model = self.handdler.searchResults.safe_element(for: self.handdler.showIdx-1) as? KMSearchMode else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.handdler.showIdx -= 1
|
|
|
+ self.handdler.showSelection(model.selection)
|
|
|
+ } else {
|
|
|
+ if let _ = self.currentSel {
|
|
|
+ self.currentSel = self.handdler.pdfView?.document.findBackwordEditText()
|
|
|
+ if let sel = self.currentSel {
|
|
|
+ self.handdler.showSelection(sel)
|
|
|
+ } else {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.messageText = NSLocalizedString("The search item was not found.", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
+ alert.runModal()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let searchS = self.searchInputView.stringValue
|
|
|
+ let opt = self.fetchSearchOptions()
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ let datas = self.handdler.pdfView?.document.startFindEditText(from: nil, with: searchS, options: opt)
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ let sel = datas?.first?.first
|
|
|
+ if sel == nil {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.messageText = NSLocalizedString("The search item was not found.", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.currentSel = sel
|
|
|
+ self.handdler.showSelection(sel)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- self.handdler.showIdx -= 1
|
|
|
- self.handdler.showSelection(model.selection)
|
|
|
}
|
|
|
|
|
|
@objc private func _searchTabAction(_ sender: NSButton) {
|
|
@@ -146,6 +232,84 @@ class KMSearchReplaceWindowController: NSWindowController {
|
|
|
self.switchType(.replace, animate: true)
|
|
|
}
|
|
|
|
|
|
+ @objc private func _replaceAction(_ sender: NSButton) {
|
|
|
+ let isEditing = self.handdler.pdfView?.isEditing() ?? false
|
|
|
+ if isEditing == false {
|
|
|
+ NSSound.beep()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if let sel = self.currentSel {
|
|
|
+ let searchS = self.searchInputView.stringValue
|
|
|
+ let replaceS = self.replaceInputView.stringValue
|
|
|
+ let success = self.handdler.replace(searchS: searchS, replaceS: replaceS, sel: sel) { [weak self] newSel in
|
|
|
+ self?.handdler.showSelection(newSel)
|
|
|
+ }
|
|
|
+ if success {
|
|
|
+ self.handdler.showSelection(sel)
|
|
|
+ }
|
|
|
+ } else { // 先查找
|
|
|
+ let searchS = self.searchInputView.stringValue
|
|
|
+ let opt = self.fetchSearchOptions()
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ let datas = self.handdler.pdfView?.document.startFindEditText(from: nil, with: searchS, options: opt)
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ let sel = datas?.first?.first
|
|
|
+ if sel == nil {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.messageText = NSLocalizedString("The search item was not found.", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
+ alert.runModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.currentSel = sel
|
|
|
+ self.handdler.showSelection(sel)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc private func _replaceAllAction(_ sender: NSButton) {
|
|
|
+ let isEditing = self.handdler.pdfView?.isEditing() ?? false
|
|
|
+ if isEditing == false {
|
|
|
+ NSSound.beep()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let datas = self.handdler.pdfView?.document.findEditSelections() ?? []
|
|
|
+ if datas.isEmpty {
|
|
|
+ let alert = NSAlert()
|
|
|
+ alert.informativeText = NSLocalizedString("The search item was not found.", comment: "")
|
|
|
+ alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
|
+ alert.beginSheetModal(for: NSApp.mainWindow!)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let searchS = self.searchInputView.stringValue
|
|
|
+ let replaceS = self.replaceInputView.stringValue
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ self.handdler.pdfView?.document.replaceAllEditText(with: searchS, toReplace: replaceS)
|
|
|
+ self.currentSel = nil
|
|
|
+
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.handdler.pdfView?.setHighlightedSelection(nil, animated: false)
|
|
|
+ self.handdler.pdfView?.setNeedsDisplayForVisiblePages()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func fetchSearchOptions() -> CPDFSearchOptions {
|
|
|
+ var opt = CPDFSearchOptions()
|
|
|
+ let isCase = self.caseSensitiveCheck.state == .on
|
|
|
+ if isCase {
|
|
|
+ opt.insert(.caseSensitive)
|
|
|
+ }
|
|
|
+ let isWholeWord = self.matchWholeCheck.state == .on
|
|
|
+ if isWholeWord {
|
|
|
+ opt.insert(.matchWholeWord)
|
|
|
+ }
|
|
|
+ return opt
|
|
|
+ }
|
|
|
+
|
|
|
func switchType(_ type: KMSearchReplaceType, animate: Bool = false) {
|
|
|
if type == .replace {
|
|
|
if IAPProductsManager.default().isAvailableAllFunction() == false {
|
|
@@ -200,6 +364,9 @@ class KMSearchReplaceWindowController: NSWindowController {
|
|
|
self.window?.setFrame(frame, display: true, animate: animate)
|
|
|
self.window?.minSize = frame.size
|
|
|
self.window?.maxSize = frame.size
|
|
|
+
|
|
|
+ // 将事件回调出去
|
|
|
+ self.replaceCallback?()
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -233,6 +400,22 @@ extension KMSearchReplaceWindowController: NSTextFieldDelegate {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ func controlTextDidChange(_ obj: Notification) {
|
|
|
+ if self.searchInputView.isEqual(to: obj.object) { // 搜索输入框
|
|
|
+ if self.searchInputView.stringValue.isEmpty {
|
|
|
+ self.previousButton.isEnabled = false
|
|
|
+ self.nextButton.isEnabled = false
|
|
|
+ self.replaceButton.isEnabled = false
|
|
|
+ self.replaceAllButton.isEnabled = false
|
|
|
+ } else {
|
|
|
+ self.previousButton.isEnabled = true
|
|
|
+ self.nextButton.isEnabled = true
|
|
|
+ self.replaceButton.isEnabled = true
|
|
|
+ self.replaceAllButton.isEnabled = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
|
|
|
switch commandSelector {
|
|
|
case #selector(NSResponder.insertNewline(_:)):
|