Moved the search bar code into a new class

This commit is contained in:
Veronica K. B. Olsen
2020-06-15 21:36:04 +02:00
parent 7374d0513e
commit bbb0f5f9dd
4 changed files with 180 additions and 189 deletions
-2
View File
@@ -2,7 +2,6 @@
from nw.gui.about import GuiAbout from nw.gui.about import GuiAbout
from nw.gui.build import GuiBuildNovel from nw.gui.build import GuiBuildNovel
from nw.gui.docbars import GuiSearchBar
from nw.gui.doceditor import GuiDocEditor from nw.gui.doceditor import GuiDocEditor
from nw.gui.docmerge import GuiDocMerge from nw.gui.docmerge import GuiDocMerge
from nw.gui.docsplit import GuiDocSplit from nw.gui.docsplit import GuiDocSplit
@@ -23,7 +22,6 @@ from nw.gui.theme import GuiIcons, GuiTheme
__all__ = [ __all__ = [
"GuiAbout", "GuiAbout",
"GuiBuildNovel", "GuiBuildNovel",
"GuiSearchBar",
"GuiDocEditor", "GuiDocEditor",
"GuiDocMerge", "GuiDocMerge",
"GuiDocSplit", "GuiDocSplit",
-168
View File
@@ -1,168 +0,0 @@
# -*- coding: utf-8 -*-
"""novelWriter GUI Main Window SearchBar
novelWriter GUI Main Window SearchBar
=========================================
Class holding the main window search bar
File History:
Created: 2019-09-29 [0.2.1] GuiSearchBar
This file is a part of novelWriter
Copyright 2020, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
import nw
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QPalette, QColor, QIcon
from PyQt5.QtWidgets import (
qApp, QWidget, QFrame, QGridLayout, QLabel, QLineEdit, QPushButton,
QHBoxLayout, QToolButton, QScrollArea
)
from nw.constants import nwDocAction, nwUnicode
logger = logging.getLogger(__name__)
class GuiSearchBar(QWidget):
def __init__(self, theParent):
QWidget.__init__(self, theParent)
logger.debug("Initialising GuiSearchBar ...")
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
self.repVisible = False
self.setContentsMargins(0, 0, 0, 0)
self.mainBox = QGridLayout(self)
self.setLayout(self.mainBox)
self.searchBox = QLineEdit()
self.replaceBox = QLineEdit()
self.searchLabel = QLabel("Search")
self.replaceLabel = QLabel("Replace")
self.closeButton = QPushButton(self.theTheme.getIcon("close"),"")
self.searchButton = QPushButton(self.theTheme.getIcon("search"),"")
self.replaceButton = QPushButton(self.theTheme.getIcon("search-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(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)
self.mainBox.setColumnStretch(2, 0)
self.mainBox.setColumnStretch(3, 0)
self.mainBox.setColumnStretch(4, 0)
self.mainBox.setContentsMargins(0, 0, 0, 0)
boxWidth = 16*self.theTheme.textNWidth
self.searchBox.setMinimumWidth(boxWidth)
self.replaceBox.setMinimumWidth(boxWidth)
self._replaceVisible(False)
logger.debug("GuiSearchBar initialisation complete")
return
##
# Get and Set Functions
##
def setSearchText(self, theText):
"""Open the search bar and set the search text to the text
provided, if any.
"""
if not self.isVisible():
self.setVisible(True)
self.searchBox.setText(theText)
self.searchBox.setFocus()
logger.verbose("Setting search text to '%s'" % theText)
return True
def setReplaceText(self, theText):
"""Set the replace text.
"""
self._replaceVisible(True)
self.replaceBox.setFocus()
self.replaceBox.setText(theText)
return True
def getSearchText(self):
"""Return the current search text.
"""
return self.searchBox.text()
def getReplaceText(self):
"""Return the current replace text.
"""
return self.replaceBox.text()
##
# Internal Functions
##
def _doClose(self):
"""Hide the search/replace bar.
"""
self._replaceVisible(False)
self.setVisible(False)
return
def _doSearch(self):
"""Call the search action function for the document editor.
"""
modKey = qApp.keyboardModifiers()
if modKey == Qt.ShiftModifier:
self.theParent.docEditor.docAction(nwDocAction.GO_PREV)
else:
self.theParent.docEditor.docAction(nwDocAction.GO_NEXT)
return
def _doReplace(self):
"""Call the replace action function for the document editor.
"""
self.theParent.docEditor.docAction(nwDocAction.REPL_NEXT)
return
def _replaceVisible(self, isVisible):
"""Set the visibility of all the replace widgets.
"""
self.replaceLabel.setVisible(isVisible)
self.replaceBox.setVisible(isVisible)
self.replaceButton.setVisible(isVisible)
self.repVisible = isVisible
return True
# END Class GuiSearchBar
+176 -13
View File
@@ -6,9 +6,11 @@
Class holding the document editor Class holding the document editor
File History: File History:
Created: 2018-09-29 [0.0.1] GuiDocEditor Created: 2018-09-29 [0.0.1] GuiDocEditor
Created: 2019-04-22 [0.0.1] BackgroundWordCounter Created: 2019-04-22 [0.0.1] BackgroundWordCounter
Created: 2020-04-25 [0.4.5] GuiDocEditHeader Created: 2019-09-29 [0.2.1] GuiDocEditSearch
Created: 2020-04-25 [0.4.5] GuiDocEditHeader
Rewritten: 2020-06-15 [0.9.0] GuiDocEditSearch
This file is a part of novelWriter This file is a part of novelWriter
Copyright 2020, Veronica Berglyd Olsen Copyright 2020, Veronica Berglyd Olsen
@@ -39,7 +41,7 @@ from PyQt5.QtGui import (
) )
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox, QWidget, QLabel, qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox, QWidget, QLabel,
QToolButton, QHBoxLayout QToolButton, QHBoxLayout, QGridLayout, QLineEdit, QPushButton, QFrame, QVBoxLayout
) )
from nw.core import NWDoc from nw.core import NWDoc
@@ -87,6 +89,7 @@ class GuiDocEditor(QTextEdit):
# Document Title # Document Title
self.docHeader = GuiDocEditHeader(self) self.docHeader = GuiDocEditHeader(self)
self.docSearch = GuiDocEditSearch(self)
# Syntax # Syntax
self.hLight = GuiDocHighlighter(self.qDocument, self.theParent) self.hLight = GuiDocHighlighter(self.qDocument, self.theParent)
@@ -309,6 +312,7 @@ class GuiDocEditor(QTextEdit):
Config.textFixedW is enabled or we're in Zen mode. Otherwise, Config.textFixedW is enabled or we're in Zen mode. Otherwise,
just ensure the margins are set correctly. just ensure the margins are set correctly.
""" """
wW = self.width()
cM = self.mainConf.getTextMargin() cM = self.mainConf.getTextMargin()
vBar = self.verticalScrollBar() vBar = self.verticalScrollBar()
@@ -322,7 +326,6 @@ class GuiDocEditor(QTextEdit):
tW = self.mainConf.getZenWidth() tW = self.mainConf.getZenWidth()
else: else:
tW = self.mainConf.getTextWidth() tW = self.mainConf.getTextWidth()
wW = self.width()
tM = int((wW - sW - tW)/2) tM = int((wW - sW - tW)/2)
if tM < cM: if tM < cM:
tM = cM tM = cM
@@ -330,15 +333,21 @@ class GuiDocEditor(QTextEdit):
tM = cM tM = cM
tB = self.frameWidth() tB = self.frameWidth()
tW = self.width() - 2*tB - sW tW = wW - 2*tB - sW
tH = self.docHeader.height() tH = self.docHeader.height()
tT = cM - tH tT = cM - tH
rH = self.docSearch.height()
rW = self.docSearch.width()
rL = wW - sW - rW - tB
self.docHeader.setGeometry(tB, tB, tW, tH) self.docHeader.setGeometry(tB, tB, tW, tH)
self.docSearch.move(rL, tB)
self.setViewportMargins(0, tH, 0, 0) self.setViewportMargins(0, tH, 0, 0)
docFormat = self.qDocument.rootFrame().frameFormat() docFormat = self.qDocument.rootFrame().frameFormat()
docFormat.setLeftMargin(tM) docFormat.setLeftMargin(tM)
docFormat.setTopMargin(max(0, tT)) docFormat.setTopMargin(max(0, tT, rH))
# Updating root frame triggers a QTextDocument->contentsChange # Updating root frame triggers a QTextDocument->contentsChange
# signal, which we do not want as it re-runs the syntax # signal, which we do not want as it re-runs the syntax
@@ -569,6 +578,13 @@ class GuiDocEditor(QTextEdit):
)) ))
return return
def closeSearch(self):
"""Close the search box.
"""
self.docSearch.setVisible(False)
self.updateDocMargins()
return self.docSearch.isVisible()
## ##
# Document Events and Maintenance # Document Events and Maintenance
## ##
@@ -1127,7 +1143,8 @@ class GuiDocEditor(QTextEdit):
selText = theCursor.selectedText() selText = theCursor.selectedText()
else: else:
selText = "" selText = ""
self.theParent.searchBar.setSearchText(selText) self.docSearch.setSearchText(selText)
self.updateDocMargins()
return return
def _beginReplace(self): def _beginReplace(self):
@@ -1135,14 +1152,14 @@ class GuiDocEditor(QTextEdit):
text. text.
""" """
self._beginSearch() self._beginSearch()
self.theParent.searchBar.setReplaceText("") self.docSearch.setReplaceText("")
return return
def _findNext(self): def _findNext(self):
"""Searches for the next occurrence of the search bar text in """Searches for the next occurrence of the search bar text in
the document. Wraps back to the top if not found. the document. Wraps back to the top if not found.
""" """
searchFor = self.theParent.searchBar.getSearchText() searchFor = self.docSearch.getSearchText()
wasFound = self.find(searchFor) wasFound = self.find(searchFor)
if not wasFound: if not wasFound:
theCursor = self.textCursor() theCursor = self.textCursor()
@@ -1154,7 +1171,7 @@ class GuiDocEditor(QTextEdit):
"""Searches for the previous occurrence of the search bar text """Searches for the previous occurrence of the search bar text
in the document. Wraps back to the end if not found. in the document. Wraps back to the end if not found.
""" """
searchFor = self.theParent.searchBar.getSearchText() searchFor = self.docSearch.getSearchText()
wasFound = self.find(searchFor, QTextDocument.FindBackward) wasFound = self.find(searchFor, QTextDocument.FindBackward)
if not wasFound: if not wasFound:
theCursor = self.textCursor() theCursor = self.textCursor()
@@ -1168,8 +1185,8 @@ class GuiDocEditor(QTextEdit):
to the top if not found. to the top if not found.
""" """
theCursor = self.textCursor() theCursor = self.textCursor()
searchFor = self.theParent.searchBar.getSearchText() searchFor = self.docSearch.getSearchText()
replWith = self.theParent.searchBar.getReplaceText() replWith = self.docSearch.getReplaceText()
if theCursor.hasSelection() and theCursor.selectedText() == searchFor: if theCursor.hasSelection() and theCursor.selectedText() == searchFor:
xPos = theCursor.selectionStart() xPos = theCursor.selectionStart()
theCursor.beginEditBlock() theCursor.beginEditBlock()
@@ -1229,6 +1246,152 @@ class BackgroundWordCounter(QThread):
## END Class BackgroundWordCounter ## END Class BackgroundWordCounter
# =============================================================================================== #
# The Embedded Document Search/Replace Feature
# Only used by DocEditor, and is at a fixed position in the QTextEdit's viewport
# =============================================================================================== #
class GuiDocEditSearch(QWidget):
def __init__(self, docEditor):
QWidget.__init__(self, docEditor)
logger.debug("Initialising GuiDocEditSearch ...")
self.mainConf = nw.CONFIG
self.docEditor = docEditor
self.theParent = docEditor.theParent
self.theProject = docEditor.theProject
self.theTheme = docEditor.theTheme
self.repVisible = False
fPx = int(0.9*self.theTheme.fontPixelSize)
boxFont = self.theTheme.guiFont
boxFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
# self.setContentsMargins(0, 0, 0, 0)
# self.setFrameStyle(QFrame.Box)
self.setAutoFillBackground(True)
self.mainBox = QGridLayout(self)
self.setLayout(self.mainBox)
self.searchBox = QLineEdit()
self.searchBox.setFont(boxFont)
self.replaceBox = QLineEdit()
self.replaceBox.setFont(boxFont)
self.closeButton = QPushButton(self.theTheme.getIcon("close"),"")
self.searchButton = QPushButton(self.theTheme.getIcon("search"),"")
self.replaceButton = QPushButton(self.theTheme.getIcon("search-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(self.searchBox, 0, 0)
self.mainBox.addWidget(self.searchButton, 0, 1)
self.mainBox.addWidget(self.closeButton, 0, 2)
self.mainBox.addWidget(self.replaceBox, 1, 0)
self.mainBox.addWidget(self.replaceButton, 1, 1)
self.mainBox.setColumnStretch(0, 1)
self.mainBox.setColumnStretch(1, 0)
self.mainBox.setColumnStretch(2, 0)
self.mainBox.setColumnStretch(3, 0)
self.mainBox.setColumnStretch(4, 0)
self.mainBox.setVerticalSpacing(0)
self.mainBox.setHorizontalSpacing(2)
# self.mainBox.setContentsMargins(0, 0, 0, 0)
boxWidth = 16*self.theTheme.textNWidth
self.searchBox.setFixedWidth(boxWidth)
self.replaceBox.setFixedWidth(boxWidth)
# self._replaceVisible(False)
logger.debug("GuiDocEditSearch initialisation complete")
return
##
# Get and Set Functions
##
def setSearchText(self, theText):
"""Open the search bar and set the search text to the text
provided, if any.
"""
if not self.isVisible():
self.setVisible(True)
self.searchBox.setText(theText)
self.searchBox.setFocus()
logger.verbose("Setting search text to '%s'" % theText)
return True
def setReplaceText(self, theText):
"""Set the replace text.
"""
self._replaceVisible(True)
self.replaceBox.setFocus()
self.replaceBox.setText(theText)
return True
def getSearchText(self):
"""Return the current search text.
"""
return self.searchBox.text()
def getReplaceText(self):
"""Return the current replace text.
"""
return self.replaceBox.text()
##
# Slots
##
def _doClose(self):
"""Hide the search/replace bar.
"""
self._replaceVisible(False)
self.docEditor.closeSearch()
return
def _doSearch(self):
"""Call the search action function for the document editor.
"""
modKey = qApp.keyboardModifiers()
if modKey == Qt.ShiftModifier:
self.docEditor.docAction(nwDocAction.GO_PREV)
else:
self.docEditor.docAction(nwDocAction.GO_NEXT)
return
def _doReplace(self):
"""Call the replace action function for the document editor.
"""
self.docEditor.docAction(nwDocAction.REPL_NEXT)
return
##
# Internal Functions
##
def _replaceVisible(self, isVisible):
"""Set the visibility of all the replace widgets.
"""
self.replaceBox.setVisible(isVisible)
self.replaceButton.setVisible(isVisible)
self.repVisible = isVisible
return True
# END Class GuiDocEditSearch
# =============================================================================================== # # =============================================================================================== #
# The Embedded Document Header # The Embedded Document Header
# Only used by DocEditor, and is at a fixed position in the QTextEdit's viewport # Only used by DocEditor, and is at a fixed position in the QTextEdit's viewport
+4 -6
View File
@@ -43,7 +43,7 @@ from nw.gui import (
GuiBuildNovel, GuiDocEditor, GuiDocMerge, GuiDocSplit, GuiDocViewDetails, GuiBuildNovel, GuiDocEditor, GuiDocMerge, GuiDocSplit, GuiDocViewDetails,
GuiDocViewer, GuiItemDetails, GuiItemEditor, GuiMainMenu, GuiMainStatus, GuiDocViewer, GuiItemDetails, GuiItemEditor, GuiMainMenu, GuiMainStatus,
GuiOutline, GuiOutlineDetails, GuiPreferences, GuiProjectLoad, GuiOutline, GuiOutlineDetails, GuiPreferences, GuiProjectLoad,
GuiProjectSettings, GuiProjectTree, GuiSearchBar, GuiSessionLogView, GuiTheme GuiProjectSettings, GuiProjectTree, GuiSessionLogView, GuiTheme
) )
from nw.core import NWProject, NWDoc, NWIndex from nw.core import NWProject, NWDoc, NWIndex
from nw.constants import nwFiles, nwItemType, nwAlert from nw.constants import nwFiles, nwItemType, nwAlert
@@ -93,7 +93,6 @@ class GuiMain(QMainWindow):
self.docEditor = GuiDocEditor(self) self.docEditor = GuiDocEditor(self)
self.viewMeta = GuiDocViewDetails(self) self.viewMeta = GuiDocViewDetails(self)
self.docViewer = GuiDocViewer(self) self.docViewer = GuiDocViewer(self)
self.searchBar = GuiSearchBar(self)
self.treeMeta = GuiItemDetails(self) self.treeMeta = GuiItemDetails(self)
self.projView = GuiOutline(self) self.projView = GuiOutline(self)
self.projMeta = GuiOutlineDetails(self) self.projMeta = GuiOutlineDetails(self)
@@ -115,7 +114,6 @@ class GuiMain(QMainWindow):
self.docEdit = QVBoxLayout() self.docEdit = QVBoxLayout()
self.docEdit.setContentsMargins(0, 0, 0, 0) self.docEdit.setContentsMargins(0, 0, 0, 0)
self.docEdit.setSpacing(self.mainConf.pxInt(2)) self.docEdit.setSpacing(self.mainConf.pxInt(2))
self.docEdit.addWidget(self.searchBar)
self.docEdit.addWidget(self.docEditor) self.docEdit.addWidget(self.docEditor)
self.editPane.setLayout(self.docEdit) self.editPane.setLayout(self.docEdit)
@@ -168,7 +166,7 @@ class GuiMain(QMainWindow):
self.splitView.setCollapsible(self.idxViewMeta, False) self.splitView.setCollapsible(self.idxViewMeta, False)
self.splitView.setVisible(False) self.splitView.setVisible(False)
self.searchBar.setVisible(False) self.docEditor.closeSearch()
# Build the Tree View # Build the Tree View
self.treeView.itemSelectionChanged.connect(self._treeSingleClick) self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
@@ -1075,8 +1073,8 @@ class GuiMain(QMainWindow):
"""When the escape key is pressed somewhere in the main window, """When the escape key is pressed somewhere in the main window,
do the following, in order: do the following, in order:
""" """
if self.searchBar.isVisible(): if self.docEditor.docSearch.isVisible():
self.searchBar.setVisible(False) self.docEditor.closeSearch()
return return
elif self.isZenMode: elif self.isZenMode:
self.toggleZenMode() self.toggleZenMode()