UI/FindFileDialog.py

changeset 846
869c200be26e
parent 791
9ec2ac20e54e
child 855
d8c4113a9274
equal deleted inserted replaced
845:0e937d523b70 846:869c200be26e
23 23
24 class FindFileDialog(QDialog, Ui_FindFileDialog): 24 class FindFileDialog(QDialog, Ui_FindFileDialog):
25 """ 25 """
26 Class implementing a dialog to search for text in files. 26 Class implementing a dialog to search for text in files.
27 27
28 The occurrences found are displayed in a QTreeWidget showing the filename, the 28 The occurrences found are displayed in a QTreeWidget showing the filename,
29 linenumber and the found text. The file will be opened upon a double click onto 29 the linenumber and the found text. The file will be opened upon a double
30 the respective entry of the list. 30 click onto the respective entry of the list.
31 31
32 @signal sourceFile(str, int, str, int, int) emitted to open a source file at a line 32 @signal sourceFile(str, int, str, int, int) emitted to open a source file
33 at a line
33 @signal designerFile(str) emitted to open a Qt-Designer file 34 @signal designerFile(str) emitted to open a Qt-Designer file
34 """ 35 """
35 sourceFile = pyqtSignal(str, int, str, int, int) 36 sourceFile = pyqtSignal(str, int, str, int, int)
36 designerFile = pyqtSignal(str) 37 designerFile = pyqtSignal(str)
37 38
53 self.setWindowFlags(Qt.WindowFlags(Qt.Window)) 54 self.setWindowFlags(Qt.WindowFlags(Qt.Window))
54 55
55 self.__replaceMode = replaceMode 56 self.__replaceMode = replaceMode
56 57
57 self.stopButton = \ 58 self.stopButton = \
58 self.buttonBox.addButton(self.trUtf8("Stop"), QDialogButtonBox.ActionRole) 59 self.buttonBox.addButton(self.trUtf8("Stop"),
60 QDialogButtonBox.ActionRole)
59 self.stopButton.setEnabled(False) 61 self.stopButton.setEnabled(False)
60 62
61 self.findButton = \ 63 self.findButton = \
62 self.buttonBox.addButton(self.trUtf8("Find"), QDialogButtonBox.ActionRole) 64 self.buttonBox.addButton(self.trUtf8("Find"),
65 QDialogButtonBox.ActionRole)
63 self.findButton.setEnabled(False) 66 self.findButton.setEnabled(False)
64 self.findButton.setDefault(True) 67 self.findButton.setDefault(True)
65 68
66 if self.__replaceMode: 69 if self.__replaceMode:
67 self.replaceButton.setEnabled(False) 70 self.replaceButton.setEnabled(False)
72 self.replaceButton.hide() 75 self.replaceButton.hide()
73 76
74 self.findProgressLabel.setMaximumWidth(550) 77 self.findProgressLabel.setMaximumWidth(550)
75 78
76 self.searchHistory = Preferences.toList( 79 self.searchHistory = Preferences.toList(
77 Preferences.Prefs.settings.value("FindFileDialog/SearchHistory")) 80 Preferences.Prefs.settings.value(
81 "FindFileDialog/SearchHistory"))
78 self.replaceHistory = Preferences.toList( 82 self.replaceHistory = Preferences.toList(
79 Preferences.Prefs.settings.value("FindFileDialog/ReplaceHistory")) 83 Preferences.Prefs.settings.value(
84 "FindFileDialog/ReplaceHistory"))
80 self.dirHistory = Preferences.toList( 85 self.dirHistory = Preferences.toList(
81 Preferences.Prefs.settings.value("FindFileDialog/DirectoryHistory")) 86 Preferences.Prefs.settings.value(
87 "FindFileDialog/DirectoryHistory"))
82 self.findtextCombo.addItems(self.searchHistory) 88 self.findtextCombo.addItems(self.searchHistory)
83 self.replacetextCombo.addItems(self.replaceHistory) 89 self.replacetextCombo.addItems(self.replaceHistory)
84 self.dirCombo.addItems(self.dirHistory) 90 self.dirCombo.addItems(self.dirHistory)
85 91
86 self.project = project 92 self.project = project
114 self.__populating = False 120 self.__populating = False
115 121
116 self.setContextMenuPolicy(Qt.CustomContextMenu) 122 self.setContextMenuPolicy(Qt.CustomContextMenu)
117 self.customContextMenuRequested.connect(self.__contextMenuRequested) 123 self.customContextMenuRequested.connect(self.__contextMenuRequested)
118 124
119 def __createItem(self, file, line, text, start, end, replTxt = "", md5 = ""): 125 def __createItem(self, file, line, text, start, end, replTxt="", md5=""):
120 """ 126 """
121 Private method to create an entry in the file list. 127 Private method to create an entry in the file list.
122 128
123 @param file filename of file (string) 129 @param file filename of file (string)
124 @param line line number (integer) 130 @param line line number (integer)
135 self.__lastFileItem.setExpanded(True) 141 self.__lastFileItem.setExpanded(True)
136 if self.__replaceMode: 142 if self.__replaceMode:
137 self.__lastFileItem.setFlags(self.__lastFileItem.flags() | \ 143 self.__lastFileItem.setFlags(self.__lastFileItem.flags() | \
138 Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsTristate)) 144 Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsTristate))
139 # Qt bug: 145 # Qt bug:
140 # item is not user checkable if setFirstColumnSpanned is True (< 4.5.0) 146 # item is not user checkable if setFirstColumnSpanned
147 # is True (< 4.5.0)
141 self.__lastFileItem.setData(0, self.md5Role, md5) 148 self.__lastFileItem.setData(0, self.md5Role, md5)
142 149
143 itm = QTreeWidgetItem(self.__lastFileItem, [' {0:5d} '.format(line), text]) 150 itm = QTreeWidgetItem(self.__lastFileItem,
151 [' {0:5d} '.format(line), text])
144 itm.setTextAlignment(0, Qt.AlignRight) 152 itm.setTextAlignment(0, Qt.AlignRight)
145 itm.setData(0, self.lineRole, line) 153 itm.setData(0, self.lineRole, line)
146 itm.setData(0, self.startRole, start) 154 itm.setData(0, self.startRole, start)
147 itm.setData(0, self.endRole, end) 155 itm.setData(0, self.endRole, end)
148 itm.setData(0, self.replaceRole, replTxt) 156 itm.setData(0, self.replaceRole, replTxt)
175 183
176 QDialog.show(self) 184 QDialog.show(self)
177 185
178 def on_findtextCombo_editTextChanged(self, text): 186 def on_findtextCombo_editTextChanged(self, text):
179 """ 187 """
180 Private slot to handle the editTextChanged signal of the find text combo. 188 Private slot to handle the editTextChanged signal of the find
189 text combo.
181 190
182 @param text (ignored) 191 @param text (ignored)
183 """ 192 """
184 self.__enableFindButton() 193 self.__enableFindButton()
185 194
186 def on_replacetextCombo_editTextChanged(self, text): 195 def on_replacetextCombo_editTextChanged(self, text):
187 """ 196 """
188 Private slot to handle the editTextChanged signal of the replace text combo. 197 Private slot to handle the editTextChanged signal of the replace
198 text combo.
189 199
190 @param text (ignored) 200 @param text (ignored)
191 """ 201 """
192 self.__enableFindButton() 202 self.__enableFindButton()
193 203
194 def on_dirCombo_editTextChanged(self, text): 204 def on_dirCombo_editTextChanged(self, text):
195 """ 205 """
196 Private slot to handle the textChanged signal of the directory combo box. 206 Private slot to handle the textChanged signal of the directory
207 combo box.
197 208
198 @param text (ignored) 209 @param text (ignored)
199 """ 210 """
200 self.__enableFindButton() 211 self.__enableFindButton()
201 212
232 def __enableFindButton(self): 243 def __enableFindButton(self):
233 """ 244 """
234 Private slot called to enable the find button. 245 Private slot called to enable the find button.
235 """ 246 """
236 if self.findtextCombo.currentText() == "" or \ 247 if self.findtextCombo.currentText() == "" or \
237 (self.__replaceMode and self.replacetextCombo.currentText() == "") or \ 248 (self.__replaceMode and \
249 self.replacetextCombo.currentText() == "") or \
238 (self.dirButton.isChecked() and \ 250 (self.dirButton.isChecked() and \
239 (self.dirCombo.currentText() == "" or \ 251 (self.dirCombo.currentText() == "" or \
240 not os.path.exists(os.path.abspath(self.dirCombo.currentText())))) or \ 252 not os.path.exists(os.path.abspath(
253 self.dirCombo.currentText())))) or \
241 (self.filterCheckBox.isChecked() and self.filterEdit.text() == ""): 254 (self.filterCheckBox.isChecked() and self.filterEdit.text() == ""):
242 self.findButton.setEnabled(False) 255 self.findButton.setEnabled(False)
243 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) 256 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
244 else: 257 else:
245 self.findButton.setEnabled(True) 258 self.findButton.setEnabled(True)
264 277
265 def __doSearch(self): 278 def __doSearch(self):
266 """ 279 """
267 Private slot to handle the find button being pressed. 280 Private slot to handle the find button being pressed.
268 """ 281 """
269 if self.__replaceMode and not e5App().getObject("ViewManager").checkAllDirty(): 282 if self.__replaceMode and \
283 not e5App().getObject("ViewManager").checkAllDirty():
270 return 284 return
271 285
272 self.__cancelSearch = False 286 self.__cancelSearch = False
273 287
274 if self.filterCheckBox.isChecked(): 288 if self.filterCheckBox.isChecked():
280 294
281 if self.projectButton.isChecked(): 295 if self.projectButton.isChecked():
282 if self.filterCheckBox.isChecked(): 296 if self.filterCheckBox.isChecked():
283 files = [self.project.getRelativePath(file) \ 297 files = [self.project.getRelativePath(file) \
284 for file in \ 298 for file in \
285 self.__getFileList(self.project.getProjectPath(), filterRe)] 299 self.__getFileList(
300 self.project.getProjectPath(), filterRe)]
286 else: 301 else:
287 files = [] 302 files = []
288 if self.sourcesCheckBox.isChecked(): 303 if self.sourcesCheckBox.isChecked():
289 files += self.project.pdata["SOURCES"] 304 files += self.project.pdata["SOURCES"]
290 if self.formsCheckBox.isChecked(): 305 if self.formsCheckBox.isChecked():
296 elif self.dirButton.isChecked(): 311 elif self.dirButton.isChecked():
297 if not self.filterCheckBox.isChecked(): 312 if not self.filterCheckBox.isChecked():
298 filters = [] 313 filters = []
299 if self.sourcesCheckBox.isChecked(): 314 if self.sourcesCheckBox.isChecked():
300 filters.extend( 315 filters.extend(
301 ["^{0}$".format(assoc.replace(".", "\.").replace("*", ".*")) \ 316 ["^{0}$".format(
302 for assoc in list(Preferences.getEditorLexerAssocs().keys()) \ 317 assoc.replace(".", "\.").replace("*", ".*"))
318 for assoc in list(
319 Preferences.getEditorLexerAssocs().keys())
303 if assoc not in self.formsExt + self.interfacesExt]) 320 if assoc not in self.formsExt + self.interfacesExt])
304 if self.formsCheckBox.isChecked(): 321 if self.formsCheckBox.isChecked():
305 filters.append(self.filterForms) 322 filters.append(self.filterForms)
306 if self.interfacesCheckBox.isChecked(): 323 if self.interfacesCheckBox.isChecked():
307 filters.append(self.filterInterfaces) 324 filters.append(self.filterInterfaces)
308 if self.resourcesCheckBox.isChecked(): 325 if self.resourcesCheckBox.isChecked():
309 filters.append(self.filterResources) 326 filters.append(self.filterResources)
310 filterString = "|".join(filters) 327 filterString = "|".join(filters)
311 filterRe = re.compile(filterString) 328 filterRe = re.compile(filterString)
312 files = self.__getFileList(os.path.abspath(self.dirCombo.currentText()), 329 files = self.__getFileList(
313 filterRe) 330 os.path.abspath(self.dirCombo.currentText()),
331 filterRe)
314 elif self.openFilesButton.isChecked(): 332 elif self.openFilesButton.isChecked():
315 files = e5App().getObject("ViewManager").getOpenFilenames() 333 files = e5App().getObject("ViewManager").getOpenFilenames()
316 334
317 self.findList.clear() 335 self.findList.clear()
318 QApplication.processEvents() 336 QApplication.processEvents()
350 if ct in self.searchHistory: 368 if ct in self.searchHistory:
351 self.searchHistory.remove(ct) 369 self.searchHistory.remove(ct)
352 self.searchHistory.insert(0, ct) 370 self.searchHistory.insert(0, ct)
353 self.findtextCombo.clear() 371 self.findtextCombo.clear()
354 self.findtextCombo.addItems(self.searchHistory) 372 self.findtextCombo.addItems(self.searchHistory)
355 Preferences.Prefs.settings.setValue("FindFileDialog/SearchHistory", 373 Preferences.Prefs.settings.setValue(
356 self.searchHistory[:30]) 374 "FindFileDialog/SearchHistory",
375 self.searchHistory[:30])
357 376
358 if self.__replaceMode: 377 if self.__replaceMode:
359 replTxt = self.replacetextCombo.currentText() 378 replTxt = self.replacetextCombo.currentText()
360 if replTxt in self.replaceHistory: 379 if replTxt in self.replaceHistory:
361 self.replaceHistory.remove(replTxt) 380 self.replaceHistory.remove(replTxt)
362 self.replaceHistory.insert(0, replTxt) 381 self.replaceHistory.insert(0, replTxt)
363 self.replacetextCombo.clear() 382 self.replacetextCombo.clear()
364 self.replacetextCombo.addItems(self.replaceHistory) 383 self.replacetextCombo.addItems(self.replaceHistory)
365 Preferences.Prefs.settings.setValue("FindFileDialog/ReplaceHistory", 384 Preferences.Prefs.settings.setValue(
366 self.replaceHistory[:30]) 385 "FindFileDialog/ReplaceHistory",
386 self.replaceHistory[:30])
367 387
368 if self.dirButton.isChecked(): 388 if self.dirButton.isChecked():
369 searchDir = self.dirCombo.currentText() 389 searchDir = self.dirCombo.currentText()
370 if searchDir in self.dirHistory: 390 if searchDir in self.dirHistory:
371 self.dirHistory.remove(searchDir) 391 self.dirHistory.remove(searchDir)
372 self.dirHistory.insert(0, searchDir) 392 self.dirHistory.insert(0, searchDir)
373 self.dirCombo.clear() 393 self.dirCombo.clear()
374 self.dirCombo.addItems(self.dirHistory) 394 self.dirCombo.addItems(self.dirHistory)
375 Preferences.Prefs.settings.setValue("FindFileDialog/DirectoryHistory", 395 Preferences.Prefs.settings.setValue(
376 self.dirHistory[:30]) 396 "FindFileDialog/DirectoryHistory",
397 self.dirHistory[:30])
377 398
378 # set the button states 399 # set the button states
379 self.stopButton.setEnabled(True) 400 self.stopButton.setEnabled(True)
380 self.stopButton.setDefault(True) 401 self.stopButton.setDefault(True)
381 self.findButton.setEnabled(False) 402 self.findButton.setEnabled(False)
424 line = "{0} ...".format(line[:1024]) 445 line = "{0} ...".format(line[:1024])
425 if self.__replaceMode: 446 if self.__replaceMode:
426 if len(rline) > 1024: 447 if len(rline) > 1024:
427 rline = "{0} ...".format(line[:1024]) 448 rline = "{0} ...".format(line[:1024])
428 line = "- {0}\n+ {1}".format(line, rline) 449 line = "- {0}\n+ {1}".format(line, rline)
429 self.__createItem(file, count, line, start, end, rline, hash) 450 self.__createItem(file, count, line, start, end,
451 rline, hash)
430 452
431 if self.feelLikeCheckBox.isChecked(): 453 if self.feelLikeCheckBox.isChecked():
432 fn = os.path.join(self.project.ppath, file) 454 fn = os.path.join(self.project.ppath, file)
433 self.sourceFile.emit(fn, count, "", start, end) 455 self.sourceFile.emit(fn, count, "", start, end)
434 QApplication.processEvents() 456 QApplication.processEvents()
509 def __getFileList(self, path, filterRe): 531 def __getFileList(self, path, filterRe):
510 """ 532 """
511 Private method to get a list of files to search. 533 Private method to get a list of files to search.
512 534
513 @param path the root directory to search in (string) 535 @param path the root directory to search in (string)
514 @param filterRe regular expression defining the filter criteria (regexp object) 536 @param filterRe regular expression defining the filter
537 criteria (regexp object)
515 @return list of files to be processed (list of strings) 538 @return list of files to be processed (list of strings)
516 """ 539 """
517 path = os.path.abspath(path) 540 path = os.path.abspath(path)
518 files = [] 541 files = []
519 for dirname, _, names in os.walk(path): 542 for dirname, _, names in os.walk(path):
554 else: 577 else:
555 fn = file 578 fn = file
556 579
557 # read the file and split it into textlines 580 # read the file and split it into textlines
558 try: 581 try:
559 text, encoding, hash = Utilities.readEncodedFileWithHash(fn) 582 text, encoding, hash = \
583 Utilities.readEncodedFileWithHash(fn)
560 lines = text.splitlines() 584 lines = text.splitlines()
561 except (UnicodeError, IOError): 585 except (UnicodeError, IOError):
562 E5MessageBox.critical(self, 586 E5MessageBox.critical(self,
563 self.trUtf8("Replace in Files"), 587 self.trUtf8("Replace in Files"),
564 self.trUtf8("""<p>Could not read the file <b>{0}</b>.""" 588 self.trUtf8(
565 """ Skipping it.</p><p>Reason: {1}</p>""")\ 589 """<p>Could not read the file <b>{0}</b>."""
590 """ Skipping it.</p><p>Reason: {1}</p>""")\
566 .format(fn, str(err)) 591 .format(fn, str(err))
567 ) 592 )
568 progress += 1 593 progress += 1
569 self.findProgress.setValue(progress) 594 self.findProgress.setValue(progress)
570 continue 595 continue
572 # Check the original and the current hash. Skip the file, 597 # Check the original and the current hash. Skip the file,
573 # if hashes are different. 598 # if hashes are different.
574 if origHash != hash: 599 if origHash != hash:
575 E5MessageBox.critical(self, 600 E5MessageBox.critical(self,
576 self.trUtf8("Replace in Files"), 601 self.trUtf8("Replace in Files"),
577 self.trUtf8("""<p>The current and the original hash of the""" 602 self.trUtf8(
578 """ file <b>{0}</b> are different. Skipping it.""" 603 """<p>The current and the original hash of the"""
579 """</p><p>Hash 1: {1}</p><p>Hash 2: {2}</p>""")\ 604 """ file <b>{0}</b> are different. Skipping it."""
605 """</p><p>Hash 1: {1}</p><p>Hash 2: {2}</p>""")\
580 .format(fn, origHash, hash) 606 .format(fn, origHash, hash)
581 ) 607 )
582 progress += 1 608 progress += 1
583 self.findProgress.setValue(progress) 609 self.findProgress.setValue(progress)
584 continue 610 continue
590 line = citm.data(0, self.lineRole) 616 line = citm.data(0, self.lineRole)
591 rline = citm.data(0, self.replaceRole) 617 rline = citm.data(0, self.replaceRole)
592 lines[line - 1] = rline 618 lines[line - 1] = rline
593 619
594 # write the file 620 # write the file
595 txt = Utilities.linesep().join(lines) + Utilities.linesep() 621 if self.project.isProjectFile(fn):
622 eol = self.project.getEolString()
623 else:
624 eol = Utilities.linesep()
625 txt = eol.join(lines) + Utilities.linesep()
596 try: 626 try:
597 Utilities.writeEncodedFile(fn, txt, encoding) 627 Utilities.writeEncodedFile(fn, txt, encoding)
598 except (IOError, Utilities.CodingError, UnicodeError) as err: 628 except (IOError, Utilities.CodingError, UnicodeError) as err:
599 E5MessageBox.critical(self, 629 E5MessageBox.critical(self,
600 self.trUtf8("Replace in Files"), 630 self.trUtf8("Replace in Files"),
601 self.trUtf8("""<p>Could not save the file <b>{0}</b>.""" 631 self.trUtf8(
602 """ Skipping it.</p><p>Reason: {1}</p>""")\ 632 """<p>Could not save the file <b>{0}</b>."""
633 """ Skipping it.</p><p>Reason: {1}</p>""")\
603 .format(fn, str(err)) 634 .format(fn, str(err))
604 ) 635 )
605 636
606 progress += 1 637 progress += 1
607 self.findProgress.setValue(progress) 638 self.findProgress.setValue(progress)
620 @param pos position the context menu shall be shown (QPoint) 651 @param pos position the context menu shall be shown (QPoint)
621 """ 652 """
622 menu = QMenu(self) 653 menu = QMenu(self)
623 654
624 menu.addAction(self.trUtf8("Open"), self.__openFile) 655 menu.addAction(self.trUtf8("Open"), self.__openFile)
625 menu.addAction(self.trUtf8("Copy Path to Clipboard"), self.__copyToClipboard) 656 menu.addAction(self.trUtf8("Copy Path to Clipboard"),
657 self.__copyToClipboard)
626 658
627 menu.exec_(QCursor.pos()) 659 menu.exec_(QCursor.pos())
628 660
629 def __openFile(self): 661 def __openFile(self):
630 """ 662 """

eric ide

mercurial