[console] Rely on QgsCodeEditorWidget search functionality

Remove duplicate code searching functionality from console script
editor and just use the standard QgsCodeEditorWidget implementation
This commit is contained in:
Nyall Dawson 2024-05-09 11:12:50 +10:00
parent 4854779200
commit 64e0fff67f
6 changed files with 164 additions and 170 deletions

View File

@ -43,6 +43,11 @@ Ownership of ``editor`` will be transferred to this widget.
QgsCodeEditor *editor();
%Docstring
Returns the wrapped code editor.
%End
bool isSearchBarVisible() const;
%Docstring
Returns ``True`` if the search bar is visible.
%End
public slots:
@ -72,6 +77,21 @@ Sets whether the search bar is ``visible``.
.. seealso:: :py:func:`showSearchBar`
.. seealso:: :py:func:`hideSearchBar`
%End
void triggerFind();
%Docstring
Triggers a find operation, using the default behavior.
This will automatically open the search bar and start a find operation using
the default behavior, e.g. searching for any selected text in the code editor.
%End
signals:
void searchBarToggled( bool visible );
%Docstring
Emitted when the visibility of the search bar is changed.
%End
};

View File

@ -177,7 +177,6 @@ class PythonConsoleWidget(QWidget):
self.splitterObj.setOrientation(Qt.Orientation.Horizontal)
self.widgetEditor = QWidget(self.splitterObj)
self.widgetFind = QWidget(self)
self.listClassMethod = QTreeWidget(self.splitterObj)
self.listClassMethod.setColumnCount(2)
@ -189,8 +188,6 @@ class PythonConsoleWidget(QWidget):
# Hide side editor on start up
self.splitterObj.hide()
self.listClassMethod.hide()
# Hide search widget on start up
self.widgetFind.hide()
icon_size = iface.iconSize(dockedToolbar=True) if iface else QSize(16, 16)
@ -318,16 +315,24 @@ class PythonConsoleWidget(QWidget):
self.objectListButton.setIconVisibleInMenu(True)
self.objectListButton.setToolTip(objList)
self.objectListButton.setText(objList)
# Action for Find text
findText = QCoreApplication.translate("PythonConsole", "Find Text")
self.findTextButton = QAction(self)
self.findTextButton.setCheckable(True)
self.findTextButton.setEnabled(True)
self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"))
self.findTextButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.findTextButton.setIconVisibleInMenu(True)
self.findTextButton.setToolTip(findText)
self.findTextButton.setText(findText)
self.find_text_action = QAction(self)
self.find_text_action.setCheckable(True)
self.find_text_action.setEnabled(True)
self.find_text_action.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"))
self.find_text_action.setMenuRole(QAction.MenuRole.PreferencesRole)
self.find_text_action.setIconVisibleInMenu(True)
self.find_text_action.setToolTip(findText)
self.find_text_action.setText(findText)
self.tabEditorWidget.search_bar_toggled.connect(
self.find_text_action.setChecked
)
self.find_text_action.toggled.connect(
self.tabEditorWidget.toggle_search_bar
)
# ----------------Toolbar Console-------------------------------------
@ -434,7 +439,7 @@ class PythonConsoleWidget(QWidget):
self.toolBarEditor.addAction(self.copyEditorButton)
self.toolBarEditor.addAction(self.pasteEditorButton)
self.toolBarEditor.addSeparator()
self.toolBarEditor.addAction(self.findTextButton)
self.toolBarEditor.addAction(self.find_text_action)
self.toolBarEditor.addSeparator()
self.toolBarEditor.addAction(self.toggleCommentEditorButton)
self.toolBarEditor.addAction(self.reformatCodeEditorButton)
@ -480,47 +485,6 @@ class PythonConsoleWidget(QWidget):
self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1)
self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1)
self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1)
self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1)
# Layout for the find widget
self.layoutFind = QGridLayout(self.widgetFind)
self.layoutFind.setContentsMargins(0, 0, 0, 0)
self.lineEditFind = QgsFilterLineEdit()
self.lineEditFind.setShowSearchIcon(True)
placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find…")
self.lineEditFind.setPlaceholderText(placeHolderTxt)
self.toolBarFindText = QToolBar()
self.toolBarFindText.setIconSize(icon_size)
self.findNextButton = QAction(self)
self.findNextButton.setEnabled(False)
toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next")
self.findNextButton.setToolTip(toolTipfindNext)
self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.svg"))
self.findPrevButton = QAction(self)
self.findPrevButton.setEnabled(False)
toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous")
self.findPrevButton.setToolTip(toolTipfindPrev)
self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.svg"))
self.caseSensitive = QCheckBox()
caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive")
self.caseSensitive.setText(caseSensTr)
self.wholeWord = QCheckBox()
wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word")
self.wholeWord.setText(wholeWordTr)
self.wrapAround = QCheckBox()
self.wrapAround.setChecked(True)
wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around")
self.wrapAround.setText(wrapAroundTr)
self.toolBarFindText.addWidget(self.lineEditFind)
self.toolBarFindText.addAction(self.findPrevButton)
self.toolBarFindText.addAction(self.findNextButton)
self.toolBarFindText.addWidget(self.caseSensitive)
self.toolBarFindText.addWidget(self.wholeWord)
self.toolBarFindText.addWidget(self.wrapAround)
self.layoutFind.addWidget(self.toolBarFindText, 0, 1, 1, 1)
# ------------ Add first Tab in Editor -------------------------------
@ -528,7 +492,6 @@ class PythonConsoleWidget(QWidget):
# ------------ Signal -------------------------------
self.findTextButton.triggered.connect(self._toggleFind)
self.objectListButton.toggled.connect(self.toggleObjectListWidget)
self.toggleCommentEditorButton.triggered.connect(self.toggleComment)
self.reformatCodeEditorButton.triggered.connect(self.reformatCode)
@ -548,27 +511,6 @@ class PythonConsoleWidget(QWidget):
self.helpAPIAction.triggered.connect(self.openHelpAPI)
self.helpCookbookAction.triggered.connect(self.openHelpCookbook)
self.listClassMethod.itemClicked.connect(self.onClickGoToLine)
self.lineEditFind.returnPressed.connect(self._findNext)
self.findNextButton.triggered.connect(self._findNext)
self.findPrevButton.triggered.connect(self._findPrev)
self.lineEditFind.textChanged.connect(self._textFindChanged)
self.findScut = QShortcut(QKeySequence.StandardKey.Find, self.widgetEditor)
self.findScut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
self.findScut.activated.connect(self._openFind)
self.findNextScut = QShortcut(QKeySequence.StandardKey.FindNext, self.widgetEditor)
self.findNextScut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
self.findNextScut.activated.connect(self._findNext)
self.findPreviousScut = QShortcut(QKeySequence.StandardKey.FindPrevious, self.widgetEditor)
self.findPreviousScut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
self.findPreviousScut.activated.connect(self._findPrev)
# Escape on editor hides the find bar
self.findScut = QShortcut(Qt.Key.Key_Escape, self.widgetEditor)
self.findScut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
self.findScut.activated.connect(self._closeFind)
if iface is not None:
self.exit_blocker = ConsoleExitBlocker(self)
@ -601,28 +543,6 @@ class PythonConsoleWidget(QWidget):
def _toggleFind(self):
self.tabEditorWidget.currentWidget().toggleFindWidget()
def _openFind(self):
self.tabEditorWidget.currentWidget().openFindWidget()
def _closeFind(self):
self.tabEditorWidget.currentWidget().closeFindWidget()
def _findNext(self):
self.tabEditorWidget.currentWidget().findText(True)
def _findPrev(self):
self.tabEditorWidget.currentWidget().findText(False)
def _textFindChanged(self):
if self.lineEditFind.text():
self.findNextButton.setEnabled(True)
self.findPrevButton.setEnabled(True)
self.tabEditorWidget.currentWidget().findText(True, showMessage=False, findFirst=True)
else:
self.lineEditFind.setStyleSheet('')
self.findNextButton.setEnabled(False)
self.findPrevButton.setEnabled(False)
def onClickGoToLine(self, item, column):
tabEditor = self.tabEditorWidget.currentWidget()
if item.text(1) == 'syntaxError':

