Search/replace now fully implemented, although only for currently edited document
This commit is contained in:
+4
-2
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user