3010:befeff46ec0f | 3011:18292228c724 |
---|---|
6 """ | 6 """ |
7 Module implementing the search and replace widget. | 7 Module implementing the search and replace widget. |
8 """ | 8 """ |
9 | 9 |
10 from PyQt4.QtCore import pyqtSignal, Qt, pyqtSlot | 10 from PyQt4.QtCore import pyqtSignal, Qt, pyqtSlot |
11 from PyQt4.QtGui import QWidget, QHBoxLayout, QToolButton, QScrollArea, QSizePolicy, \ | 11 from PyQt4.QtGui import QWidget, QHBoxLayout, QToolButton, QScrollArea, \ |
12 QFrame | 12 QSizePolicy, QFrame |
13 | 13 |
14 from .Editor import Editor | 14 from .Editor import Editor |
15 | 15 |
16 from E5Gui.E5Action import E5Action | 16 from E5Gui.E5Action import E5Action |
17 from E5Gui import E5MessageBox | 17 from E5Gui import E5MessageBox |
53 self.replaceHistory = vm.getSRHistory('replace') | 53 self.replaceHistory = vm.getSRHistory('replace') |
54 self.ui = Ui_ReplaceWidget() | 54 self.ui = Ui_ReplaceWidget() |
55 whatsThis = self.trUtf8(r""" | 55 whatsThis = self.trUtf8(r""" |
56 <b>Find and Replace</b> | 56 <b>Find and Replace</b> |
57 <p>This dialog is used to find some text and replace it with another text. | 57 <p>This dialog is used to find some text and replace it with another text. |
58 By checking the various checkboxes, the search can be made more specific. The search | 58 By checking the various checkboxes, the search can be made more specific. |
59 string might be a regular expression. In a regular expression, special characters | 59 The search string might be a regular expression. In a regular expression, |
60 interpreted are:</p> | 60 special characters interpreted are:</p> |
61 """ | 61 """ |
62 ) | 62 ) |
63 else: | 63 else: |
64 from .Ui_SearchWidget import Ui_SearchWidget | 64 from .Ui_SearchWidget import Ui_SearchWidget |
65 self.ui = Ui_SearchWidget() | 65 self.ui = Ui_SearchWidget() |
66 whatsThis = self.trUtf8(r""" | 66 whatsThis = self.trUtf8(r""" |
67 <b>Find</b> | 67 <b>Find</b> |
68 <p>This dialog is used to find some text. By checking the various checkboxes, the search | 68 <p>This dialog is used to find some text. By checking the various checkboxes, |
69 can be made more specific. The search string might be a regular expression. In a regular | 69 the search can be made more specific. The search string might be a regular |
70 expression, special characters interpreted are:</p> | 70 expression. In a regular expression, special characters interpreted are:</p> |
71 """ | 71 """ |
72 ) | 72 ) |
73 self.ui.setupUi(self) | 73 self.ui.setupUi(self) |
74 if not replace: | 74 if not replace: |
75 self.ui.wrapCheckBox.setChecked(True) | 75 self.ui.wrapCheckBox.setChecked(True) |
76 | 76 |
77 whatsThis += self.trUtf8(r""" | 77 whatsThis += self.trUtf8(r""" |
78 <table border="0"> | 78 <table border="0"> |
79 <tr><td><code>.</code></td><td>Matches any character</td></tr> | 79 <tr><td><code>.</code></td><td>Matches any character</td></tr> |
80 <tr><td><code>\(</code></td><td>This marks the start of a region for tagging a match.</td></tr> | 80 <tr><td><code>\(</code></td><td>This marks the start of a region for tagging a |
81 <tr><td><code>\)</code></td><td>This marks the end of a tagged region.</td></tr> | 81 match.</td></tr> |
82 <tr><td><code>\)</code></td><td>This marks the end of a tagged region. | |
83 </td></tr> | |
82 <tr><td><code>\\n</code></td> | 84 <tr><td><code>\\n</code></td> |
83 <td>Where <code>n</code> is 1 through 9 refers to the first through ninth tagged region | 85 <td>Where <code>n</code> is 1 through 9 refers to the first through ninth |
84 when replacing. For example, if the search string was <code>Fred\([1-9]\)XXX</code> and | 86 tagged region when replacing. For example, if the search string was |
85 the replace string was <code>Sam\1YYY</code>, when applied to <code>Fred2XXX</code> this | 87 <code>Fred\([1-9]\)XXX</code> and the replace string was <code>Sam\1YYY</code>, |
86 would generate <code>Sam2YYY</code>.</td></tr> | 88 when applied to <code>Fred2XXX</code> this would generate <code>Sam2YYY</code>. |
89 </td></tr> | |
87 <tr><td><code>\<</code></td> | 90 <tr><td><code>\<</code></td> |
88 <td>This matches the start of a word using Scintilla's definitions of words.</td></tr> | 91 <td>This matches the start of a word using Scintilla's definitions of words. |
92 </td></tr> | |
89 <tr><td><code>\></code></td> | 93 <tr><td><code>\></code></td> |
90 <td>This matches the end of a word using Scintilla's definition of words.</td></tr> | 94 <td>This matches the end of a word using Scintilla's definition of words. |
95 </td></tr> | |
91 <tr><td><code>\\x</code></td> | 96 <tr><td><code>\\x</code></td> |
92 <td>This allows you to use a character x that would otherwise have a special meaning. For | 97 <td>This allows you to use a character x that would otherwise have a special |
93 example, \\[ would be interpreted as [ and not as the start of a character set.</td></tr> | 98 meaning. For example, \\[ would be interpreted as [ and not as the start of a |
99 character set.</td></tr> | |
94 <tr><td><code>[...]</code></td> | 100 <tr><td><code>[...]</code></td> |
95 <td>This indicates a set of characters, for example, [abc] means any of the characters a, | 101 <td>This indicates a set of characters, for example, [abc] means any of the |
96 b or c. You can also use ranges, for example [a-z] for any lower case character.</td></tr> | 102 characters a, b or c. You can also use ranges, for example [a-z] for any lower |
103 case character.</td></tr> | |
97 <tr><td><code>[^...]</code></td> | 104 <tr><td><code>[^...]</code></td> |
98 <td>The complement of the characters in the set. For example, [^A-Za-z] means any | 105 <td>The complement of the characters in the set. For example, [^A-Za-z] means |
99 character except an alphabetic character.</td></tr> | 106 any character except an alphabetic character.</td></tr> |
100 <tr><td><code>^</code></td> | 107 <tr><td><code>^</code></td> |
101 <td>This matches the start of a line (unless used inside a set, see above).</td></tr> | 108 <td>This matches the start of a line (unless used inside a set, see above). |
109 </td></tr> | |
102 <tr><td><code>$</code></td> <td>This matches the end of a line.</td></tr> | 110 <tr><td><code>$</code></td> <td>This matches the end of a line.</td></tr> |
103 <tr><td><code>*</code></td> | 111 <tr><td><code>*</code></td> |
104 <td>This matches 0 or more times. For example, <code>Sa*m</code> matches <code>Sm</code>, | 112 <td>This matches 0 or more times. For example, <code>Sa*m</code> matches |
105 <code>Sam</code>, <code>Saam</code>, <code>Saaam</code> and so on.</td></tr> | 113 <code>Sm</code>, <code>Sam</code>, <code>Saam</code>, <code>Saaam</code> |
114 and so on.</td></tr> | |
106 <tr><td><code>+</code></td> | 115 <tr><td><code>+</code></td> |
107 <td>This matches 1 or more times. For example, <code>Sa+m</code> matches | 116 <td>This matches 1 or more times. For example, <code>Sa+m</code> matches |
108 <code>Sam</code>, <code>Saam</code>, <code>Saaam</code> and so on.</td></tr> | 117 <code>Sam</code>, <code>Saam</code>, <code>Saaam</code> and so on.</td></tr> |
109 </table> | 118 </table> |
110 """) | 119 """) |
111 self.setWhatsThis(whatsThis) | 120 self.setWhatsThis(whatsThis) |
112 | 121 |
113 self.ui.closeButton.setIcon(UI.PixmapCache.getIcon("close.png")) | 122 self.ui.closeButton.setIcon(UI.PixmapCache.getIcon("close.png")) |
114 self.ui.findPrevButton.setIcon(UI.PixmapCache.getIcon("1leftarrow.png")) | 123 self.ui.findPrevButton.setIcon( |
115 self.ui.findNextButton.setIcon(UI.PixmapCache.getIcon("1rightarrow.png")) | 124 UI.PixmapCache.getIcon("1leftarrow.png")) |
125 self.ui.findNextButton.setIcon( | |
126 UI.PixmapCache.getIcon("1rightarrow.png")) | |
116 | 127 |
117 if replace: | 128 if replace: |
118 self.ui.replaceButton.setIcon( | 129 self.ui.replaceButton.setIcon( |
119 UI.PixmapCache.getIcon("editReplace.png")) | 130 UI.PixmapCache.getIcon("editReplace.png")) |
120 self.ui.replaceSearchButton.setIcon( | 131 self.ui.replaceSearchButton.setIcon( |
121 UI.PixmapCache.getIcon("editReplaceSearch.png")) | 132 UI.PixmapCache.getIcon("editReplaceSearch.png")) |
122 self.ui.replaceAllButton.setIcon( | 133 self.ui.replaceAllButton.setIcon( |
123 UI.PixmapCache.getIcon("editReplaceAll.png")) | 134 UI.PixmapCache.getIcon("editReplaceAll.png")) |
124 | 135 |
125 self.ui.findtextCombo.lineEdit().returnPressed.connect(self.__findByReturnPressed) | 136 self.ui.findtextCombo.lineEdit().returnPressed.connect( |
137 self.__findByReturnPressed) | |
126 if replace: | 138 if replace: |
127 self.ui.replacetextCombo.lineEdit().returnPressed.connect( | 139 self.ui.replacetextCombo.lineEdit().returnPressed.connect( |
128 self.on_replaceButton_clicked) | 140 self.on_replaceButton_clicked) |
129 | 141 |
130 self.findNextAct = E5Action(self.trUtf8('Find Next'), | 142 self.findNextAct = E5Action(self.trUtf8('Find Next'), |
268 E5MessageBox.information(self, self.windowTitle(), | 280 E5MessageBox.information(self, self.windowTitle(), |
269 self.trUtf8("'{0}' was not found.").format(txt)) | 281 self.trUtf8("'{0}' was not found.").format(txt)) |
270 | 282 |
271 def __findByReturnPressed(self): | 283 def __findByReturnPressed(self): |
272 """ | 284 """ |
273 Private slot to handle the returnPressed signal of the findtext combobox. | 285 Private slot to handle the returnPressed signal of the findtext |
286 combobox. | |
274 """ | 287 """ |
275 if self.__findBackwards: | 288 if self.__findBackwards: |
276 self.findPrev() | 289 self.findPrev() |
277 else: | 290 else: |
278 self.findNext() | 291 self.findNext() |
421 if backwards: | 434 if backwards: |
422 if after: | 435 if after: |
423 line, index = self.__selections[ind][2:] | 436 line, index = self.__selections[ind][2:] |
424 else: | 437 else: |
425 if ind > 0: | 438 if ind > 0: |
426 line, index = self.__selections[ind - 1][2:] | 439 line, index = \ |
440 self.__selections[ind - 1][2:] | |
427 else: | 441 else: |
428 if after: | 442 if after: |
429 if ind < len(self.__selections) - 1: | 443 if ind < len(self.__selections) - 1: |
430 line, index = self.__selections[ind + 1][:2] | 444 line, index = \ |
445 self.__selections[ind + 1][:2] | |
431 else: | 446 else: |
432 line, index = self.__selections[ind][:2] | 447 line, index = self.__selections[ind][:2] |
433 break | 448 break |
434 else: | 449 else: |
435 break | 450 break |
439 self.ui.wordCheckBox.isChecked(), | 454 self.ui.wordCheckBox.isChecked(), |
440 self.ui.wrapCheckBox.isChecked(), | 455 self.ui.wrapCheckBox.isChecked(), |
441 not backwards, | 456 not backwards, |
442 line, index) | 457 line, index) |
443 if ok: | 458 if ok: |
444 lineFrom, indexFrom, lineTo, indexTo = aw.getSelection() | 459 lineFrom, indexFrom, lineTo, indexTo = \ |
445 if lineFrom < boundary[0] or lineFrom > boundary[2] or \ | 460 aw.getSelection() |
446 indexFrom < boundary[1] or indexFrom > boundary[3] or \ | 461 if lineFrom < boundary[0] or \ |
447 indexTo < boundary[1] or indexTo > boundary[3]: | 462 lineFrom > boundary[2] or \ |
463 indexFrom < boundary[1] or \ | |
464 indexFrom > boundary[3] or \ | |
465 indexTo < boundary[1] or \ | |
466 indexTo > boundary[3]: | |
448 ok = False | 467 ok = False |
449 break | 468 break |
450 if not ok: | 469 if not ok: |
451 if self.ui.wrapCheckBox.isChecked(): | 470 if self.ui.wrapCheckBox.isChecked(): |
452 # try it again | 471 # try it again |
460 self.ui.wordCheckBox.isChecked(), | 479 self.ui.wordCheckBox.isChecked(), |
461 self.ui.wrapCheckBox.isChecked(), | 480 self.ui.wrapCheckBox.isChecked(), |
462 not backwards, | 481 not backwards, |
463 line, index) | 482 line, index) |
464 if ok: | 483 if ok: |
465 lineFrom, indexFrom, lineTo, indexTo = aw.getSelection() | 484 lineFrom, indexFrom, lineTo, indexTo = \ |
485 aw.getSelection() | |
466 if len(self.__selections) > 1: | 486 if len(self.__selections) > 1: |
467 for sel in self.__selections: | 487 for sel in self.__selections: |
468 if lineFrom == sel[0] and \ | 488 if lineFrom == sel[0] and \ |
469 indexFrom >= sel[1] and \ | 489 indexFrom >= sel[1] and \ |
470 indexTo <= sel[3]: | 490 indexTo <= sel[3]: |
543 @param editor reference to the editor (Editor) | 563 @param editor reference to the editor (Editor) |
544 """ | 564 """ |
545 if not self.__finding and isinstance(editor, Editor): | 565 if not self.__finding and isinstance(editor, Editor): |
546 if editor.hasSelectedText(): | 566 if editor.hasSelectedText(): |
547 selections = editor.getSelections() | 567 selections = editor.getSelections() |
548 line1, index1, line2, index2 = self.__selectionBoundary(selections) | 568 line1, index1, line2, index2 = \ |
569 self.__selectionBoundary(selections) | |
549 if line1 != line2: | 570 if line1 != line2: |
550 self.ui.selectionCheckBox.setEnabled(True) | 571 self.ui.selectionCheckBox.setEnabled(True) |
551 self.ui.selectionCheckBox.setChecked(True) | 572 self.ui.selectionCheckBox.setChecked(True) |
552 self.__selections = selections | 573 self.__selections = selections |
553 return | 574 return |
564 self.__doReplace(False) | 585 self.__doReplace(False) |
565 | 586 |
566 @pyqtSlot() | 587 @pyqtSlot() |
567 def on_replaceSearchButton_clicked(self): | 588 def on_replaceSearchButton_clicked(self): |
568 """ | 589 """ |
569 Private slot to replace one occurrence of text and search for the next one. | 590 Private slot to replace one occurrence of text and search for the next |
591 one. | |
570 """ | 592 """ |
571 self.__doReplace(True) | 593 self.__doReplace(True) |
572 | 594 |
573 def __doReplace(self, searchNext): | 595 def __doReplace(self, searchNext): |
574 """ | 596 """ |
575 Private method to replace one occurrence of text. | 597 Private method to replace one occurrence of text. |
576 | 598 |
577 @param searchNext flag indicating to search for the next occurrence (boolean). | 599 @param searchNext flag indicating to search for the next occurrence |
600 (boolean). | |
578 """ | 601 """ |
579 self.__finding = True | 602 self.__finding = True |
580 | 603 |
581 # Check enabled status due to dual purpose usage of this method | 604 # Check enabled status due to dual purpose usage of this method |
582 if not self.ui.replaceButton.isEnabled() and \ | 605 if not self.ui.replaceButton.isEnabled() and \ |
673 for ind in range(len(self.__selections)): | 696 for ind in range(len(self.__selections)): |
674 if lineFrom == self.__selections[ind][0]: | 697 if lineFrom == self.__selections[ind][0]: |
675 after = indexTo > self.__selections[ind][3] | 698 after = indexTo > self.__selections[ind][3] |
676 if after: | 699 if after: |
677 if ind < len(self.__selections) - 1: | 700 if ind < len(self.__selections) - 1: |
678 line, index = self.__selections[ind + 1][:2] | 701 line, index = \ |
702 self.__selections[ind + 1][:2] | |
679 else: | 703 else: |
680 line, index = self.__selections[ind][:2] | 704 line, index = self.__selections[ind][:2] |
681 break | 705 break |
682 else: | 706 else: |
683 break | 707 break |
685 self.ui.regexpCheckBox.isChecked(), | 709 self.ui.regexpCheckBox.isChecked(), |
686 self.ui.caseCheckBox.isChecked(), | 710 self.ui.caseCheckBox.isChecked(), |
687 self.ui.wordCheckBox.isChecked(), | 711 self.ui.wordCheckBox.isChecked(), |
688 False, True, line, index) | 712 False, True, line, index) |
689 if ok: | 713 if ok: |
690 lineFrom, indexFrom, lineTo, indexTo = aw.getSelection() | 714 lineFrom, indexFrom, lineTo, indexTo = \ |
691 if lineFrom < boundary[0] or lineFrom > boundary[2] or \ | 715 aw.getSelection() |
692 indexFrom < boundary[1] or indexFrom > boundary[3] or \ | 716 if lineFrom < boundary[0] or \ |
693 indexTo < boundary[1] or indexTo > boundary[3]: | 717 lineFrom > boundary[2] or \ |
718 indexFrom < boundary[1] or \ | |
719 indexFrom > boundary[3] or \ | |
720 indexTo < boundary[1] or \ | |
721 indexTo > boundary[3]: | |
694 ok = False | 722 ok = False |
695 break | 723 break |
696 | 724 |
697 if not ok: | 725 if not ok: |
698 aw.selectAll(False) | 726 aw.selectAll(False) |
827 @param vm reference to the viewmanager object | 855 @param vm reference to the viewmanager object |
828 @param parent parent widget of this widget (QWidget) | 856 @param parent parent widget of this widget (QWidget) |
829 """ | 857 """ |
830 super().__init__(parent) | 858 super().__init__(parent) |
831 | 859 |
832 self.__searchReplaceWidget = SearchReplaceWidget(replace, vm, self, True) | 860 self.__searchReplaceWidget = \ |
861 SearchReplaceWidget(replace, vm, self, True) | |
833 srHeight = self.__searchReplaceWidget.height() | 862 srHeight = self.__searchReplaceWidget.height() |
834 | 863 |
835 self.__layout = QHBoxLayout(self) | 864 self.__layout = QHBoxLayout(self) |
836 self.setLayout(self.__layout) | 865 self.setLayout(self.__layout) |
837 self.__layout.setContentsMargins(0, 0, 0, 0) | 866 self.__layout.setContentsMargins(0, 0, 0, 0) |
863 self.__layout.addWidget(self.__scroller) | 892 self.__layout.addWidget(self.__scroller) |
864 self.__layout.addWidget(self.__rightButton) | 893 self.__layout.addWidget(self.__rightButton) |
865 | 894 |
866 self.setMaximumHeight(srHeight) | 895 self.setMaximumHeight(srHeight) |
867 | 896 |
868 self.__searchReplaceWidget.searchListChanged.connect(self.searchListChanged) | 897 self.__searchReplaceWidget.searchListChanged.connect( |
898 self.searchListChanged) | |
869 self.__leftButton.clicked[()].connect(self.__slideLeft) | 899 self.__leftButton.clicked[()].connect(self.__slideLeft) |
870 self.__rightButton.clicked[()].connect(self.__slideRight) | 900 self.__rightButton.clicked[()].connect(self.__slideRight) |
871 | 901 |
872 def findNext(self): | 902 def findNext(self): |
873 """ | 903 """ |
907 super().show() | 937 super().show() |
908 self.__enableScrollerButtons() | 938 self.__enableScrollerButtons() |
909 | 939 |
910 def __slideLeft(self): | 940 def __slideLeft(self): |
911 """ | 941 """ |
912 Private slot to move the widget to the left, i.e. show contents to the right. | 942 Private slot to move the widget to the left, i.e. show contents to the |
943 right. | |
913 """ | 944 """ |
914 self.__slide(True) | 945 self.__slide(True) |
915 | 946 |
916 def __slideRight(self): | 947 def __slideRight(self): |
917 """ | 948 """ |
918 Private slot to move the widget to the right, i.e. show contents to the left. | 949 Private slot to move the widget to the right, i.e. show contents to |
950 the left. | |
919 """ | 951 """ |
920 self.__slide(False) | 952 self.__slide(False) |
921 | 953 |
922 def __slide(self, toLeft): | 954 def __slide(self, toLeft): |
923 """ | 955 """ |