Fri, 29 Apr 2022 15:40:17 +0200
Added capability to configure use of an external "Find/Replace In Files" dialog.
--- a/eric7/Preferences/ConfigurationPages/InterfacePage.py Fri Apr 29 11:40:00 2022 +0200 +++ b/eric7/Preferences/ConfigurationPages/InterfacePage.py Fri Apr 29 15:40:17 2022 +0200 @@ -87,6 +87,10 @@ # integrated tools activation # left side + self.findReplaceCheckBox.setChecked( + Preferences.getUI("ShowFindFileWidget")) + self.findLocationCheckBox.setChecked( + Preferences.getUI("ShowFindLocationWidget")) self.templateViewerCheckBox.setChecked( Preferences.getUI("ShowTemplateViewer")) self.fileBrowserCheckBox.setChecked( @@ -184,6 +188,12 @@ # save the integrated tools activation # left side Preferences.setUI( + "ShowFindFileWidget", + self.findReplaceCheckBox.isChecked()) + Preferences.setUI( + "ShowFindLocationWidget", + self.findLocationCheckBox.isChecked()) + Preferences.setUI( "ShowTemplateViewer", self.templateViewerCheckBox.isChecked()) Preferences.setUI(
--- a/eric7/Preferences/ConfigurationPages/InterfacePage.ui Fri Apr 29 11:40:00 2022 +0200 +++ b/eric7/Preferences/ConfigurationPages/InterfacePage.ui Fri Apr 29 15:40:17 2022 +0200 @@ -433,7 +433,17 @@ <string>Left Side</string> </property> <layout class="QGridLayout" name="gridLayout_5"> - <item row="0" column="0"> + <item row="2" column="0"> + <widget class="QCheckBox" name="symbolsCheckBox"> + <property name="toolTip"> + <string>Select to activate the Symbols widget</string> + </property> + <property name="text"> + <string>Symbols</string> + </property> + </widget> + </item> + <item row="1" column="0"> <widget class="QCheckBox" name="templateViewerCheckBox"> <property name="toolTip"> <string>Select to activate the Template viewer</string> @@ -443,7 +453,7 @@ </property> </widget> </item> - <item row="0" column="1"> + <item row="1" column="1"> <widget class="QCheckBox" name="fileBrowserCheckBox"> <property name="toolTip"> <string>Select to activate the File-Browser widget</string> @@ -453,13 +463,23 @@ </property> </widget> </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="symbolsCheckBox"> + <item row="0" column="0"> + <widget class="QCheckBox" name="findReplaceCheckBox"> <property name="toolTip"> - <string>Select to activate the Symbols widget</string> + <string>Select to activate the embedded Find/Replace In Files tool.</string> </property> <property name="text"> - <string>Symbols</string> + <string>Find/Replace In Files</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="findLocationCheckBox"> + <property name="toolTip"> + <string>Select to activate the embedded Find File tool.</string> + </property> + <property name="text"> + <string>Find File</string> </property> </widget> </item> @@ -643,6 +663,8 @@ <tabstop>combinedLeftRightSidebarCheckBox</tabstop> <tabstop>languageComboBox</tabstop> <tabstop>layoutComboBox</tabstop> + <tabstop>findReplaceCheckBox</tabstop> + <tabstop>findLocationCheckBox</tabstop> <tabstop>templateViewerCheckBox</tabstop> <tabstop>fileBrowserCheckBox</tabstop> <tabstop>symbolsCheckBox</tabstop>
--- a/eric7/Preferences/__init__.py Fri Apr 29 11:40:00 2022 +0200 +++ b/eric7/Preferences/__init__.py Fri Apr 29 15:40:17 2022 +0200 @@ -142,6 +142,8 @@ "ShowTemplateViewer": True, # left side "ShowFileBrowser": True, # left side "ShowSymbolsViewer": True, # left side + "ShowFindFileWidget": True, # left side + "ShowFindLocationWidget": True, # left side "ShowCodeDocumentationViewer": True, # right side "ShowPyPIPackageManager": True, # right side "ShowCondaPackageManager": True, # right side @@ -1930,37 +1932,39 @@ @param key the key of the value to get @return the requested UI setting """ - if key in ["BrowsersListFoldersFirst", "BrowsersHideNonPublic", - "BrowsersListContentsByOccurrence", "BrowsersListHiddenFiles", - "BrowserShowCoding", "LogViewerAutoRaise", - "SingleApplicationMode", "TabViewManagerFilenameOnly", - "ShowFilePreview", "ShowFilePreviewJS", "ShowFilePreviewSSI", - "CaptionShowsFilename", "ShowSplash", - "SplitOrientationVertical", "DynamicOnlineCheck", - "UseProxy", "UseSystemProxy", "UseHttpProxyForAll", - "RequestDownloadFilename", "CheckErrorLog", - "OpenCrashSessionOnStartup", "CrashSessionEnabled", - "ShowCodeDocumentationViewer", "ShowPyPIPackageManager", - "ShowCondaPackageManager", "ShowCooperation", "ShowIrc", - "ShowTemplateViewer", "ShowFileBrowser", "ShowSymbolsViewer", - "ShowNumbersViewer", "ShowMicroPython", - "ShowInternalHelpViewer", "UseNativeMenuBar", - "CombinedLeftRightSidebar"]: + if key in [ + "BrowsersListFoldersFirst", "BrowsersHideNonPublic", + "BrowsersListContentsByOccurrence", "BrowsersListHiddenFiles", + "BrowserShowCoding", "LogViewerAutoRaise", "SingleApplicationMode", + "TabViewManagerFilenameOnly", "ShowFilePreview", "ShowFilePreviewJS", + "ShowFilePreviewSSI", "CaptionShowsFilename", "ShowSplash", + "SplitOrientationVertical", "DynamicOnlineCheck", "UseProxy", + "UseSystemProxy", "UseHttpProxyForAll", "RequestDownloadFilename", + "CheckErrorLog", "OpenCrashSessionOnStartup", "CrashSessionEnabled", + "ShowCodeDocumentationViewer", "ShowPyPIPackageManager", + "ShowCondaPackageManager", "ShowCooperation", "ShowIrc", + "ShowTemplateViewer", "ShowFileBrowser", "ShowSymbolsViewer", + "ShowNumbersViewer", "ShowMicroPython", "ShowFindFileWidget", + "ShowFindLocationWidget", "ShowInternalHelpViewer", "UseNativeMenuBar", + "CombinedLeftRightSidebar", + ]: return toBool(Prefs.settings.value( "UI/" + key, Prefs.uiDefaults[key])) - elif key in ["TabViewManagerFilenameLength", "CaptionFilenameLength", - "ProxyPort/Http", "ProxyPort/Https", "ProxyPort/Ftp", - "OpenOnStartup", "PerformVersionCheck", "RecentNumber", - "NotificationTimeout", "UpgraderDelay", - "KeyboardInputInterval", "BackgroundServiceProcesses", - "MinimumMessageTypeSeverity"]: + elif key in [ + "TabViewManagerFilenameLength", "CaptionFilenameLength", + "ProxyPort/Http", "ProxyPort/Https", "ProxyPort/Ftp", + "OpenOnStartup", "PerformVersionCheck", "RecentNumber", + "NotificationTimeout", "UpgraderDelay", "KeyboardInputInterval", + "BackgroundServiceProcesses", "MinimumMessageTypeSeverity", + ]: return int(Prefs.settings.value( "UI/" + key, Prefs.uiDefaults[key])) elif key in ["ProxyType/Ftp", ]: return EricFtpProxyType(int(Prefs.settings.value( "UI/" + key, Prefs.uiDefaults[key].value))) - elif key in ["ProxyPassword/Http", "ProxyPassword/Https", - "ProxyPassword/Ftp", ]: + elif key in [ + "ProxyPassword/Http", "ProxyPassword/Https", "ProxyPassword/Ftp", + ]: from Utilities.crypto import pwConvert return pwConvert( Prefs.settings.value("UI/" + key, Prefs.uiDefaults[key]), @@ -1999,8 +2003,10 @@ return state else: return Prefs.uiDefaults[key] - elif key in ["LogViewerStdoutFilter", "LogViewerStderrFilter", - "LogViewerStdxxxFilter", "TextMimeTypes"]: + elif key in [ + "LogViewerStdoutFilter", "LogViewerStderrFilter", + "LogViewerStdxxxFilter", "TextMimeTypes" + ]: return toList( Prefs.settings.value("UI/" + key, Prefs.uiDefaults[key])) else:
--- a/eric7/UI/FindFileWidget.py Fri Apr 29 11:40:00 2022 +0200 +++ b/eric7/UI/FindFileWidget.py Fri Apr 29 15:40:17 2022 +0200 @@ -14,7 +14,8 @@ from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QPoint, QUrl from PyQt6.QtGui import QCursor, QDesktopServices, QImageReader from PyQt6.QtWidgets import ( - QWidget, QApplication, QMenu, QTreeWidgetItem, QComboBox + QWidget, QApplication, QMenu, QTreeWidgetItem, QComboBox, QDialog, + QDialogButtonBox, QVBoxLayout ) from EricWidgets.EricApplication import ericApp @@ -89,16 +90,20 @@ self.stopButton.setEnabled(False) self.stopButton.clicked.connect(self.__stopSearch) self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading")) + self.stopButton.setAutoDefault(False) self.findButton.setEnabled(False) self.findButton.clicked.connect(self.__doSearch) self.findButton.setIcon(UI.PixmapCache.getIcon("find")) + self.findButton.setAutoDefault(False) self.clearButton.setEnabled(False) self.clearButton.clicked.connect(self.__clearResults) self.clearButton.setIcon(UI.PixmapCache.getIcon("clear")) + self.clearButton.setAutoDefault(False) self.replaceButton.setIcon(UI.PixmapCache.getIcon("editReplace")) + self.replaceButton.setAutoDefault(False) self.modeToggleButton.clicked.connect(self.__toggleReplaceMode) @@ -898,4 +903,96 @@ cb = QApplication.clipboard() cb.setText(fn) -# TODO: add separate dialog variant + +class FindFileDialog(QDialog): + """ + Class implementing a dialog to search for text in files and replace it + with some other text. + + The occurrences found are displayed in a tree showing the file name, + the line number and the text found. The file will be opened upon a double + click onto the respective entry of the list. If the widget is in replace + mode the line below shows the text after replacement. Replacements can + be authorized by ticking them on. Pressing the replace button performs + all ticked replacement operations. + + @signal sourceFile(str, int, str, int, int) emitted to open a source file + at a specificline + @signal designerFile(str) emitted to open a Qt-Designer file + @signal linguistFile(str) emitted to open a Qt-Linguist (*.ts) file + @signal trpreview([str]) emitted to preview Qt-Linguist (*.qm) files + @signal pixmapFile(str) emitted to open a pixmap file + @signal svgFile(str) emitted to open a SVG file + @signal umlFile(str) emitted to open an eric UML file + """ + sourceFile = pyqtSignal(str, int, str, int, int) + designerFile = pyqtSignal(str) + linguistFile = pyqtSignal(str) + trpreview = pyqtSignal(list) + pixmapFile = pyqtSignal(str) + svgFile = pyqtSignal(str) + umlFile = pyqtSignal(str) + + def __init__(self, project, parent=None): + """ + Constructor + + @param project reference to the project object + @type Project + @param parent parent widget of this dialog (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setWindowFlags(Qt.WindowType.Window) + + self.__layout = QVBoxLayout() + + self.__findWidget = FindFileWidget(project, self) + self.__layout.addWidget(self.__findWidget) + + self.__buttonBox = QDialogButtonBox( + QDialogButtonBox.StandardButton.Close, + Qt.Orientation.Horizontal, + self + ) + self.__buttonBox.button( + QDialogButtonBox.StandardButton.Close).setAutoDefault(False) + self.__layout.addWidget(self.__buttonBox) + + self.setLayout(self.__layout) + self.resize(600, 800) + + # connect the widgets + self.__findWidget.sourceFile.connect(self.sourceFile) + self.__findWidget.designerFile.connect(self.designerFile) + self.__findWidget.linguistFile.connect(self.linguistFile) + self.__findWidget.trpreview.connect(self.trpreview) + self.__findWidget.pixmapFile.connect(self.pixmapFile) + self.__findWidget.svgFile.connect(self.svgFile) + self.__findWidget.umlFile.connect(self.umlFile) + + self.__buttonBox.accepted.connect(self.accept) + self.__buttonBox.rejected.connect(self.reject) + + def activate(self, replaceMode=False, txt="", searchDir="", + openFiles=False): + """ + Public method to activate the dialog with a given mode, a text + to search for and some search parameters. + + @param replaceMode flag indicating replacement mode (defaults to False) + @type bool (optional) + @param txt text to be searched for (defaults to "") + @type str (optional) + @param searchDir directory to search in (defaults to "") + @type str (optional) + @param openFiles flag indicating to operate on open files only + (defaults to False) + @type bool (optional) + """ + self.__findWidget.activate(replaceMode=replaceMode, txt=txt, + searchDir=searchDir, openFiles=openFiles) + + self.raise_() + self.activateWindow() + self.show()
--- a/eric7/UI/UserInterface.py Fri Apr 29 11:40:00 2022 +0200 +++ b/eric7/UI/UserInterface.py Fri Apr 29 15:40:17 2022 +0200 @@ -944,18 +944,22 @@ self.__virtualenvManagerWidget = VirtualenvManagerWidget( self.virtualenvManager, self) - # TODO: add separate dialog variant - # Create the find in files widget - from .FindFileWidget import FindFileWidget - self.__findFileWidget = FindFileWidget(self.project, self) - self.__findFileWidget.sourceFile.connect( - self.viewmanager.openSourceFile) - self.__findFileWidget.designerFile.connect(self.__designer) - self.__findFileWidget.linguistFile.connect(self.__linguist) - self.__findFileWidget.trpreview.connect(self.__TRPreviewer) - self.__findFileWidget.pixmapFile.connect(self.__showPixmap) - self.__findFileWidget.svgFile.connect(self.__showSvg) - self.__findFileWidget.umlFile.connect(self.__showUml) + self.__FindFileDialog = None + self.__replaceFileDialog = None + if Preferences.getUI("ShowFindFileWidget"): + # Create the find in files widget + from .FindFileWidget import FindFileWidget + self.__findFileWidget = FindFileWidget(self.project, self) + self.__findFileWidget.sourceFile.connect( + self.viewmanager.openSourceFile) + self.__findFileWidget.designerFile.connect(self.__designer) + self.__findFileWidget.linguistFile.connect(self.__linguist) + self.__findFileWidget.trpreview.connect(self.__TRPreviewer) + self.__findFileWidget.pixmapFile.connect(self.__showPixmap) + self.__findFileWidget.svgFile.connect(self.__showSvg) + self.__findFileWidget.umlFile.connect(self.__showUml) + else: + self.__findFileWidget = None # TODO: add separate dialog variant # Create the find location (file) widget @@ -1086,9 +1090,10 @@ UI.PixmapCache.getIcon("projectViewer"), self.tr("Project-Viewer")) - self.lToolbox.addItem(self.__findFileWidget, - UI.PixmapCache.getIcon("find"), - self.tr("Find/Replace In Files")) + if self.__findFileWidget: + self.lToolbox.addItem(self.__findFileWidget, + UI.PixmapCache.getIcon("find"), + self.tr("Find/Replace In Files")) self.lToolbox.addItem(self.__findLocationWidget, UI.PixmapCache.getIcon("findLocation"), @@ -1235,10 +1240,11 @@ UI.PixmapCache.getIcon("sbProjectViewer96"), self.tr("Project-Viewer")) - self.leftSidebar.addTab( - self.__findFileWidget, - UI.PixmapCache.getIcon("sbFind96"), - self.tr("Find/Replace In Files")) + if self.__findFileWidget: + self.leftSidebar.addTab( + self.__findFileWidget, + UI.PixmapCache.getIcon("sbFind96"), + self.tr("Find/Replace In Files")) self.leftSidebar.addTab( self.__findLocationWidget, @@ -2314,24 +2320,25 @@ self.activateVirtualenvManager) self.actions.append(self.virtualenvManagerActivateAct) self.addAction(self.virtualenvManagerActivateAct) - - self.findFileActivateAct = EricAction( - self.tr("Find/Replace In Files"), - self.tr("Find/Replace In Files"), - QKeySequence(self.tr("Ctrl+Alt+Shift+F")), - 0, self, - 'find_file_activate') - self.findFileActivateAct.setStatusTip(self.tr( - "Switch the input focus to the Find/Replace In Files window.")) - self.findFileActivateAct.setWhatsThis(self.tr( - """<b>Find/Replace In Files</b>""" - """<p>This switches the input focus to the Find/Replace In Files""" - """ window.</p>""" - )) - self.findFileActivateAct.triggered.connect( - self.__activateFindFileWidget) - self.actions.append(self.findFileActivateAct) - self.addAction(self.findFileActivateAct) + + if self.__findFileWidget is not None: + self.findFileActivateAct = EricAction( + self.tr("Find/Replace In Files"), + self.tr("Find/Replace In Files"), + QKeySequence(self.tr("Ctrl+Alt+Shift+F")), + 0, self, + 'find_file_activate') + self.findFileActivateAct.setStatusTip(self.tr( + "Switch the input focus to the Find/Replace In Files window.")) + self.findFileActivateAct.setWhatsThis(self.tr( + """<b>Find/Replace In Files</b>""" + """<p>This switches the input focus to the Find/Replace In""" + """ Files window.</p>""" + )) + self.findFileActivateAct.triggered.connect( + self.__activateFindFileWidget) + self.actions.append(self.findFileActivateAct) + self.addAction(self.findFileActivateAct) self.findLocationActivateAct = EricAction( self.tr("Find File"), @@ -3468,7 +3475,8 @@ self.__menus["subwindow"].addSection(self.tr("Left Side")) self.__menus["subwindow"].addAction(self.mpbActivateAct) self.__menus["subwindow"].addAction(self.pbActivateAct) - self.__menus["subwindow"].addAction(self.findFileActivateAct) + if self.__findFileWidget is not None: + self.__menus["subwindow"].addAction(self.findFileActivateAct) self.__menus["subwindow"].addAction(self.findLocationActivateAct) self.__menus["subwindow"].addAction(self.vcsStatusListActivateAct) if not self.rightSidebar: @@ -7163,11 +7171,28 @@ (defaults to False) @type bool (optional) """ - # TODO: add separate dialog variant - self.__activateFindFileWidget() - self.__findFileWidget.activate( - replaceMode=False, txt=txt, searchDir=searchDir, - openFiles=openFiles) + if Preferences.getUI("ShowFindFileWidget"): + # embedded tool + self.__activateFindFileWidget() + self.__findFileWidget.activate( + replaceMode=False, txt=txt, searchDir=searchDir, + openFiles=openFiles) + else: + # external dialog + if self.__FindFileDialog is None: + from .FindFileWidget import FindFileDialog + self.__FindFileDialog = FindFileDialog(self.project) + self.__FindFileDialog.sourceFile.connect( + self.viewmanager.openSourceFile) + self.__FindFileDialog.designerFile.connect(self.__designer) + self.__FindFileDialog.linguistFile.connect(self.__linguist) + self.__FindFileDialog.trpreview.connect(self.__TRPreviewer) + self.__FindFileDialog.pixmapFile.connect(self.__showPixmap) + self.__FindFileDialog.svgFile.connect(self.__showSvg) + self.__FindFileDialog.umlFile.connect(self.__showUml) + self.__FindFileDialog.activate( + replaceMode=False, txt=txt, searchDir=searchDir, + openFiles=openFiles) def showReplaceFilesWidget(self, txt="", searchDir="", openFiles=False): """ @@ -7181,11 +7206,27 @@ (defaults to False) @type bool (optional) """ - # TODO: add separate dialog variant - self.__activateFindFileWidget() - self.__findFileWidget.activate( - replaceMode=True, txt=txt, searchDir=searchDir, - openFiles=openFiles) + if Preferences.getUI("ShowFindFileWidget"): + self.__activateFindFileWidget() + self.__findFileWidget.activate( + replaceMode=True, txt=txt, searchDir=searchDir, + openFiles=openFiles) + else: + # external dialog + if self.__replaceFileDialog is None: + from .FindFileWidget import FindFileDialog + self.__replaceFileDialog = FindFileDialog(self.project) + self.__replaceFileDialog.sourceFile.connect( + self.viewmanager.openSourceFile) + self.__replaceFileDialog.designerFile.connect(self.__designer) + self.__replaceFileDialog.linguistFile.connect(self.__linguist) + self.__replaceFileDialog.trpreview.connect(self.__TRPreviewer) + self.__replaceFileDialog.pixmapFile.connect(self.__showPixmap) + self.__replaceFileDialog.svgFile.connect(self.__showSvg) + self.__replaceFileDialog.umlFile.connect(self.__showUml) + self.__replaceFileDialog.activate( + replaceMode=True, txt=txt, searchDir=searchDir, + openFiles=openFiles) def __activateFindFileWidget(self): """