Merge pull request #51 from vkbo/replace

Extend search feature to allow replace as well
This commit is contained in:
Veronica K. Berglyd Olsen
2019-10-06 15:41:25 +02:00
committed by GitHub
5 changed files with 133 additions and 35 deletions
+4 -2
View File
@@ -66,8 +66,10 @@ class nwDocAction(Enum):
SEL_ALL = 11
SEL_PARA = 12
FIND = 13
GO_NEXT = 14
GO_PREV = 15
REPLACE = 14
GO_NEXT = 15
GO_PREV = 16
REPL_NEXT = 17
# END Enum nwDocAction
+48 -21
View File
@@ -267,21 +267,23 @@ class GuiDocEditor(QTextEdit):
if not self.theParent.hasProject:
logger.error("No project open")
return False
if theAction == nwDocAction.UNDO: self.undo()
elif theAction == nwDocAction.REDO: self.redo()
elif theAction == nwDocAction.CUT: self.cut()
elif theAction == nwDocAction.COPY: self.copy()
elif theAction == nwDocAction.PASTE: self.paste()
elif theAction == nwDocAction.BOLD: self._wrapSelection("**","**")
elif theAction == nwDocAction.ITALIC: self._wrapSelection("_","_")
elif theAction == nwDocAction.U_LINE: self._wrapSelection("__","__")
elif theAction == nwDocAction.S_QUOTE: self._wrapSelection(self.typSQOpen,self.typSQClose)
elif theAction == nwDocAction.D_QUOTE: self._wrapSelection(self.typDQOpen,self.typDQClose)
elif theAction == nwDocAction.SEL_ALL: self._makeSelection(QTextCursor.Document)
elif theAction == nwDocAction.SEL_PARA: self._makeSelection(QTextCursor.BlockUnderCursor)
elif theAction == nwDocAction.FIND: self._beginSearch()
elif theAction == nwDocAction.GO_NEXT: self._findNext()
elif theAction == nwDocAction.GO_PREV: self._findPrev()
if theAction == nwDocAction.UNDO: self.undo()
elif theAction == nwDocAction.REDO: self.redo()
elif theAction == nwDocAction.CUT: self.cut()
elif theAction == nwDocAction.COPY: self.copy()
elif theAction == nwDocAction.PASTE: self.paste()
elif theAction == nwDocAction.BOLD: self._wrapSelection("**","**")
elif theAction == nwDocAction.ITALIC: self._wrapSelection("_","_")
elif theAction == nwDocAction.U_LINE: self._wrapSelection("__","__")
elif theAction == nwDocAction.S_QUOTE: self._wrapSelection(self.typSQOpen,self.typSQClose)
elif theAction == nwDocAction.D_QUOTE: self._wrapSelection(self.typDQOpen,self.typDQClose)
elif theAction == nwDocAction.SEL_ALL: self._makeSelection(QTextCursor.Document)
elif theAction == nwDocAction.SEL_PARA: self._makeSelection(QTextCursor.BlockUnderCursor)
elif theAction == nwDocAction.FIND: self._beginSearch()
elif theAction == nwDocAction.REPLACE: self._beginReplace()
elif theAction == nwDocAction.GO_NEXT: self._findNext()
elif theAction == nwDocAction.GO_PREV: self._findPrev()
elif theAction == nwDocAction.REPL_NEXT: self._replaceNext()
else:
logger.error("Unknown or unsupported document action %s" % str(theAction))
return False
@@ -489,21 +491,26 @@ class GuiDocEditor(QTextEdit):
return
def _beginSearch(self):
"""Sets the selected text as the search text for the search bar.
"""
theCursor = self.textCursor()
if theCursor.hasSelection():
selText = theCursor.selectedText()
else:
selText = ""
self.theParent.searchBar.setSearchText(selText)
return
if selText != "":
self._findNext()
def _beginReplace(self):
"""Opens the replace line of the search bar and sets the replace text.
"""
self.theParent.searchBar.setReplaceText("")
return
def _findNext(self):
"""Searches for the next occurrence of the search bar text in the document.
Wraps back to the top if not found.
"""
searchFor = self.theParent.searchBar.getSearchText()
wasFound = self.find(searchFor)
if not wasFound:
@@ -513,12 +520,32 @@ class GuiDocEditor(QTextEdit):
return
def _findPrev(self):
"""Searches for the previous occurrence of the search bar text in the document.
Wraps back to the end if not found.
"""
searchFor = self.theParent.searchBar.getSearchText()
wasFound = self.find(searchFor, QTextDocument.FindBackward)
wasFound = self.find(searchFor, QTextDocument.FindBackward)
if not wasFound:
theCursor = self.textCursor()
theCursor.movePosition(QTextCursor.End)
self.setTextCursor(theCursor)
return
def _replaceNext(self):
"""Searches for the next occurrence of the search bar text in the document and replaces it
with the replace text. Wraps back to the top if not found.
"""
theCursor = self.textCursor()
replWith = self.theParent.searchBar.getReplaceText()
if theCursor.hasSelection():
xPos = theCursor.selectionStart()
theCursor.beginEditBlock()
theCursor.removeSelectedText()
theCursor.insertText(replWith)
theCursor.endEditBlock()
theCursor.setPosition(xPos)
self.setTextCursor(theCursor)
self._findNext()
return
# END Class GuiDocEditor
+14
View File
@@ -405,6 +405,13 @@ class GuiMainMenu(QMenuBar):
menuItem.triggered.connect(lambda: self._docAction(nwDocAction.FIND))
self.editMenu.addAction(menuItem)
# Edit > Replace
menuItem = QAction(QIcon.fromTheme("edit-find-replace"), "Replace", self)
menuItem.setStatusTip("Replace text in document")
menuItem.setShortcut("Ctrl+H")
menuItem.triggered.connect(lambda: self._docAction(nwDocAction.REPLACE))
self.editMenu.addAction(menuItem)
# Edit > Find Next
menuItem = QAction(QIcon.fromTheme("go-next"), "Go Next", self)
menuItem.setStatusTip("Find next occurrence text in document")
@@ -419,6 +426,13 @@ class GuiMainMenu(QMenuBar):
menuItem.triggered.connect(lambda: self._docAction(nwDocAction.GO_PREV))
self.editMenu.addAction(menuItem)
# Edit > Replace Next
menuItem = QAction(QIcon.fromTheme("go-next"), "Replace Next", self)
menuItem.setStatusTip("Find and replace next occurrence text in document")
menuItem.setShortcut("Ctrl+Shift+1")
menuItem.triggered.connect(lambda: self._docAction(nwDocAction.REPL_NEXT))
self.editMenu.addAction(menuItem)
# Edit > Separator
self.editMenu.addSeparator()
+58 -12
View File
@@ -13,8 +13,9 @@
import logging
import nw
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QLineEdit, QPushButton
from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QLineEdit, QPushButton, QApplication
from nw.enum import nwDocAction
@@ -27,26 +28,37 @@ class GuiSearchBar(QFrame):
logger.debug("Initialising GuiSearchBar ...")
self.mainConf = nw.CONFIG
self.theParent = theParent
self.mainConf = nw.CONFIG
self.theParent = theParent
self.repVisible = False
self.setContentsMargins(0,0,0,0)
self.mainBox = QGridLayout(self)
self.setLayout(self.mainBox)
self.searchBox = QLineEdit()
self.closeButton = QPushButton(QIcon.fromTheme("edit-delete"),"")
self.searchButton = QPushButton(QIcon.fromTheme("edit-find"),"")
self.searchBox = QLineEdit()
self.replaceBox = QLineEdit()
self.searchLabel = QLabel("Search")
self.replaceLabel = QLabel("Replace")
self.closeButton = QPushButton(QIcon.fromTheme("edit-delete"),"")
self.searchButton = QPushButton(QIcon.fromTheme("edit-find"),"")
self.replaceButton = QPushButton(QIcon.fromTheme("edit-find-replace"),"")
self.closeButton.clicked.connect(self._doClose)
self.searchButton.clicked.connect(self._doSearch)
self.replaceButton.clicked.connect(self._doReplace)
self.searchBox.returnPressed.connect(self._doSearch)
self.replaceBox.returnPressed.connect(self._doSearch)
self.mainBox.addWidget(QLabel(""), 0,0)
self.mainBox.addWidget(QLabel("Search"), 0,1)
self.mainBox.addWidget(self.searchBox, 0,2)
self.mainBox.addWidget(self.searchButton,0,3)
self.mainBox.addWidget(self.closeButton, 0,4)
self.mainBox.addWidget(QLabel(""), 0,0)
self.mainBox.addWidget(self.searchLabel, 0,1)
self.mainBox.addWidget(self.searchBox, 0,2)
self.mainBox.addWidget(self.searchButton, 0,3)
self.mainBox.addWidget(self.closeButton, 0,4)
self.mainBox.addWidget(self.replaceLabel, 1,1)
self.mainBox.addWidget(self.replaceBox, 1,2)
self.mainBox.addWidget(self.replaceButton, 1,3)
self.mainBox.setColumnStretch(0,1)
self.mainBox.setColumnStretch(1,0)
@@ -55,10 +67,19 @@ class GuiSearchBar(QFrame):
self.mainBox.setColumnStretch(4,0)
self.mainBox.setContentsMargins(0,0,0,0)
self.searchBox.setMinimumWidth(180)
self.replaceBox.setMinimumWidth(180)
self._replaceVisible(False)
logger.debug("GuiSearchBar initialisation complete")
return
##
# Get and Set Functions
##
def setSearchText(self, theText):
if not self.isVisible():
@@ -71,19 +92,44 @@ class GuiSearchBar(QFrame):
return True
def setReplaceText(self, theText):
self._replaceVisible(True)
self.replaceBox.setFocus(True)
self.replaceBox.setText(theText)
return True
def getSearchText(self):
return self.searchBox.text()
def getReplaceText(self):
return self.replaceBox.text()
##
# Internal Functions
##
def _doClose(self):
self._replaceVisible(False)
self.setVisible(False)
return
def _doSearch(self):
self.theParent.docEditor.docAction(nwDocAction.GO_NEXT)
modKey = QApplication.keyboardModifiers()
if modKey == Qt.ShiftModifier:
self.theParent.docEditor.docAction(nwDocAction.GO_PREV)
else:
self.theParent.docEditor.docAction(nwDocAction.GO_NEXT)
return
def _doReplace(self):
self.theParent.docEditor.docAction(nwDocAction.REPL_NEXT)
return
def _replaceVisible(self, isVisible):
self.replaceLabel.setVisible(isVisible)
self.replaceBox.setVisible(isVisible)
self.replaceButton.setVisible(isVisible)
self.repVisible = isVisible
return True
# END Class GuiSearchBar
+9
View File
@@ -137,6 +137,7 @@ class GuiMain(QMainWindow):
# Keyboard Shortcuts
QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn)
QShortcut(Qt.Key_Escape, self, activated=self._keyPressEscape)
# Forward Functions
self.setStatus = self.statusBar.setStatus
@@ -689,6 +690,14 @@ class GuiMain(QMainWindow):
logger.verbose("Requested item %s is a folder" % tHandle)
return
def _keyPressEscape(self):
"""When the escape key is pressed somewhere in the main window, do the following, in order
"""
if self.searchBar.isVisible():
self.searchBar.setVisible(False)
return
return
def _splitMainMove(self, pWidth, pHeight):
"""Alert dependent GUI elements that the main pane splitter has been moved.
"""