|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2004 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a dialog to search for files. |
|
8 """ |
|
9 |
|
10 import os |
|
11 import sys |
|
12 |
|
13 from PyQt5.QtCore import pyqtSignal, pyqtSlot |
|
14 from PyQt5.QtWidgets import ( |
|
15 QWidget, QHeaderView, QApplication, QDialogButtonBox, QTreeWidgetItem |
|
16 ) |
|
17 |
|
18 from E5Gui.E5PathPicker import E5PathPickerModes |
|
19 |
|
20 from .Ui_FindFileNameDialog import Ui_FindFileNameDialog |
|
21 |
|
22 from Utilities import direntries |
|
23 import Utilities |
|
24 |
|
25 |
|
26 class FindFileNameDialog(QWidget, Ui_FindFileNameDialog): |
|
27 """ |
|
28 Class implementing a dialog to search for files. |
|
29 |
|
30 The occurrences found are displayed in a QTreeWidget showing the |
|
31 filename and the pathname. The file will be opened upon a double click |
|
32 onto the respective entry of the list. |
|
33 |
|
34 @signal sourceFile(str) emitted to open a file in the editor |
|
35 @signal designerFile(str) emitted to open a Qt-Designer file |
|
36 """ |
|
37 sourceFile = pyqtSignal(str) |
|
38 designerFile = pyqtSignal(str) |
|
39 |
|
40 def __init__(self, project, parent=None): |
|
41 """ |
|
42 Constructor |
|
43 |
|
44 @param project reference to the project object |
|
45 @param parent parent widget of this dialog (QWidget) |
|
46 """ |
|
47 super().__init__(parent) |
|
48 self.setupUi(self) |
|
49 |
|
50 self.searchDirPicker.setMode(E5PathPickerModes.DirectoryMode) |
|
51 |
|
52 self.fileList.headerItem().setText(self.fileList.columnCount(), "") |
|
53 |
|
54 self.stopButton = self.buttonBox.addButton( |
|
55 self.tr("Stop"), QDialogButtonBox.ButtonRole.ActionRole) |
|
56 self.stopButton.setToolTip(self.tr("Press to stop the search")) |
|
57 self.stopButton.setEnabled(False) |
|
58 self.buttonBox.button( |
|
59 QDialogButtonBox.StandardButton.Open).setToolTip( |
|
60 self.tr("Opens the selected file")) |
|
61 self.buttonBox.button( |
|
62 QDialogButtonBox.StandardButton.Open).setEnabled(False) |
|
63 |
|
64 self.project = project |
|
65 self.extsepLabel.setText(os.extsep) |
|
66 |
|
67 self.shouldStop = False |
|
68 |
|
69 def on_buttonBox_clicked(self, button): |
|
70 """ |
|
71 Private slot called by a button of the button box clicked. |
|
72 |
|
73 @param button button that was clicked (QAbstractButton) |
|
74 """ |
|
75 if button == self.stopButton: |
|
76 self.shouldStop = True |
|
77 elif button == self.buttonBox.button( |
|
78 QDialogButtonBox.StandardButton.Open |
|
79 ): |
|
80 self.__openFile() |
|
81 |
|
82 def __openFile(self, itm=None): |
|
83 """ |
|
84 Private slot to open a file. |
|
85 |
|
86 It emits the signal sourceFile or designerFile depending on the |
|
87 file extension. |
|
88 |
|
89 @param itm item to be opened (QTreeWidgetItem) |
|
90 """ |
|
91 if itm is None: |
|
92 itm = self.fileList.currentItem() |
|
93 if itm is not None: |
|
94 fileName = itm.text(0) |
|
95 filePath = itm.text(1) |
|
96 |
|
97 if fileName.endswith('.ui'): |
|
98 self.designerFile.emit(os.path.join(filePath, fileName)) |
|
99 else: |
|
100 self.sourceFile.emit(os.path.join(filePath, fileName)) |
|
101 |
|
102 def __searchFile(self): |
|
103 """ |
|
104 Private slot to handle the search. |
|
105 """ |
|
106 fileName = self.fileNameEdit.text() |
|
107 if not fileName: |
|
108 self.fileList.clear() |
|
109 return |
|
110 fileExt = self.fileExtEdit.text() |
|
111 if not fileExt and Utilities.isWindowsPlatform(): |
|
112 self.fileList.clear() |
|
113 return |
|
114 |
|
115 patternFormat = fileExt and "{0}{1}{2}" or "{0}*{1}{2}" |
|
116 fileNamePattern = patternFormat.format( |
|
117 fileName, os.extsep, fileExt and fileExt or '*') |
|
118 |
|
119 searchPaths = [] |
|
120 if ( |
|
121 self.searchDirCheckBox.isChecked() and |
|
122 self.searchDirPicker.text() != "" |
|
123 ): |
|
124 searchPaths.append(self.searchDirPicker.text()) |
|
125 if self.projectCheckBox.isChecked(): |
|
126 searchPaths.append(self.project.ppath) |
|
127 if self.syspathCheckBox.isChecked(): |
|
128 searchPaths.extend(sys.path) |
|
129 |
|
130 found = False |
|
131 self.fileList.clear() |
|
132 locations = {} |
|
133 self.shouldStop = False |
|
134 self.stopButton.setEnabled(True) |
|
135 QApplication.processEvents() |
|
136 |
|
137 for path in searchPaths: |
|
138 if os.path.isdir(path): |
|
139 files = direntries(path, True, fileNamePattern, |
|
140 False, self.checkStop) |
|
141 if files: |
|
142 found = True |
|
143 for file in files: |
|
144 fp, fn = os.path.split(file) |
|
145 if fn in locations: |
|
146 if fp in locations[fn]: |
|
147 continue |
|
148 else: |
|
149 locations[fn].append(fp) |
|
150 else: |
|
151 locations[fn] = [fp] |
|
152 QTreeWidgetItem(self.fileList, [fn, fp]) |
|
153 QApplication.processEvents() |
|
154 |
|
155 del locations |
|
156 self.stopButton.setEnabled(False) |
|
157 self.fileList.header().resizeSections( |
|
158 QHeaderView.ResizeMode.ResizeToContents) |
|
159 self.fileList.header().setStretchLastSection(True) |
|
160 |
|
161 if found: |
|
162 self.fileList.setCurrentItem(self.fileList.topLevelItem(0)) |
|
163 |
|
164 def checkStop(self): |
|
165 """ |
|
166 Public method to check, if the search should be stopped. |
|
167 |
|
168 @return flag indicating the search should be stopped (boolean) |
|
169 """ |
|
170 QApplication.processEvents() |
|
171 return self.shouldStop |
|
172 |
|
173 def on_fileNameEdit_textChanged(self, text): |
|
174 """ |
|
175 Private slot to handle the textChanged signal of the file name edit. |
|
176 |
|
177 @param text (ignored) |
|
178 """ |
|
179 self.__searchFile() |
|
180 |
|
181 def on_fileExtEdit_textChanged(self, text): |
|
182 """ |
|
183 Private slot to handle the textChanged signal of the file extension |
|
184 edit. |
|
185 |
|
186 @param text (ignored) |
|
187 """ |
|
188 self.__searchFile() |
|
189 |
|
190 def on_searchDirPicker_textChanged(self, text): |
|
191 """ |
|
192 Private slot to handle the textChanged signal of the search directory |
|
193 edit. |
|
194 |
|
195 @param text text of the search dir edit (string) |
|
196 """ |
|
197 self.searchDirCheckBox.setEnabled(text != "") |
|
198 if self.searchDirCheckBox.isChecked(): |
|
199 self.__searchFile() |
|
200 |
|
201 def on_searchDirCheckBox_toggled(self, checked): |
|
202 """ |
|
203 Private slot to handle the toggled signal of the search directory |
|
204 checkbox. |
|
205 |
|
206 @param checked flag indicating the state of the checkbox (boolean) |
|
207 """ |
|
208 if self.searchDirPicker.text(): |
|
209 self.__searchFile() |
|
210 |
|
211 def on_projectCheckBox_toggled(self, checked): |
|
212 """ |
|
213 Private slot to handle the toggled signal of the project checkbox. |
|
214 |
|
215 @param checked flag indicating the state of the checkbox (boolean) |
|
216 """ |
|
217 self.__searchFile() |
|
218 |
|
219 def on_syspathCheckBox_toggled(self, checked): |
|
220 """ |
|
221 Private slot to handle the toggled signal of the sys.path checkbox. |
|
222 |
|
223 @param checked flag indicating the state of the checkbox (boolean) |
|
224 """ |
|
225 self.__searchFile() |
|
226 |
|
227 def on_fileList_itemActivated(self, itm, column): |
|
228 """ |
|
229 Private slot to handle the double click on a file item. |
|
230 |
|
231 It emits the signal sourceFile or designerFile depending on the |
|
232 file extension. |
|
233 |
|
234 @param itm the double clicked listview item (QTreeWidgetItem) |
|
235 @param column column that was double clicked (integer) (ignored) |
|
236 """ |
|
237 self.__openFile(itm) |
|
238 |
|
239 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
|
240 def on_fileList_currentItemChanged(self, current, previous): |
|
241 """ |
|
242 Private slot handling a change of the current item. |
|
243 |
|
244 @param current current item (QTreeWidgetItem) |
|
245 @param previous prevoius current item (QTreeWidgetItem) |
|
246 """ |
|
247 self.buttonBox.button(QDialogButtonBox.StandardButton.Open).setEnabled( |
|
248 current is not None) |
|
249 |
|
250 def show(self): |
|
251 """ |
|
252 Public method to enable/disable the project checkbox. |
|
253 """ |
|
254 if self.project and self.project.isOpen(): |
|
255 self.projectCheckBox.setEnabled(True) |
|
256 self.projectCheckBox.setChecked(True) |
|
257 else: |
|
258 self.projectCheckBox.setEnabled(False) |
|
259 self.projectCheckBox.setChecked(False) |
|
260 |
|
261 self.fileNameEdit.selectAll() |
|
262 self.fileNameEdit.setFocus() |
|
263 |
|
264 super().show() |