Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Find in Workbox feature #11

Merged
merged 2 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[report]
show_missing = false
skip_covered = true
skip_empty = true

[run]
# Ensure all python modules in preditor have their coverage reported,
# not just files that pytest touches.
source = preditor
omit =
*/site-packages/*
relative_files=True
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