Changeset View
Changeset View
Standalone View
Standalone View
src/search/katesearchbar.cpp
Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Line(s) | |||||
43 | #include <KLocalizedString> | 43 | #include <KLocalizedString> | ||
44 | 44 | | |||
45 | #include <QVBoxLayout> | 45 | #include <QVBoxLayout> | ||
46 | #include <QCheckBox> | 46 | #include <QCheckBox> | ||
47 | #include <QComboBox> | 47 | #include <QComboBox> | ||
48 | #include <QCompleter> | 48 | #include <QCompleter> | ||
49 | #include <QShortcut> | 49 | #include <QShortcut> | ||
50 | #include <QStringListModel> | 50 | #include <QStringListModel> | ||
51 | #include <QTime> | ||||
51 | 52 | | |||
52 | #include <memory> | | |||
53 | #include <vector> | 53 | #include <vector> | ||
54 | 54 | | |||
55 | // Turn debug messages on/off here | 55 | // Turn debug messages on/off here | ||
56 | // #define FAST_DEBUG_ENABLE | 56 | // #define FAST_DEBUG_ENABLE | ||
57 | 57 | | |||
58 | #ifdef FAST_DEBUG_ENABLE | 58 | #ifdef FAST_DEBUG_ENABLE | ||
59 | # define FAST_DEBUG(x) qCDebug(LOG_KTE) << x | 59 | # define FAST_DEBUG(x) qCDebug(LOG_KTE) << x | ||
60 | #else | 60 | #else | ||
61 | # define FAST_DEBUG(x) | 61 | # define FAST_DEBUG(x) | ||
62 | #endif | 62 | #endif | ||
63 | 63 | | |||
64 | using namespace KTextEditor; | 64 | using namespace KTextEditor; | ||
65 | 65 | | |||
66 | namespace | 66 | namespace | ||
67 | { | 67 | { | ||
68 | 68 | | |||
69 | // BCI: Add a real d-pointer | ||||
70 | class KateSearchBarPrivate | ||||
71 | { | ||||
72 | public: | ||||
73 | KTextEditor::MovingRange *m_workingRange = nullptr; | ||||
74 | KTextEditor::Range m_inputRange; | ||||
75 | QString m_replacement; | ||||
76 | uint m_matchCounter = 0; | ||||
77 | bool m_replaceMode = false; | ||||
78 | bool m_cancelFindOrReplace = true; | ||||
79 | std::vector<KTextEditor::Range> m_highlightRanges; | ||||
80 | }; | ||||
81 | | ||||
82 | typedef QHash<const KateSearchBar *, KateSearchBarPrivate *> KateSearchBarPrivateHash; | ||||
83 | Q_GLOBAL_STATIC(KateSearchBarPrivateHash, d_func) | ||||
anthonyfieroni: It's not needed, right? | |||||
84 | static KateSearchBarPrivate *d(const KateSearchBar *foo) | ||||
85 | { | ||||
86 | KateSearchBarPrivate *ret = d_func()->value(foo); | ||||
87 | if (!ret) { | ||||
88 | ret = new KateSearchBarPrivate; | ||||
89 | d_func()->insert(foo, ret); | ||||
You can take another approach connect(foo, &Qobject::destroyed, d_func, [foo]() { delete d_func()->take(foo); }); anthonyfieroni: You can take another approach
```
connect(foo, &Qobject::destroyed, d_func, [foo]() { delete… | |||||
90 | } | ||||
91 | return ret; | ||||
92 | } | ||||
93 | | ||||
94 | static void delete_d(const KateSearchBar *foo) | ||||
95 | { | ||||
96 | delete d_func()->take(foo); | ||||
97 | } | ||||
anthonyfieroni: Remove. | |||||
98 | | ||||
69 | class AddMenuManager | 99 | class AddMenuManager | ||
anthonyfieroni: Use directly
```
delete d_func()->take(foo);
``` | |||||
70 | { | 100 | { | ||
71 | 101 | | |||
72 | private: | 102 | private: | ||
73 | QVector<QString> m_insertBefore; | 103 | QVector<QString> m_insertBefore; | ||
74 | QVector<QString> m_insertAfter; | 104 | QVector<QString> m_insertAfter; | ||
75 | QSet<QAction *> m_actionPointers; | 105 | QSet<QAction *> m_actionPointers; | ||
76 | uint m_indexWalker; | 106 | uint m_indexWalker; | ||
77 | QMenu *m_menu; | 107 | QMenu *m_menu; | ||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Line(s) | 173 | : KateViewBarWidget(true, view), | |||
154 | m_incFromCursor(true), | 184 | m_incFromCursor(true), | ||
155 | m_incMatchCase(false), | 185 | m_incMatchCase(false), | ||
156 | m_powerMatchCase(true), | 186 | m_powerMatchCase(true), | ||
157 | m_powerFromCursor(false), | 187 | m_powerFromCursor(false), | ||
158 | m_powerHighlightAll(false), | 188 | m_powerHighlightAll(false), | ||
159 | m_powerMode(0) | 189 | m_powerMode(0) | ||
160 | { | 190 | { | ||
161 | 191 | | |||
162 | connect(view, SIGNAL(cursorPositionChanged(KTextEditor::View*,KTextEditor::Cursor)), | 192 | connect(view, &KTextEditor::View::cursorPositionChanged, this, &KateSearchBar::updateIncInitCursor); | ||
163 | this, SLOT(updateIncInitCursor())); | 193 | connect(view, &KTextEditor::View::selectionChanged, this, &KateSearchBar::updateSelectionOnly); | ||
194 | connect(this, &KateSearchBar::findOrReplaceAllFinished, this, &KateSearchBar::endFindOrReplaceAll); | ||||
164 | 195 | | |||
165 | // init match attribute | 196 | // init match attribute | ||
166 | Attribute::Ptr mouseInAttribute(new Attribute()); | 197 | Attribute::Ptr mouseInAttribute(new Attribute()); | ||
167 | mouseInAttribute->setFontBold(true); | 198 | mouseInAttribute->setFontBold(true); | ||
168 | highlightMatchAttribute->setDynamicAttribute(Attribute::ActivateMouseIn, mouseInAttribute); | 199 | highlightMatchAttribute->setDynamicAttribute(Attribute::ActivateMouseIn, mouseInAttribute); | ||
169 | 200 | | |||
170 | Attribute::Ptr caretInAttribute(new Attribute()); | 201 | Attribute::Ptr caretInAttribute(new Attribute()); | ||
171 | caretInAttribute->setFontItalic(true); | 202 | caretInAttribute->setFontItalic(true); | ||
Show All 28 Lines | |||||
200 | // Load one of either dialogs | 231 | // Load one of either dialogs | ||
201 | if (initAsPower) { | 232 | if (initAsPower) { | ||
202 | enterPowerMode(); | 233 | enterPowerMode(); | ||
203 | } else { | 234 | } else { | ||
204 | enterIncrementalMode(); | 235 | enterIncrementalMode(); | ||
205 | } | 236 | } | ||
206 | 237 | | |||
207 | updateSelectionOnly(); | 238 | updateSelectionOnly(); | ||
208 | connect(view, SIGNAL(selectionChanged(KTextEditor::View*)), | | |||
209 | this, SLOT(updateSelectionOnly())); | | |||
210 | } | 239 | } | ||
211 | 240 | | |||
212 | KateSearchBar::~KateSearchBar() | 241 | KateSearchBar::~KateSearchBar() | ||
213 | { | 242 | { | ||
243 | if (!d(this)->m_cancelFindOrReplace) { | ||||
244 | // Finish/Cancel the still running job to avoid a crash | ||||
245 | endFindOrReplaceAll(); | ||||
246 | } | ||||
247 | | ||||
214 | clearHighlights(); | 248 | clearHighlights(); | ||
215 | delete m_layout; | 249 | delete m_layout; | ||
216 | delete m_widget; | 250 | delete m_widget; | ||
217 | 251 | | |||
218 | delete m_incUi; | 252 | delete m_incUi; | ||
219 | delete m_powerUi; | 253 | delete m_powerUi; | ||
254 | | ||||
255 | delete_d(this); | ||||
220 | } | 256 | } | ||
221 | 257 | | |||
222 | void KateSearchBar::closed() | 258 | void KateSearchBar::closed() | ||
223 | { | 259 | { | ||
224 | // remove search from the view bar, because it vertically bloats up the | 260 | // remove search from the view bar, because it vertically bloats up the | ||
225 | // stacked layout in KateViewBar. | 261 | // stacked layout in KateViewBar. | ||
226 | if (viewBar()) { | 262 | if (viewBar()) { | ||
227 | viewBar()->removeBarWidget(this); | 263 | viewBar()->removeBarWidget(this); | ||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Line(s) | 307 | { | |||
274 | if (found) { | 310 | if (found) { | ||
275 | QComboBox *combo = m_powerUi != nullptr ? m_powerUi->pattern : m_incUi->pattern; | 311 | QComboBox *combo = m_powerUi != nullptr ? m_powerUi->pattern : m_incUi->pattern; | ||
276 | 312 | | |||
277 | // Add to search history | 313 | // Add to search history | ||
278 | addCurrentTextToHistory(combo); | 314 | addCurrentTextToHistory(combo); | ||
279 | } | 315 | } | ||
280 | } | 316 | } | ||
281 | 317 | | |||
282 | void KateSearchBar::showInfoMessage(const QString &text) | 318 | void KateSearchBar::showResultMessage() | ||
283 | { | 319 | { | ||
284 | delete m_infoMessage; | 320 | QString text; | ||
285 | 321 | | |||
286 | m_infoMessage = new KTextEditor::Message(text, KTextEditor::Message::Positive); | 322 | if (d(this)->m_replaceMode) { | ||
287 | m_infoMessage->setPosition(KTextEditor::Message::BottomInView); | 323 | text = i18ncp("short translation", "1 replacement made", "%1 replacements made", d(this)->m_matchCounter); | ||
288 | m_infoMessage->setAutoHide(3000); // 3 seconds | 324 | } else { | ||
289 | m_infoMessage->setView(m_view); | 325 | text = i18ncp("short translation", "1 match found", "%1 matches found", d(this)->m_matchCounter); | ||
326 | } | ||||
290 | 327 | | |||
291 | m_view->doc()->postMessage(m_infoMessage); | 328 | if (m_infoMessage) { | ||
329 | m_infoMessage->setText(text); | ||||
330 | } else { | ||||
331 | m_infoMessage = new KTextEditor::Message(text, KTextEditor::Message::Positive); | ||||
332 | m_infoMessage->setPosition(KTextEditor::Message::BottomInView); | ||||
333 | m_infoMessage->setAutoHide(3000); // 3 seconds | ||||
334 | m_infoMessage->setView(m_view); | ||||
335 | m_view->doc()->postMessage(m_infoMessage); | ||||
336 | } | ||||
292 | } | 337 | } | ||
293 | 338 | | |||
294 | void KateSearchBar::highlightMatch(const Range &range) | 339 | void KateSearchBar::highlightMatch(const Range &range) | ||
295 | { | 340 | { | ||
296 | KTextEditor::MovingRange *const highlight = m_view->doc()->newMovingRange(range, Kate::TextRange::DoNotExpand); | 341 | KTextEditor::MovingRange *const highlight = m_view->doc()->newMovingRange(range, Kate::TextRange::DoNotExpand); | ||
297 | highlight->setView(m_view); // show only in this view | 342 | highlight->setView(m_view); // show only in this view | ||
298 | highlight->setAttributeOnlyForViews(true); | 343 | highlight->setAttributeOnlyForViews(true); | ||
299 | // use z depth defined in moving ranges interface | 344 | // use z depth defined in moving ranges interface | ||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Line(s) | 555 | } else { | |||
512 | findNext(); | 557 | findNext(); | ||
513 | } | 558 | } | ||
514 | 559 | | |||
515 | if (controlDown) { | 560 | if (controlDown) { | ||
516 | emit hideMe(); | 561 | emit hideMe(); | ||
517 | } | 562 | } | ||
518 | } | 563 | } | ||
519 | 564 | | |||
565 | //BCI: Remove | ||||
520 | bool KateSearchBar::find(SearchDirection searchDirection, const QString *replacement) | 566 | bool KateSearchBar::find(SearchDirection searchDirection, const QString *replacement) | ||
567 | { | ||||
568 | Q_UNUSED(replacement) | ||||
569 | return findOrReplace(searchDirection, nullptr); | ||||
570 | } | ||||
571 | | ||||
572 | bool KateSearchBar::findOrReplace(SearchDirection searchDirection, const QString *replacement) | ||||
521 | { | 573 | { | ||
522 | // What to find? | 574 | // What to find? | ||
523 | if (searchPattern().isEmpty()) { | 575 | if (searchPattern().isEmpty()) { | ||
524 | return false; // == Pattern error | 576 | return false; // == Pattern error | ||
525 | } | 577 | } | ||
526 | 578 | | |||
527 | // don't let selectionChanged signal mess around in this routine | 579 | // don't let selectionChanged signal mess around in this routine | ||
528 | disconnect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | 580 | disconnect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | ||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Line(s) | |||||
660 | void KateSearchBar::findAll() | 712 | void KateSearchBar::findAll() | ||
661 | { | 713 | { | ||
662 | // clear highlightings of prior search&replace action | 714 | // clear highlightings of prior search&replace action | ||
663 | clearHighlights(); | 715 | clearHighlights(); | ||
664 | 716 | | |||
665 | Range inputRange = (m_view->selection() && selectionOnly()) | 717 | Range inputRange = (m_view->selection() && selectionOnly()) | ||
666 | ? m_view->selectionRange() | 718 | ? m_view->selectionRange() | ||
667 | : m_view->document()->documentRange(); | 719 | : m_view->document()->documentRange(); | ||
668 | const int occurrences = findAll(inputRange, nullptr); | | |||
669 | | ||||
670 | // send passive notification to view | | |||
671 | showInfoMessage(i18ncp("short translation", "1 match found", "%1 matches found", occurrences)); | | |||
672 | 720 | | |||
673 | indicateMatch(occurrences > 0 ? MatchFound : MatchMismatch); | 721 | beginFindAll(inputRange); | ||
674 | } | 722 | } | ||
675 | 723 | | |||
676 | void KateSearchBar::onPowerPatternChanged(const QString & /*pattern*/) | 724 | void KateSearchBar::onPowerPatternChanged(const QString & /*pattern*/) | ||
677 | { | 725 | { | ||
678 | givePatternFeedback(); | 726 | givePatternFeedback(); | ||
679 | indicateMatch(MatchNothing); | 727 | indicateMatch(MatchNothing); | ||
680 | } | 728 | } | ||
681 | 729 | | |||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Line(s) | 779 | { | |||
777 | // Adjust global config | 825 | // Adjust global config | ||
778 | m_config->setSearchFlags(futureFlags); | 826 | m_config->setSearchFlags(futureFlags); | ||
779 | } | 827 | } | ||
780 | 828 | | |||
781 | void KateSearchBar::replaceNext() | 829 | void KateSearchBar::replaceNext() | ||
782 | { | 830 | { | ||
783 | const QString replacement = m_powerUi->replacement->currentText(); | 831 | const QString replacement = m_powerUi->replacement->currentText(); | ||
784 | 832 | | |||
785 | if (find(SearchForward, &replacement)) { | 833 | if (findOrReplace(SearchForward, &replacement)) { | ||
786 | // Never merge replace actions with other replace actions/user actions | 834 | // Never merge replace actions with other replace actions/user actions | ||
787 | m_view->doc()->undoManager()->undoSafePoint(); | 835 | m_view->doc()->undoManager()->undoSafePoint(); | ||
788 | 836 | | |||
789 | // Add to search history | 837 | // Add to search history | ||
790 | addCurrentTextToHistory(m_powerUi->pattern); | 838 | addCurrentTextToHistory(m_powerUi->pattern); | ||
791 | 839 | | |||
792 | // Add to replace history | 840 | // Add to replace history | ||
793 | addCurrentTextToHistory(m_powerUi->replacement); | 841 | addCurrentTextToHistory(m_powerUi->replacement); | ||
794 | } | 842 | } | ||
795 | } | 843 | } | ||
796 | 844 | | |||
797 | // replacement == NULL --> Highlight all matches | 845 | // replacement == NULL --> Only highlight all matches | ||
798 | // replacement != NULL --> Replace and highlight all matches | 846 | // replacement != NULL --> Replace and highlight all matches | ||
799 | int KateSearchBar::findAll(Range inputRange, const QString *replacement) | 847 | void KateSearchBar::beginFindOrReplaceAll(Range inputRange, const QString &replacement, bool replaceMode/* = true*/) | ||
800 | { | 848 | { | ||
801 | // don't let selectionChanged signal mess around in this routine | 849 | // don't let selectionChanged signal mess around in this routine | ||
802 | disconnect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | 850 | disconnect(m_view, &KTextEditor::View::selectionChanged, this, &KateSearchBar::updateSelectionOnly); | ||
851 | // Cancel job when user close the document to avoid crash | ||||
852 | connect(m_view->doc(), &KTextEditor::Document::aboutToClose, this, &KateSearchBar::endFindOrReplaceAll); | ||||
853 | | ||||
854 | // Offer Cancel button and disable not useful buttons | ||||
855 | m_powerUi->searchCancelStacked->setCurrentIndex(m_powerUi->searchCancelStacked->indexOf(m_powerUi->cancelPage)); | ||||
856 | m_powerUi->findNext->setEnabled(false); | ||||
857 | m_powerUi->findPrev->setEnabled(false); | ||||
858 | m_powerUi->replaceNext->setEnabled(false); | ||||
859 | | ||||
860 | auto dd = d(this); // Improve the readability and prevent unwanted lookup | ||||
861 | dd->m_inputRange = inputRange; | ||||
862 | dd->m_workingRange = m_view->doc()->newMovingRange(dd->m_inputRange); | ||||
863 | dd->m_replacement = replacement; | ||||
864 | dd->m_replaceMode = replaceMode; | ||||
865 | dd->m_matchCounter = 0; | ||||
Maybe not an issue, but you can try to cache value preventing unwanted lookup auto dd = d(this); dd->... anthonyfieroni: Maybe not an issue, but you can try to cache value preventing unwanted lookup
```
auto dd = d… | |||||
Only here or everywhere? loh.tar: Only here or everywhere?
At this particular place may that optimized by the compiler(?)
| |||||
866 | dd->m_cancelFindOrReplace = false; // Ensure we have a GO! | ||||
867 | | ||||
868 | findOrReplaceAll(); | ||||
869 | } | ||||
803 | 870 | | |||
871 | void KateSearchBar::findOrReplaceAll() | ||||
872 | { | ||||
804 | const SearchOptions enabledOptions = searchOptions(SearchForward); | 873 | const SearchOptions enabledOptions = searchOptions(SearchForward); | ||
805 | 874 | | |||
806 | const bool regexMode = enabledOptions.testFlag(Regex); | 875 | const bool regexMode = enabledOptions.testFlag(Regex); | ||
807 | const bool multiLinePattern = regexMode ? KateRegExp(searchPattern()).isMultiLine() : false; | 876 | const bool multiLinePattern = regexMode ? KateRegExp(searchPattern()).isMultiLine() : false; | ||
808 | 877 | | |||
809 | std::unique_ptr<KTextEditor::MovingRange> workingRange(m_view->doc()->newMovingRange(inputRange)); | | |||
810 | int matchCounter = 0; | | |||
811 | | ||||
812 | // we highlight all ranges of a replace, up to some hard limit | 878 | // we highlight all ranges of a replace, up to some hard limit | ||
813 | // e.g. if you replace 100000 things, rendering will break down otherwise ;=) | 879 | // e.g. if you replace 100000 things, rendering will break down otherwise ;=) | ||
814 | const int maxHighlightings = 65536; | 880 | const int maxHighlightings = 65536; | ||
815 | std::vector<Range> highlightRanges; | | |||
816 | 881 | | |||
817 | // reuse match object to avoid massive moving range creation | 882 | // reuse match object to avoid massive moving range creation | ||
818 | KateMatch match(m_view->doc(), enabledOptions); | 883 | KateMatch match(m_view->doc(), enabledOptions); | ||
819 | 884 | | |||
820 | bool block = m_view->selection() && m_view->blockSelection(); | 885 | bool block = m_view->selection() && m_view->blockSelection(); | ||
821 | int line = inputRange.start().line(); | 886 | | ||
887 | auto dd = d(this); // Improve the readability and prevent unwanted lookup | ||||
888 | int line = dd->m_inputRange.start().line(); | ||||
889 | | ||||
890 | QTime rolex; // Watchog to suspend the work after some time | ||||
891 | rolex.start(); | ||||
892 | bool timeOut = false; | ||||
893 | bool done = false; | ||||
822 | do { | 894 | do { | ||
823 | if (block) { | 895 | if (block) { | ||
824 | workingRange.reset(m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(inputRange, line))); | 896 | delete dd->m_workingRange; // Never forget that! | ||
897 | dd->m_workingRange = m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(dd->m_inputRange, line)); | ||||
825 | } | 898 | } | ||
826 | 899 | | |||
827 | for (;;) { | 900 | do { | ||
828 | match.searchText(*workingRange, searchPattern()); | 901 | match.searchText(*dd->m_workingRange, searchPattern()); | ||
829 | if (!match.isValid()) { | 902 | if (!match.isValid()) { | ||
903 | done = true; | ||||
830 | break; | 904 | break; | ||
831 | } | 905 | } | ||
832 | bool const originalMatchEmpty = match.isEmpty(); | 906 | bool const originalMatchEmpty = match.isEmpty(); | ||
833 | 907 | | |||
834 | // Work with the match | 908 | // Work with the match | ||
835 | Range lastRange; | 909 | Range lastRange; | ||
836 | if (replacement != nullptr) { | 910 | if (dd->m_replaceMode) { | ||
837 | if (matchCounter == 0) { | 911 | if (dd->m_matchCounter == 0) { | ||
838 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->startEditing(); | 912 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->startEditing(); | ||
839 | } | 913 | } | ||
840 | 914 | | |||
841 | // Replace | 915 | // Replace | ||
842 | lastRange = match.replace(*replacement, false, ++matchCounter); | 916 | lastRange = match.replace(dd->m_replacement, false, ++dd->m_matchCounter); | ||
843 | } else { | 917 | } else { | ||
844 | lastRange = match.range(); | 918 | lastRange = match.range(); | ||
845 | ++matchCounter; | 919 | ++dd->m_matchCounter; | ||
846 | } | 920 | } | ||
847 | 921 | | |||
848 | // remember ranges if limit not reached | 922 | // remember ranges if limit not reached | ||
849 | if (matchCounter < maxHighlightings) { | 923 | if (dd->m_matchCounter < maxHighlightings) { | ||
850 | highlightRanges.push_back(lastRange); | 924 | dd->m_highlightRanges.push_back(lastRange); | ||
851 | } else { | 925 | } else { | ||
852 | highlightRanges.clear(); | 926 | dd->m_highlightRanges.clear(); | ||
927 | // TODO Info user that highlighting is disabled | ||||
853 | } | 928 | } | ||
854 | 929 | | |||
855 | // Continue after match | 930 | // Continue after match | ||
856 | if (lastRange.end() >= workingRange->end()) { | 931 | if (lastRange.end() >= dd->m_workingRange->end()) { | ||
932 | done = true; | ||||
857 | break; | 933 | break; | ||
858 | } | 934 | } | ||
859 | 935 | | |||
860 | KTextEditor::DocumentCursor workingStart(m_view->doc(), lastRange.end()); | 936 | KTextEditor::DocumentCursor workingStart(m_view->doc(), lastRange.end()); | ||
937 | | ||||
861 | if (originalMatchEmpty) { | 938 | if (originalMatchEmpty) { | ||
862 | // Can happen for regex patterns like "^". | 939 | // Can happen for regex patterns like "^". | ||
863 | // If we don't advance here we will loop forever... | 940 | // If we don't advance here we will loop forever... | ||
864 | workingStart.move(1); | 941 | workingStart.move(1); | ||
865 | } else if (regexMode && !multiLinePattern && workingStart.atEndOfLine()) { | 942 | } else if (regexMode && !multiLinePattern && workingStart.atEndOfLine()) { | ||
866 | // single-line regexps might match the naked line end | 943 | // single-line regexps might match the naked line end | ||
867 | // therefore we better advance to the next line | 944 | // therefore we better advance to the next line | ||
868 | workingStart.move(1); | 945 | workingStart.move(1); | ||
869 | } | 946 | } | ||
870 | workingRange->setRange(workingStart.toCursor(), workingRange->end()); | 947 | dd->m_workingRange->setRange(workingStart.toCursor(), dd->m_workingRange->end()); | ||
871 | 948 | | |||
872 | // Are we done? | 949 | // Are we done? | ||
873 | if (!workingRange->toRange().isValid() || workingStart.atEndOfDocument()) { | 950 | if (!dd->m_workingRange->toRange().isValid() || workingStart.atEndOfDocument()) { | ||
951 | done = true; | ||||
874 | break; | 952 | break; | ||
875 | } | 953 | } | ||
876 | } | | |||
877 | 954 | | |||
878 | } while (block && ++line <= inputRange.end().line()); | 955 | timeOut = rolex.elapsed() > 150; | ||
956 | | ||||
957 | } while (!dd->m_cancelFindOrReplace && !timeOut); | ||||
958 | | ||||
959 | } while (!dd->m_cancelFindOrReplace && !timeOut && block && ++line <= dd->m_inputRange.end().line()); | ||||
879 | 960 | | |||
961 | if (done || dd->m_cancelFindOrReplace) { | ||||
962 | emit findOrReplaceAllFinished(); | ||||
963 | } else if (timeOut) { | ||||
964 | QTimer::singleShot(0, this, &KateSearchBar::findOrReplaceAll); | ||||
965 | } | ||||
966 | | ||||
967 | showResultMessage(); | ||||
968 | } | ||||
969 | | ||||
970 | void KateSearchBar::endFindOrReplaceAll() | ||||
971 | { | ||||
972 | // Don't forget to remove our "crash protector" | ||||
973 | disconnect(m_view->doc(), &KTextEditor::Document::aboutToClose, this, &KateSearchBar::endFindOrReplaceAll); | ||||
974 | | ||||
975 | auto dd = d(this); // Improve the readability and prevent unwanted lookup | ||||
880 | // After last match | 976 | // After last match | ||
881 | if (matchCounter > 0) { | 977 | if (dd->m_matchCounter > 0) { | ||
882 | if (replacement != nullptr) { | 978 | if (dd->m_replaceMode) { | ||
883 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->finishEditing(); | 979 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->finishEditing(); | ||
884 | } | 980 | } | ||
885 | } | 981 | } | ||
886 | 982 | | |||
887 | // Add ScrollBarMarks | 983 | // Add ScrollBarMarks | ||
888 | if (!highlightRanges.empty()) { | 984 | if (!dd->m_highlightRanges.empty()) { | ||
889 | KTextEditor::MarkInterface* iface = qobject_cast<KTextEditor::MarkInterface*>(m_view->document()); | 985 | KTextEditor::MarkInterface* iface = qobject_cast<KTextEditor::MarkInterface*>(m_view->document()); | ||
890 | if (iface) { | 986 | if (iface) { | ||
891 | iface->setMarkDescription(KTextEditor::MarkInterface::SearchMatch, i18n("SearchHighLight")); | 987 | iface->setMarkDescription(KTextEditor::MarkInterface::SearchMatch, i18n("SearchHighLight")); | ||
892 | iface->setMarkPixmap(KTextEditor::MarkInterface::SearchMatch, QIcon().pixmap(0,0)); | 988 | iface->setMarkPixmap(KTextEditor::MarkInterface::SearchMatch, QIcon().pixmap(0,0)); | ||
893 | for (const Range &r : highlightRanges) { | 989 | for (const Range &r : dd->m_highlightRanges) { | ||
894 | iface->addMark(r.start().line(), KTextEditor::MarkInterface::SearchMatch); | 990 | iface->addMark(r.start().line(), KTextEditor::MarkInterface::SearchMatch); | ||
895 | } | 991 | } | ||
896 | } | 992 | } | ||
897 | } | 993 | } | ||
898 | 994 | | |||
899 | // Add highlights | 995 | // Add highlights | ||
900 | if (replacement == nullptr) { | 996 | if (dd->m_replaceMode) { | ||
901 | for (const Range &r : highlightRanges) { | 997 | for (const Range &r : qAsConst(dd->m_highlightRanges)) { | ||
902 | highlightMatch(r); | 998 | highlightReplacement(r); | ||
903 | } | 999 | } | ||
1000 | // Never merge replace actions with other replace actions/user actions | ||||
1001 | m_view->doc()->undoManager()->undoSafePoint(); | ||||
1002 | | ||||
904 | } else { | 1003 | } else { | ||
905 | for (const Range &r : highlightRanges) { | 1004 | for (const Range &r : qAsConst(dd->m_highlightRanges)) { | ||
906 | highlightReplacement(r); | 1005 | highlightMatch(r); | ||
907 | } | 1006 | } | ||
1007 | // indicateMatch(dd->m_matchCounter > 0 ? MatchFound : MatchMismatch); TODO | ||||
908 | } | 1008 | } | ||
909 | 1009 | | |||
1010 | // Clean-Up the still hold MovingRange | ||||
1011 | delete dd->m_workingRange; | ||||
1012 | | ||||
910 | // restore connection | 1013 | // restore connection | ||
911 | connect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | 1014 | connect(m_view, &KTextEditor::View::selectionChanged, this, &KateSearchBar::updateSelectionOnly); | ||
1015 | | ||||
1016 | // Offer Find and Replace buttons and enable again useful buttons | ||||
1017 | m_powerUi->searchCancelStacked->setCurrentIndex(m_powerUi->searchCancelStacked->indexOf(m_powerUi->searchPage)); | ||||
1018 | m_powerUi->findNext->setEnabled(true); | ||||
1019 | m_powerUi->findPrev->setEnabled(true); | ||||
1020 | m_powerUi->replaceNext->setEnabled(true); | ||||
912 | 1021 | | |||
913 | return matchCounter; | 1022 | // Add to search history | ||
1023 | addCurrentTextToHistory(m_powerUi->pattern); | ||||
1024 | | ||||
1025 | // Add to replace history | ||||
1026 | addCurrentTextToHistory(m_powerUi->replacement); | ||||
1027 | | ||||
1028 | dd->m_cancelFindOrReplace = true; // Indicate we are not running | ||||
914 | } | 1029 | } | ||
915 | 1030 | | |||
916 | void KateSearchBar::replaceAll() | 1031 | void KateSearchBar::replaceAll() | ||
917 | { | 1032 | { | ||
918 | // clear prior highlightings (deletes info message if present) | 1033 | // clear prior highlightings (deletes info message if present) | ||
919 | clearHighlights(); | 1034 | clearHighlights(); | ||
920 | 1035 | | |||
921 | // What to find/replace? | 1036 | // What to find/replace? | ||
922 | const QString replacement = m_powerUi->replacement->currentText(); | 1037 | const QString replacement = m_powerUi->replacement->currentText(); | ||
923 | 1038 | | |||
924 | // Where to replace? | 1039 | // Where to replace? | ||
925 | const bool selected = m_view->selection(); | 1040 | const bool selected = m_view->selection(); | ||
926 | Range inputRange = (selected && selectionOnly()) | 1041 | Range inputRange = (selected && selectionOnly()) | ||
927 | ? m_view->selectionRange() | 1042 | ? m_view->selectionRange() | ||
928 | : m_view->document()->documentRange(); | 1043 | : m_view->document()->documentRange(); | ||
929 | 1044 | | |||
930 | // Pass on the hard work | 1045 | beginFindOrReplaceAll(inputRange, replacement); | ||
931 | int replacementsDone = findAll(inputRange, &replacement); | | |||
932 | | ||||
933 | // send passive notification to view | | |||
934 | showInfoMessage(i18ncp("short translation", "1 replacement made", "%1 replacements made", replacementsDone)); | | |||
935 | | ||||
936 | // Never merge replace actions with other replace actions/user actions | | |||
937 | m_view->doc()->undoManager()->undoSafePoint(); | | |||
938 | | ||||
939 | // Add to search history | | |||
940 | addCurrentTextToHistory(m_powerUi->pattern); | | |||
941 | | ||||
942 | // Add to replace history | | |||
943 | addCurrentTextToHistory(m_powerUi->replacement); | | |||
944 | } | 1046 | } | ||
945 | 1047 | | |||
946 | void KateSearchBar::setSearchPattern(const QString &searchPattern) | 1048 | void KateSearchBar::setSearchPattern(const QString &searchPattern) | ||
947 | { | 1049 | { | ||
948 | if (searchPattern == this->searchPattern()) { | 1050 | if (searchPattern == this->searchPattern()) { | ||
949 | return; | 1051 | return; | ||
950 | } | 1052 | } | ||
951 | 1053 | | |||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Line(s) | 1487 | if (create) { | |||
1388 | connect(patternLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onPowerPatternChanged(QString))); | 1490 | connect(patternLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onPowerPatternChanged(QString))); | ||
1389 | connect(m_powerUi->findNext, SIGNAL(clicked()), this, SLOT(findNext())); | 1491 | connect(m_powerUi->findNext, SIGNAL(clicked()), this, SLOT(findNext())); | ||
1390 | connect(m_powerUi->findPrev, SIGNAL(clicked()), this, SLOT(findPrevious())); | 1492 | connect(m_powerUi->findPrev, SIGNAL(clicked()), this, SLOT(findPrevious())); | ||
1391 | connect(m_powerUi->replaceNext, SIGNAL(clicked()), this, SLOT(replaceNext())); | 1493 | connect(m_powerUi->replaceNext, SIGNAL(clicked()), this, SLOT(replaceNext())); | ||
1392 | connect(m_powerUi->replaceAll, SIGNAL(clicked()), this, SLOT(replaceAll())); | 1494 | connect(m_powerUi->replaceAll, SIGNAL(clicked()), this, SLOT(replaceAll())); | ||
1393 | connect(m_powerUi->searchMode, SIGNAL(currentIndexChanged(int)), this, SLOT(onPowerModeChanged(int))); | 1495 | connect(m_powerUi->searchMode, SIGNAL(currentIndexChanged(int)), this, SLOT(onPowerModeChanged(int))); | ||
1394 | connect(m_powerUi->matchCase, SIGNAL(toggled(bool)), this, SLOT(onMatchCaseToggled(bool))); | 1496 | connect(m_powerUi->matchCase, SIGNAL(toggled(bool)), this, SLOT(onMatchCaseToggled(bool))); | ||
1395 | connect(m_powerUi->findAll, SIGNAL(clicked()), this, SLOT(findAll())); | 1497 | connect(m_powerUi->findAll, SIGNAL(clicked()), this, SLOT(findAll())); | ||
1498 | connect(m_powerUi->cancel, &QPushButton::clicked, this, &KateSearchBar::onPowerCancelFindOrReplace); | ||||
1396 | 1499 | | |||
1397 | // Make [return] in pattern line edit trigger <find next> action | 1500 | // Make [return] in pattern line edit trigger <find next> action | ||
1398 | connect(patternLineEdit, SIGNAL(returnPressed()), this, SLOT(onReturnPressed())); | 1501 | connect(patternLineEdit, SIGNAL(returnPressed()), this, SLOT(onReturnPressed())); | ||
1399 | connect(replacementLineEdit, SIGNAL(returnPressed()), this, SLOT(replaceNext())); | 1502 | connect(replacementLineEdit, SIGNAL(returnPressed()), this, SLOT(replaceNext())); | ||
1400 | 1503 | | |||
1401 | // Hook into line edit context menus | 1504 | // Hook into line edit context menus | ||
1402 | m_powerUi->pattern->setContextMenuPolicy(Qt::CustomContextMenu); | 1505 | m_powerUi->pattern->setContextMenuPolicy(Qt::CustomContextMenu); | ||
1403 | connect(m_powerUi->pattern, SIGNAL(customContextMenuRequested(QPoint)), this, | 1506 | connect(m_powerUi->pattern, SIGNAL(customContextMenuRequested(QPoint)), this, | ||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Line(s) | 1744 | { | |||
1643 | showExtendedContextMenu(FOR_REPLACEMENT, pos); | 1746 | showExtendedContextMenu(FOR_REPLACEMENT, pos); | ||
1644 | } | 1747 | } | ||
1645 | 1748 | | |||
1646 | void KateSearchBar::onPowerReplacmentContextMenuRequest() | 1749 | void KateSearchBar::onPowerReplacmentContextMenuRequest() | ||
1647 | { | 1750 | { | ||
1648 | onPowerReplacmentContextMenuRequest(m_powerUi->replacement->mapFromGlobal(QCursor::pos())); | 1751 | onPowerReplacmentContextMenuRequest(m_powerUi->replacement->mapFromGlobal(QCursor::pos())); | ||
1649 | } | 1752 | } | ||
1650 | 1753 | | |||
1754 | void KateSearchBar::onPowerCancelFindOrReplace() | ||||
1755 | { | ||||
1756 | d(this)->m_cancelFindOrReplace = true; | ||||
1757 | } | ||||
1758 | | ||||
1651 | bool KateSearchBar::isPower() const | 1759 | bool KateSearchBar::isPower() const | ||
1652 | { | 1760 | { | ||
1653 | return m_powerUi != nullptr; | 1761 | return m_powerUi != nullptr; | ||
1654 | } | 1762 | } | ||
1655 | 1763 | | |||
1656 | void KateSearchBar::slotReadWriteChanged() | 1764 | void KateSearchBar::slotReadWriteChanged() | ||
1657 | { | 1765 | { | ||
1658 | if (!KateSearchBar::isPower()) { | 1766 | if (!KateSearchBar::isPower()) { | ||
1659 | return; | 1767 | return; | ||
1660 | } | 1768 | } | ||
1661 | 1769 | | |||
1662 | // perhaps disable/enable | 1770 | // perhaps disable/enable | ||
1663 | m_powerUi->replaceNext->setEnabled(m_view->doc()->isReadWrite() && isPatternValid()); | 1771 | m_powerUi->replaceNext->setEnabled(m_view->doc()->isReadWrite() && isPatternValid()); | ||
1664 | m_powerUi->replaceAll->setEnabled(m_view->doc()->isReadWrite() && isPatternValid()); | 1772 | m_powerUi->replaceAll->setEnabled(m_view->doc()->isReadWrite() && isPatternValid()); | ||
1665 | } | 1773 | } | ||
1666 | 1774 | | |||
Context not available. |
It's not needed, right?