Skip to content

Commit

Permalink
Add TextSearch for easily searching all workboxes for text
Browse files Browse the repository at this point in the history
  • Loading branch information
MHendricks committed Mar 14, 2024
1 parent 7047908 commit d908165
Show file tree
Hide file tree
Showing 24 changed files with 1,058 additions and 3 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ repos:
- id: end-of-file-fixer
- id: requirements-txt-fixer
- id: trailing-whitespace
exclude: ^(tests/find_files/)

- repo: https://github.com/pycqa/isort
rev: 5.12.0
Expand Down
119 changes: 119 additions & 0 deletions preditor/gui/find_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
from __future__ import absolute_import, print_function

from Qt.QtCore import Qt
from Qt.QtGui import QIcon
from Qt.QtWidgets import QApplication, QShortcut, QWidget

from .. import resourcePath
from ..utils.text_search import RegexTextSearch, SimpleTextSearch
from . import loadUi


class FindFiles(QWidget):
def __init__(self, parent=None, managers=None, console=None):
super(FindFiles, self).__init__(parent=parent)
if managers is None:
managers = []
self.managers = managers
self.console = console
self.finder = None
self.match_files_count = 0

loadUi(__file__, self)

# Set the icons
self.uiCaseSensitiveBTN.setIcon(
QIcon(resourcePath("img/format-letter-case.svg"))
)
self.uiCloseBTN.setIcon(QIcon(resourcePath('img/close-thick.png')))
self.uiRegexBTN.setIcon(QIcon(resourcePath("img/regex.svg")))

# Create shortcuts
self.uiCloseSCT = QShortcut(
Qt.Key_Escape, self, context=Qt.WidgetWithChildrenShortcut
)
self.uiCloseSCT.activated.connect(self.hide)

self.uiCaseSensitiveSCT = QShortcut(
Qt.AltModifier | Qt.Key_C, self, context=Qt.WidgetWithChildrenShortcut
)
self.uiCaseSensitiveSCT.activated.connect(self.uiCaseSensitiveBTN.toggle)

self.uiRegexSCT = QShortcut(
Qt.AltModifier | Qt.Key_R, self, context=Qt.WidgetWithChildrenShortcut
)
self.uiRegexSCT.activated.connect(self.uiRegexBTN.toggle)

def activate(self):
"""Called to make this widget ready for the user to interact with."""
self.show()
self.uiFindTXT.setFocus()

def find(self):
find_text = self.uiFindTXT.text()
context = self.uiContextSPN.value()
# Create an instance of the TextSearch to use for this search
if self.uiRegexBTN.isChecked():
TextSearch = RegexTextSearch
else:
TextSearch = SimpleTextSearch
self.finder = TextSearch(
find_text, self.uiCaseSensitiveBTN.isChecked(), context=context
)
self.finder.callback_matching = self.insert_found_text
self.finder.callback_non_matching = self.insert_text

self.insert_text(self.finder.title())

self.match_files_count = 0
for manager in self.managers:
for (
editor,
group_name,
tab_name,
group_index,
tab_index,
) in manager.all_widgets():
path = "/".join((group_name, tab_name))
workbox_id = '{},{}'.format(group_index, tab_index)
self.find_in_editor(editor, path, workbox_id)

self.insert_text(
'\n{} matches in {} workboxes\n'.format(
self.finder.match_count, self.match_files_count
)
)

def find_in_editor(self, editor, path, workbox_id):
# Ensure the editor text is loaded and get its raw text
editor.__show__()
text = editor.__text__()

# Use the finder to check for matches
found = self.finder.search_text(text, path, workbox_id)
if found:
self.match_files_count += 1

def insert_found_text(self, text, workbox_id, line_num, tool_tip):
href = ', {}, {}'.format(workbox_id, line_num)
cursor = self.console.textCursor()
# Insert hyperlink
fmt = cursor.charFormat()
fmt.setAnchor(True)
fmt.setAnchorHref(href)
fmt.setFontUnderline(True)
fmt.setToolTip(tool_tip)
cursor.insertText(text, fmt)
# Show the updated text output
QApplication.instance().processEvents()

def insert_text(self, text):
cursor = self.console.textCursor()
fmt = cursor.charFormat()
fmt.setAnchor(False)
fmt.setAnchorHref('')
fmt.setFontUnderline(False)
fmt.setToolTip('')
cursor.insertText(text, fmt)
# Show the updated text output
QApplication.instance().processEvents()
28 changes: 28 additions & 0 deletions preditor/gui/loggerwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False):
)
self.uiConsoleTOOLBAR.insertSeparator(self.uiRunSelectedACT)