View File

@ -39,7 +39,18 @@ from qgis.gui import (
)
from qgis.PyQt.Qsci import QsciScintilla
from qgis.PyQt.QtCore import QByteArray, QCoreApplication, QDir, QEvent, QFileInfo, QJsonDocument, QSize, Qt, QUrl
from qgis.PyQt.QtCore import (
pyqtSignal,
QByteArray,
QCoreApplication,
QDir,
QEvent,
QFileInfo,
QJsonDocument,
QSize,
Qt,
QUrl
)
from qgis.PyQt.QtGui import QKeySequence
from qgis.PyQt.QtNetwork import QNetworkRequest
from qgis.PyQt.QtWidgets import (
@ -64,6 +75,8 @@ from qgis.utils import OverrideCursor, iface
class Editor(QgsCodeEditorPython):
trigger_find = pyqtSignal()
def __init__(self,
editor_tab: 'EditorTab',
console_widget: 'PythonConsoleWidget',
@ -165,7 +178,7 @@ class Editor(QgsCodeEditorPython):
QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Find Text"),
menu)
find_action.triggered.connect(self.openFindWidget)
find_action.triggered.connect(self.trigger_find)
menu.addAction(find_action)
cutAction = QAction(
@ -253,44 +266,6 @@ class Editor(QgsCodeEditorPython):
showCodeInspection.setEnabled(True)
menu.exec(self.mapToGlobal(e.pos()))
def findText(self, forward, showMessage=True, findFirst=False):
lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
if findFirst:
line = 0
index = 0
else:
line, index = self.getCursorPosition()
text = self.console_widget.lineEditFind.text()
re = False
wrap = self.console_widget.wrapAround.isChecked()
cs = self.console_widget.caseSensitive.isChecked()
wo = self.console_widget.wholeWord.isChecked()
notFound = False
if text:
if not forward:
line = lineFrom
index = indexFrom
# findFirst(QString(), re bool, cs bool, wo bool, wrap, bool, forward=True)
# re = Regular Expression, cs = Case Sensitive, wo = Whole Word, wrap = Wrap Around
if not self.findFirst(text, re, cs, wo, wrap, forward, line, index):
notFound = True
if notFound:
styleError = 'QLineEdit {background-color: #d65253; \
color: #ffffff;}'
if showMessage:
msgText = QCoreApplication.translate('PythonConsole',
'<b>"{0}"</b> was not found.').format(text)
self.showMessage(msgText)
else:
styleError = ''
self.console_widget.lineEditFind.setStyleSheet(styleError)
def findNext(self):
self.findText(True)
def findPrevious(self):
self.findText(False)
def objectListEditor(self):
listObj = self.console_widget.listClassMethod
if listObj.isVisible():
@ -343,26 +318,6 @@ class Editor(QgsCodeEditorPython):
self.console_widget.splitterObj.hide()
self.console_widget.showEditorButton.setChecked(False)
def openFindWidget(self):
wF = self.console_widget.widgetFind
wF.show()
if self.hasSelectedText():
self.console_widget.lineEditFind.setText(self.selectedText().strip())
self.console_widget.lineEditFind.setFocus()
self.console_widget.findTextButton.setChecked(True)
def closeFindWidget(self):
wF = self.console_widget.widgetFind
wF.hide()
self.console_widget.findTextButton.setChecked(False)
def toggleFindWidget(self):
wF = self.console_widget.widgetFind
if wF.isVisible():
self.closeFindWidget()
else:
self.openFindWidget()
def createTempFile(self):
name = tempfile.NamedTemporaryFile(delete=False).name
# Need to use newline='' to avoid adding extra \r characters on Windows
@ -568,6 +523,8 @@ class Editor(QgsCodeEditorPython):
class EditorTab(QWidget):
search_bar_toggled = pyqtSignal(bool)
def __init__(self,
tab_widget: 'EditorTabWidget',
console_widget: 'PythonConsoleWidget',
@ -583,6 +540,13 @@ class EditorTab(QWidget):
self._editor_code_widget = QgsCodeEditorWidget(
self._editor
)
self._editor_code_widget.searchBarToggled.connect(
self.search_bar_toggled
)
self._editor.trigger_find.connect(
self._editor_code_widget.triggerFind
)
if filename:
if QFileInfo(filename).exists():
@ -606,6 +570,24 @@ class EditorTab(QWidget):
def modified(self, modified):
self.tab_widget.tabModified(self, modified)
def search_bar_visible(self) -> bool:
"""
Returns True if the tab's search bar is visible
"""
return self._editor_code_widget.isSearchBarVisible()
def trigger_find(self):
"""
Triggers a find operation using the default behavior
"""
self._editor_code_widget.triggerFind()
def hide_search_bar(self):
"""
Hides the search bar
"""
self._editor_code_widget.hideSearchBar()
def close(self):
self.tab_widget._removeTab(self, tab2index=True)
@ -629,6 +611,8 @@ class EditorTab(QWidget):
class EditorTabWidget(QTabWidget):
search_bar_toggled = pyqtSignal(bool)
def __init__(self, console_widget: 'PythonConsoleWidget'):
super().__init__(parent=None)
self.console_widget: 'PythonConsoleWidget' = console_widget
@ -725,6 +709,19 @@ class EditorTabWidget(QTabWidget):
self.changeLastDirPath(tab)
self.enableSaveIfModified(tab)
self.search_bar_toggled.emit(
self.currentWidget().search_bar_visible()
)
def toggle_search_bar(self, visible: bool):
"""
Toggles whether the search bar should be visible
"""
if visible and not self.currentWidget().search_bar_visible():
self.currentWidget().trigger_find()
elif not visible and self.currentWidget().search_bar_visible():
self.currentWidget().hide_search_bar()
def contextMenuEvent(self, e):
tabBar = self.tabBar()
self.idx = tabBar.tabAt(e.pos())
@ -822,6 +819,14 @@ class EditorTabWidget(QTabWidget):
else:
self.setTabToolTip(self.currentIndex(), tabName)
tab.search_bar_toggled.connect(self._tab_search_bar_toggled)
def _tab_search_bar_toggled(self, visible: bool):
if self.sender() != self.currentWidget():
return
self.search_bar_toggled.emit(visible)
def tabModified(self, tab, modified):
index = self.indexOf(tab)
s = self.tabText(index)

View File

@ -43,6 +43,11 @@ Ownership of ``editor`` will be transferred to this widget.
QgsCodeEditor *editor();
%Docstring
Returns the wrapped code editor.
%End
bool isSearchBarVisible() const;
%Docstring
Returns ``True`` if the search bar is visible.
%End
public slots:
@ -72,6 +77,21 @@ Sets whether the search bar is ``visible``.
.. seealso:: :py:func:`showSearchBar`
.. seealso:: :py:func:`hideSearchBar`
%End
void triggerFind();
%Docstring
Triggers a find operation, using the default behavior.
This will automatically open the search bar and start a find operation using
the default behavior, e.g. searching for any selected text in the code editor.
%End
signals:
void searchBarToggled( bool visible );
%Docstring
Emitted when the visibility of the search bar is changed.
%End
};

View File

@ -76,19 +76,7 @@ QgsCodeEditorWidget::QgsCodeEditorWidget( QgsCodeEditor *editor, QWidget *parent
QShortcut *findShortcut = new QShortcut( QKeySequence::StandardKey::Find, mEditor );
findShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
connect( findShortcut, &QShortcut::activated, this, [this]
{
clearSearchHighlights();
mLineEditFind->setFocus();
if ( mEditor->hasSelectedText() )
{
mBlockSearching++;
mLineEditFind->setText( mEditor->selectedText().trimmed() );
mBlockSearching--;
}
mLineEditFind->selectAll();
showSearchBar();
} );
connect( findShortcut, &QShortcut::activated, this, &QgsCodeEditorWidget::triggerFind );
QShortcut *findNextShortcut = new QShortcut( QKeySequence::StandardKey::FindNext, this );
findNextShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
@ -133,16 +121,23 @@ QgsCodeEditorWidget::QgsCodeEditorWidget( QgsCodeEditor *editor, QWidget *parent
setLayout( vl );
}
bool QgsCodeEditorWidget::isSearchBarVisible() const
{
return !mFindWidget->isHidden();
}
void QgsCodeEditorWidget::showSearchBar()
{
addSearchHighlights();
mFindWidget->show();
emit searchBarToggled( true );
}
void QgsCodeEditorWidget::hideSearchBar()
{
clearSearchHighlights();
mFindWidget->hide();
emit searchBarToggled( false );
}
void QgsCodeEditorWidget::setSearchBarVisible( bool visible )
@ -153,6 +148,20 @@ void QgsCodeEditorWidget::setSearchBarVisible( bool visible )
hideSearchBar();
}
void QgsCodeEditorWidget::triggerFind()
{
clearSearchHighlights();
mLineEditFind->setFocus();
if ( mEditor->hasSelectedText() )
{
mBlockSearching++;
mLineEditFind->setText( mEditor->selectedText().trimmed() );
mBlockSearching--;
}
mLineEditFind->selectAll();
showSearchBar();
}
void QgsCodeEditorWidget::findNext()
{
findText( true, false );

View File

@ -59,6 +59,11 @@ class GUI_EXPORT QgsCodeEditorWidget : public QgsPanelWidget
*/
QgsCodeEditor *editor() { return mEditor; }
/**
* Returns TRUE if the search bar is visible.
*/
bool isSearchBarVisible() const;
public slots:
/**
@ -85,6 +90,21 @@ class GUI_EXPORT QgsCodeEditorWidget : public QgsPanelWidget
*/
void setSearchBarVisible( bool visible );
/**
* Triggers a find operation, using the default behavior.
*
* This will automatically open the search bar and start a find operation using
* the default behavior, e.g. searching for any selected text in the code editor.
*/
void triggerFind();
signals:
/**
* Emitted when the visibility of the search bar is changed.
*/
void searchBarToggled( bool visible );
private slots:
void findNext();