From 7c60d9e9fd4ed2bf5d60afcf964ac8e6582225d6 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 29 Sep 2019 15:39:35 +0200 Subject: [PATCH 1/3] Added searchbar class --- nw/gui/searchbar.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 nw/gui/searchbar.py diff --git a/nw/gui/searchbar.py b/nw/gui/searchbar.py new file mode 100644 index 00000000..90dd8c72 --- /dev/null +++ b/nw/gui/searchbar.py @@ -0,0 +1,34 @@ +# -*- 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] + +""" + +import logging +import nw + +from PyQt5.QtWidgets import QFrame + +logger = logging.getLogger(__name__) + +class GuiSearchBar(QFrame): + + def __init__(self, theParent): + + logger.debug("Initialising GuiSearchBar ...") + + self.mainConf = nw.CONFIG + self.theParent = theParent + self.refTime = None + + logger.debug("GuiSearchBar initialisation complete") + + return + +# END Class GuiSearchBar From 1bf539d4906e40f1cf20b41ce3c6da3cbc3602f0 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 29 Sep 2019 17:16:17 +0200 Subject: [PATCH 2/3] Basic search feature now works, but needs more tweaking --- nw/enum.py | 2 ++ nw/gui/docdetails.py | 2 +- nw/gui/doceditor.py | 29 +++++++++++++++++++++++++++++ nw/gui/mainmenu.py | 17 +++++++++++++++++ nw/gui/searchbar.py | 43 +++++++++++++++++++++++++++++++++++++++---- nw/gui/winmain.py | 13 +++++++++++-- 6 files changed, 99 insertions(+), 7 deletions(-) diff --git a/nw/enum.py b/nw/enum.py index 61540882..3ee73975 100644 --- a/nw/enum.py +++ b/nw/enum.py @@ -65,6 +65,8 @@ class nwDocAction(Enum): D_QUOTE = 10 SEL_ALL = 11 SEL_PARA = 12 + FIND = 13 + GO_NEXT = 14 # END Enum nwDocAction diff --git a/nw/gui/docdetails.py b/nw/gui/docdetails.py index 43c51ccd..804b43bc 100644 --- a/nw/gui/docdetails.py +++ b/nw/gui/docdetails.py @@ -60,7 +60,7 @@ class GuiDocDetails(QFrame): lblOne.setFont(self.fntOne) self.mainBox.addWidget(lblOne,nRow,0) self.mainBox.addWidget(self.colTwo[nRow],nRow,1) - + self.mainBox.setColumnStretch(0,0) self.mainBox.setColumnStretch(1,1) diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 383640ea..9e2cf7e4 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -279,6 +279,8 @@ class GuiDocEditor(QTextEdit): 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() else: logger.error("Unknown or unsupported document action %s" % str(theAction)) return False @@ -485,4 +487,31 @@ class GuiDocEditor(QTextEdit): self.setTextCursor(theCursor) return + def _beginSearch(self): + + print("Boo!") + + theCursor = self.textCursor() + if self.mainConf.autoSelect and not theCursor.hasSelection(): + theCursor.select(QTextCursor.WordUnderCursor) + if theCursor.hasSelection(): + selText = theCursor.selectedText() + else: + selText = "" + + self.theParent.searchBar.setSearchText(selText) + + if selText != "": + self._findNext() + + return + + def _findNext(self): + + searchFor = self.theParent.searchBar.getSearchText() + self.find(searchFor) + + return + + # END Class GuiDocEditor diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py index 155fc5a3..7280a617 100644 --- a/nw/gui/mainmenu.py +++ b/nw/gui/mainmenu.py @@ -398,6 +398,23 @@ class GuiMainMenu(QMenuBar): # Edit > Separator self.editMenu.addSeparator() + # Edit > Find + menuItem = QAction(QIcon.fromTheme("edit-find"), "Find", self) + menuItem.setStatusTip("Find text in document") + menuItem.setShortcut("Ctrl+F") + menuItem.triggered.connect(lambda: self._docAction(nwDocAction.FIND)) + self.editMenu.addAction(menuItem) + + # Edit > Find Next + menuItem = QAction(QIcon.fromTheme("go-right"), "Go Next", self) + menuItem.setStatusTip("Find next occurrence text in document") + menuItem.setShortcut("F3") + menuItem.triggered.connect(lambda: self._docAction(nwDocAction.GO_NEXT)) + self.editMenu.addAction(menuItem) + + # Edit > Separator + self.editMenu.addSeparator() + # Edit > Select All menuItem = QAction(QIcon.fromTheme("edit-select-all"), "Select All", self) menuItem.setStatusTip("Select all text in document") diff --git a/nw/gui/searchbar.py b/nw/gui/searchbar.py index 90dd8c72..ea8ef748 100644 --- a/nw/gui/searchbar.py +++ b/nw/gui/searchbar.py @@ -13,22 +13,57 @@ import logging import nw -from PyQt5.QtWidgets import QFrame +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QLineEdit, QPushButton logger = logging.getLogger(__name__) class GuiSearchBar(QFrame): def __init__(self, theParent): + QFrame.__init__(self, theParent) logger.debug("Initialising GuiSearchBar ...") - self.mainConf = nw.CONFIG - self.theParent = theParent - self.refTime = None + self.mainConf = nw.CONFIG + self.theParent = theParent + + self.setContentsMargins(0,0,0,0) + + self.mainBox = QGridLayout(self) + self.setLayout(self.mainBox) + + self.searchBox = QLineEdit() + self.searchButton = QPushButton(QIcon.fromTheme("edit-find"),"") + + 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.setColumnStretch(0,1) + self.mainBox.setColumnStretch(1,0) + self.mainBox.setColumnStretch(2,0) + self.mainBox.setColumnStretch(3,0) + self.mainBox.setContentsMargins(0,0,0,0) logger.debug("GuiSearchBar initialisation complete") return + def setSearchText(self, theText): + + if not self.isVisible(): + self.setVisible(True) + + self.searchBox.setText(theText) + self.searchBox.setFocus(True) + + logger.debug("Setting search text to '%s'" % theText) + + return True + + def getSearchText(self): + return self.searchBox.text() + # END Class GuiSearchBar diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index 7884da83..c39aa6f5 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -26,6 +26,7 @@ from nw.gui.doctree import GuiDocTree from nw.gui.doceditor import GuiDocEditor from nw.gui.docviewer import GuiDocViewer from nw.gui.docdetails import GuiDocDetails +from nw.gui.searchbar import GuiSearchBar from nw.gui.mainmenu import GuiMainMenu from nw.gui.configeditor import GuiConfigEditor from nw.gui.projecteditor import GuiProjectEditor @@ -69,6 +70,7 @@ class GuiMain(QMainWindow): self.docEditor = GuiDocEditor(self, self.theProject) self.docViewer = GuiDocViewer(self, self.theProject) self.docDetails = GuiDocDetails(self, self.theProject) + self.searchBar = GuiSearchBar(self) self.treeView = GuiDocTree(self, self.theProject) self.mainMenu = GuiMainMenu(self, self.theProject) @@ -83,8 +85,14 @@ class GuiMain(QMainWindow): self.treeBox.addWidget(self.docDetails) self.treePane.setLayout(self.treeBox) + self.docPane = QFrame() + self.docView = QVBoxLayout() + self.docView.addWidget(self.searchBar) + self.docView.addWidget(self.docEditor) + self.docPane.setLayout(self.docView) + self.splitView = QSplitter(Qt.Horizontal) - self.splitView.addWidget(self.docEditor) + self.splitView.addWidget(self.docPane) self.splitView.addWidget(self.docViewer) self.splitView.splitterMoved.connect(self._splitViewMove) @@ -98,7 +106,7 @@ class GuiMain(QMainWindow): self.idxTree = self.splitMain.indexOf(self.treePane) self.idxMain = self.splitMain.indexOf(self.splitView) - self.idxEditor = self.splitView.indexOf(self.docEditor) + self.idxEditor = self.splitView.indexOf(self.docPane) self.idxViewer = self.splitView.indexOf(self.docViewer) self.splitMain.setCollapsible(self.idxTree, False) @@ -107,6 +115,7 @@ class GuiMain(QMainWindow): self.splitView.setCollapsible(self.idxViewer, True) self.docViewer.setVisible(False) + self.searchBar.setVisible(False) # Build The Tree View self.treeView.itemSelectionChanged.connect(self._treeSingleClick) From cb2ee95d1065c4ce0a6a9965dcaeb5c0c7a557d7 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 29 Sep 2019 18:50:43 +0200 Subject: [PATCH 3/3] Simple search function now working --- nw/enum.py | 1 + nw/gui/doceditor.py | 23 +++++++++++++++-------- nw/gui/mainmenu.py | 9 ++++++++- nw/gui/searchbar.py | 26 +++++++++++++++++++++++--- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/nw/enum.py b/nw/enum.py index 3ee73975..54fee904 100644 --- a/nw/enum.py +++ b/nw/enum.py @@ -67,6 +67,7 @@ class nwDocAction(Enum): SEL_PARA = 12 FIND = 13 GO_NEXT = 14 + GO_PREV = 15 # END Enum nwDocAction diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 9e2cf7e4..7f1466fc 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -17,7 +17,7 @@ from time import time from PyQt5.QtCore import Qt, QTimer, QSizeF from PyQt5.QtWidgets import QTextEdit, QAction, QMenu, QShortcut -from PyQt5.QtGui import QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette +from PyQt5.QtGui import QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette, QTextDocument from nw.project.document import NWDoc from nw.gui.dochighlight import GuiDocHighlighter @@ -281,6 +281,7 @@ class GuiDocEditor(QTextEdit): 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() else: logger.error("Unknown or unsupported document action %s" % str(theAction)) return False @@ -489,11 +490,7 @@ class GuiDocEditor(QTextEdit): def _beginSearch(self): - print("Boo!") - theCursor = self.textCursor() - if self.mainConf.autoSelect and not theCursor.hasSelection(): - theCursor.select(QTextCursor.WordUnderCursor) if theCursor.hasSelection(): selText = theCursor.selectedText() else: @@ -507,11 +504,21 @@ class GuiDocEditor(QTextEdit): return def _findNext(self): - searchFor = self.theParent.searchBar.getSearchText() - self.find(searchFor) - + wasFound = self.find(searchFor) + if not wasFound: + theCursor = self.textCursor() + theCursor.movePosition(QTextCursor.Start) + self.setTextCursor(theCursor) return + def _findPrev(self): + searchFor = self.theParent.searchBar.getSearchText() + wasFound = self.find(searchFor, QTextDocument.FindBackward) + if not wasFound: + theCursor = self.textCursor() + theCursor.movePosition(QTextCursor.End) + self.setTextCursor(theCursor) + return # END Class GuiDocEditor diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py index 7280a617..f1c1a6d1 100644 --- a/nw/gui/mainmenu.py +++ b/nw/gui/mainmenu.py @@ -406,12 +406,19 @@ class GuiMainMenu(QMenuBar): self.editMenu.addAction(menuItem) # Edit > Find Next - menuItem = QAction(QIcon.fromTheme("go-right"), "Go Next", self) + menuItem = QAction(QIcon.fromTheme("go-next"), "Go Next", self) menuItem.setStatusTip("Find next occurrence text in document") menuItem.setShortcut("F3") menuItem.triggered.connect(lambda: self._docAction(nwDocAction.GO_NEXT)) self.editMenu.addAction(menuItem) + # Edit > Find Prev + menuItem = QAction(QIcon.fromTheme("go-previous"), "Go Previous", self) + menuItem.setStatusTip("Find previous occurrence text in document") + menuItem.setShortcut("Shift+F3") + menuItem.triggered.connect(lambda: self._docAction(nwDocAction.GO_PREV)) + self.editMenu.addAction(menuItem) + # Edit > Separator self.editMenu.addSeparator() diff --git a/nw/gui/searchbar.py b/nw/gui/searchbar.py index ea8ef748..f88de328 100644 --- a/nw/gui/searchbar.py +++ b/nw/gui/searchbar.py @@ -16,6 +16,8 @@ import nw from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QLineEdit, QPushButton +from nw.enum import nwDocAction + logger = logging.getLogger(__name__) class GuiSearchBar(QFrame): @@ -34,17 +36,23 @@ class GuiSearchBar(QFrame): self.setLayout(self.mainBox) self.searchBox = QLineEdit() + self.closeButton = QPushButton(QIcon.fromTheme("edit-delete"),"") self.searchButton = QPushButton(QIcon.fromTheme("edit-find"),"") - self.mainBox.addWidget(QLabel(""),0,0) - self.mainBox.addWidget(QLabel("Search"),0,1) - self.mainBox.addWidget(self.searchBox,0,2) + self.closeButton.clicked.connect(self._doClose) + self.searchButton.clicked.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.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) logger.debug("GuiSearchBar initialisation complete") @@ -66,4 +74,16 @@ class GuiSearchBar(QFrame): def getSearchText(self): return self.searchBox.text() + ## + # Internal Functions + ## + + def _doClose(self): + self.setVisible(False) + return + + def _doSearch(self): + self.theParent.docEditor.docAction(nwDocAction.GO_NEXT) + return + # END Class GuiSearchBar