# Configure Find in Workboxes
self.uiFindInWorkboxesWGT.hide()
self.uiFindInWorkboxesWGT.managers.append(self.uiWorkboxTAB)
self.uiFindInWorkboxesWGT.console = self.console()

# Initial configuration of the logToFile feature
self._logToFilePath = None
self._stds = None
Expand Down Expand Up @@ -680,6 +685,12 @@ def recordPrefs(self, manual=False):
'textEditorCmdTempl': self.textEditorCmdTempl,
'currentStyleSheet': self._stylesheet,
'flash_time': self.uiConsoleTXT.flash_time,
'find_files_regex': self.uiFindInWorkboxesWGT.uiRegexBTN.isChecked(),
'find_files_cs': (
self.uiFindInWorkboxesWGT.uiCaseSensitiveBTN.isChecked()
),
'find_files_context': self.uiFindInWorkboxesWGT.uiContextSPN.value(),
'find_files_text': self.uiFindInWorkboxesWGT.uiFindTXT.text(),
}
)

Expand Down Expand Up @@ -786,6 +797,18 @@ def restorePrefs(self):
)
self.uiErrorHyperlinksACT.setChecked(pref.get('uiErrorHyperlinksACT', True))

# Find Files settings
self.uiFindInWorkboxesWGT.uiRegexBTN.setChecked(
pref.get('find_files_regex', False)
)
self.uiFindInWorkboxesWGT.uiCaseSensitiveBTN.setChecked(
pref.get('find_files_cs', False)
)
self.uiFindInWorkboxesWGT.uiContextSPN.setValue(
pref.get('find_files_context', 3)
)
self.uiFindInWorkboxesWGT.uiFindTXT.setText(pref.get('find_files_text', ''))

# External text editor filepath and command template
defaultExePath = r"C:\Program Files\Sublime Text 3\sublime_text.exe"
defaultCmd = r"{exePath} {modulePath}:{lineNum}"
Expand Down Expand Up @@ -1023,6 +1046,11 @@ def showEvent(self, event):
def show_workbox_options(self):
self.uiWorkboxSTACK.setCurrentIndex(WorkboxPages.Options)

@Slot()
def show_find_in_workboxes(self):
"""Ensure the find workboxes widget is visible and has focus."""
self.uiFindInWorkboxesWGT.activate()

@Slot()
def show_focus_name(self):
model = GroupTabListItemModel(manager=self.uiWorkboxTAB)
Expand Down
140 changes: 140 additions & 0 deletions preditor/gui/ui/find_files.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>uiFindFilesWGT</class>
<widget class="QWidget" name="uiFindFilesWGT">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>636</width>
<height>41</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="uiFindLBL">
<property name="text">
<string>Find:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="uiFindOptionsLYT">
<item>
<widget class="QToolButton" name="uiRegexBTN">
<property name="toolTip">
<string>Regex (Alt + R)</string>
</property>
<property name="text">
<string>Regex</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="uiCaseSensitiveBTN">
<property name="toolTip">
<string>Case Sensitive (Alt + C)</string>
</property>
<property name="text">
<string>Case Sensitive</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="uiContextSPN">
<property name="toolTip">
<string># of lines of context to show</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::PlusMinus</enum>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="uiFindTXT"/>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="uiFindBTN">
<property name="text">
<string>Find</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QToolButton" name="uiCloseBTN">
<property name="text">
<string>x</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>uiFindBTN</sender>
<signal>released()</signal>
<receiver>uiFindFilesWGT</receiver>
<slot>find()</slot>
<hints>
<hint type="sourcelabel">
<x>601</x>
<y>31</y>
</hint>
<hint type="destinationlabel">
<x>421</x>
<y>29</y>
</hint>
</hints>
</connection>
<connection>
<sender>uiFindTXT</sender>
<signal>returnPressed()</signal>
<receiver>uiFindFilesWGT</receiver>
<slot>find()</slot>
<hints>
<hint type="sourcelabel">
<x>488</x>
<y>23</y>
</hint>
<hint type="destinationlabel">
<x>501</x>
<y>65</y>
</hint>
</hints>
</connection>
<connection>
<sender>uiCloseBTN</sender>
<signal>released()</signal>
<receiver>uiFindFilesWGT</receiver>
<slot>hide()</slot>
<hints>
<hint type="sourcelabel">
<x>620</x>
<y>19</y>
</hint>
<hint type="destinationlabel">
<x>676</x>
<y>24</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>find()</slot>
</slots>
</ui>
Loading

0 comments on commit d908165

Please sign in to comment.