00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "katesearchbar.h"
00022 #include "kateview.h"
00023 #include "katedocument.h"
00024 #include "kateglobal.h"
00025
00026 #include "ui_searchbarincremental.h"
00027 #include "ui_searchbarpower.h"
00028
00029 #include <kactioncollection.h>
00030
00031 #include <QtGui/QVBoxLayout>
00032 #include <QtGui/QComboBox>
00033 #include <QtGui/QCheckBox>
00034 #include <QStringListModel>
00035 #include <QCompleter>
00036
00037 using namespace KTextEditor;
00038
00039
00040
00041
00042
00043
00044 #ifdef FAST_DEBUG_ENABLE
00045 # define FAST_DEBUG(x) (kDebug() << x)
00046 #else
00047 # define FAST_DEBUG(x)
00048 #endif
00049
00050
00051
00052 KateSearchBar::KateSearchBar(KateViewBar * viewBar, bool initAsPower)
00053 : KateViewBarWidget(viewBar),
00054 m_view(viewBar->view()),
00055 m_topRange(NULL),
00056 m_layout(new QVBoxLayout()),
00057 m_widget(NULL),
00058 m_incUi(NULL),
00059 m_incMenu(NULL),
00060 m_incMenuMatchCase(NULL),
00061 m_incMenuFromCursor(NULL),
00062 m_incMenuHighlightAll(NULL),
00063 m_incInitCursor(0, 0),
00064 m_powerUi(NULL),
00065 m_incHighlightAll(false),
00066 m_incFromCursor(true),
00067 m_incMatchCase(false),
00068 m_powerMatchCase(true),
00069 m_powerFromCursor(false),
00070 m_powerHighlightAll(false),
00071 m_powerUsePlaceholders(false),
00072 m_powerMode(0) {
00073
00074 QWidget * const widget = centralWidget();
00075 widget->setLayout(m_layout);
00076 m_layout->setMargin(2);
00077
00078
00079 m_topRange = m_view->doc()->newSmartRange(m_view->doc()->documentRange());
00080 static_cast<KateSmartRange*>(m_topRange)->setInternal();
00081 m_topRange->setInsertBehavior(SmartRange::ExpandLeft | SmartRange::ExpandRight);
00082 enableHighlights(true);
00083
00084
00085
00086 KateViewConfig * const globalConfig = KateGlobal::self()->viewConfig();
00087 const long searchFlags = globalConfig->searchFlags();
00088 m_incHighlightAll = (searchFlags & KateViewConfig::IncHighlightAll) != 0;
00089 m_incFromCursor = (searchFlags & KateViewConfig::IncFromCursor) != 0;
00090 m_incMatchCase = (searchFlags & KateViewConfig::IncMatchCase) != 0;
00091 m_powerMatchCase = (searchFlags & KateViewConfig::PowerMatchCase) != 0;
00092 m_powerFromCursor = (searchFlags & KateViewConfig::PowerFromCursor) != 0;
00093 m_powerHighlightAll = (searchFlags & KateViewConfig::PowerHighlightAll) != 0;
00094 m_powerUsePlaceholders = (searchFlags & KateViewConfig::PowerUsePlaceholders) != 0;
00095 m_powerMode = ((searchFlags & KateViewConfig::PowerModeRegularExpression) != 0)
00096 ? MODE_REGEX
00097 : (((searchFlags & KateViewConfig::PowerModeEscapeSequences) != 0)
00098 ? MODE_ESCAPE_SEQUENCES
00099 : (((searchFlags & KateViewConfig::PowerModeWholeWords) != 0)
00100 ? MODE_WHOLE_WORDS
00101 : MODE_PLAIN_TEXT));
00102
00103
00104
00105 if (initAsPower) {
00106 onMutatePower();
00107 } else {
00108 onMutateIncremental();
00109 }
00110 }
00111
00112
00113
00114 KateSearchBar::~KateSearchBar() {
00115 delete m_topRange;
00116 delete m_layout;
00117 delete m_widget;
00118 delete m_incUi;
00119 delete m_incMenu;
00120 delete m_powerUi;
00121 }
00122
00123
00124
00125 void KateSearchBar::findNext() {
00126 if (m_incUi != NULL) {
00127 onIncNext();
00128 } else {
00129 onPowerFindNext();
00130 }
00131 }
00132
00133
00134
00135 void KateSearchBar::findPrevious() {
00136 if (m_incUi != NULL) {
00137 onIncPrev();
00138 } else {
00139 onPowerFindPrev();
00140 }
00141 }
00142
00143
00144
00145 void KateSearchBar::highlight(const Range & range, const QColor & color) {
00146 SmartRange * const highlight = m_view->doc()->newSmartRange(range, m_topRange);
00147 highlight->setInsertBehavior(SmartRange::DoNotExpand);
00148 Attribute::Ptr attribute(new Attribute());
00149 attribute->setBackground(color);
00150 highlight->setAttribute(attribute);
00151 }
00152
00153
00154
00155 void KateSearchBar::highlightMatch(const Range & range) {
00156 highlight(range, Qt::yellow);
00157 }
00158
00159
00160
00161 void KateSearchBar::highlightReplacement(const Range & range) {
00162 highlight(range, Qt::green);
00163 }
00164
00165
00166
00167 void KateSearchBar::highlightAllMatches(const QString & pattern,
00168 Search::SearchOptions searchOptions) {
00169 onForAll(pattern, m_view->doc()->documentRange(),
00170 searchOptions, NULL);
00171 }
00172
00173
00174
00175 void KateSearchBar::indicateMatch(bool wrapped) {
00176 if (m_incUi != NULL) {
00177
00178 QPalette background(m_incUi->pattern->palette());
00179 KColorScheme::adjustBackground(background, KColorScheme::PositiveBackground);
00180 m_incUi->pattern->setPalette(background);
00181
00182
00183 m_incUi->status->setText(wrapped
00184 ? i18n("Reached bottom, continued from top")
00185 : "");
00186 } else {
00187
00188 QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00189 Q_ASSERT(lineEdit != NULL);
00190 QPalette background(lineEdit->palette());
00191 KColorScheme::adjustBackground(background, KColorScheme::PositiveBackground);
00192 lineEdit->setPalette(background);
00193 }
00194 }
00195
00196
00197
00198 void KateSearchBar::indicateMismatch() {
00199 if (m_incUi != NULL) {
00200
00201 QPalette background(m_incUi->pattern->palette());
00202 KColorScheme::adjustBackground(background, KColorScheme::NegativeBackground);
00203 m_incUi->pattern->setPalette(background);
00204
00205
00206 m_incUi->status->setText(i18n("Not found"));
00207 } else {
00208
00209 QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00210 Q_ASSERT(lineEdit != NULL);
00211 QPalette background(lineEdit->palette());
00212 KColorScheme::adjustBackground(background, KColorScheme::NegativeBackground);
00213 lineEdit->setPalette(background);
00214 }
00215 }
00216
00217
00218
00219 void KateSearchBar::indicateNothing() {
00220 if (m_incUi != NULL) {
00221
00222 m_incUi->pattern->setPalette(QPalette());
00223
00224
00225 m_incUi->status->setText("");
00226 } else {
00227
00228 QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00229 Q_ASSERT(lineEdit != NULL);
00230
00231
00232 QColor color = QPalette().color(QPalette::Base);
00233 QPalette background(lineEdit->palette());
00234 background.setBrush(QPalette::Active, QPalette::Base, QPalette().brush(QPalette::Active, QPalette::Base));
00235 background.setBrush(QPalette::Inactive, QPalette::Base, QPalette().brush(QPalette::Inactive, QPalette::Base));
00236 background.setBrush(QPalette::Disabled, QPalette::Base, QPalette().brush(QPalette::Disabled, QPalette::Base));
00237 lineEdit->setPalette(background);
00238 }
00239 }
00240
00241
00242
00243 void KateSearchBar::selectRange(KateView * view, const KTextEditor::Range & range) {
00244 view->setCursorPositionInternal(range.start(), 1);
00245 view->setSelection(range);
00246 }
00247
00248
00249
00250 void KateSearchBar::buildReplacement(QString & output, QList<ReplacementPart> & parts,
00251 const QVector<Range> & details, int replacementCounter) {
00252 const int MIN_REF_INDEX = 0;
00253 const int MAX_REF_INDEX = details.count() - 1;
00254
00255 output.clear();
00256 ReplacementPart::Type caseConversion = ReplacementPart::KeepCase;
00257 for (QList<ReplacementPart>::iterator iter = parts.begin(); iter != parts.end(); iter++) {
00258 ReplacementPart & curPart = *iter;
00259 switch (curPart.type) {
00260 case ReplacementPart::Reference:
00261 if ((curPart.index < MIN_REF_INDEX) || (curPart.index > MAX_REF_INDEX)) {
00262
00263 output.append(QString::number(curPart.index));
00264 } else {
00265 const Range & captureRange = details[curPart.index];
00266 if (captureRange.isValid()) {
00267
00268 const bool blockMode = m_view->blockSelection();
00269 const QString content = m_view->doc()->text(captureRange, blockMode);
00270 switch (caseConversion) {
00271 case ReplacementPart::UpperCase:
00272
00273 output.append(content.toUpper());
00274 break;
00275
00276 case ReplacementPart::LowerCase:
00277
00278 output.append(content.toLower());
00279 break;
00280
00281 case ReplacementPart::KeepCase:
00282 default:
00283
00284 output.append(content);
00285 break;
00286
00287 }
00288 }
00289 }
00290 break;
00291
00292 case ReplacementPart::UpperCase:
00293 case ReplacementPart::LowerCase:
00294 case ReplacementPart::KeepCase:
00295 caseConversion = curPart.type;
00296 break;
00297
00298 case ReplacementPart::Counter:
00299 {
00300
00301 const int minWidth = curPart.index;
00302 const int number = replacementCounter;
00303 output.append(QString("%1").arg(number, minWidth, 10, QLatin1Char('0')));
00304 }
00305 break;
00306
00307 case ReplacementPart::Text:
00308 default:
00309 switch (caseConversion) {
00310 case ReplacementPart::UpperCase:
00311
00312 output.append(curPart.text.toUpper());
00313 break;
00314
00315 case ReplacementPart::LowerCase:
00316
00317 output.append(curPart.text.toLower());
00318 break;
00319
00320 case ReplacementPart::KeepCase:
00321 default:
00322
00323 output.append(curPart.text);
00324 break;
00325
00326 }
00327 break;
00328
00329 }
00330 }
00331 }
00332
00333
00334
00335 void KateSearchBar::replaceMatch(const QVector<Range> & match, const QString & replacement,
00336 int replacementCounter) {
00337 const bool usePlaceholders = isChecked(m_powerUi->usePlaceholders);
00338 const Range & targetRange = match[0];
00339
00340 QString finalReplacement;
00341 if (usePlaceholders) {
00342
00343 QList<ReplacementPart> parts;
00344 QString writableHack(replacement);
00345 const bool REPLACEMENT_GOODIES = true;
00346 KateDocument::escapePlaintext(writableHack, &parts, REPLACEMENT_GOODIES);
00347 buildReplacement(finalReplacement, parts, match, replacementCounter);
00348 } else {
00349
00350 finalReplacement = replacement;
00351 }
00352
00353 const bool blockMode = (m_view->blockSelection() && !targetRange.onSingleLine());
00354 m_view->doc()->replaceText(targetRange, finalReplacement, blockMode);
00355 }
00356
00357
00358
00359 void KateSearchBar::onIncPatternChanged(const QString & pattern, bool invokedByUserAction) {
00360 if (pattern.isEmpty()) {
00361 if (invokedByUserAction) {
00362
00363 m_view->setSelection(Range::invalid());
00364
00365
00366 resetHighlights();
00367 }
00368
00369
00370 indicateNothing();
00371
00372
00373 m_incUi->next->setDisabled(true);
00374 m_incUi->prev->setDisabled(true);
00375 return;
00376 }
00377
00378
00379 m_incUi->next->setDisabled(false);
00380 m_incUi->prev->setDisabled(false);
00381
00382 if (invokedByUserAction) {
00383
00384 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
00385 const bool matchCase = isChecked(m_incMenuMatchCase);
00386 if (!matchCase) {
00387 enabledOptions |= Search::CaseInsensitive;
00388 }
00389
00390
00391
00392 Range inputRange;
00393 const bool fromCursor = isChecked(m_incMenuFromCursor);
00394 if (fromCursor) {
00395 inputRange.setRange(m_incInitCursor, m_view->doc()->documentEnd());
00396 } else {
00397 inputRange = m_view->doc()->documentRange();
00398 }
00399
00400
00401 const QVector<Range> resultRanges = m_view->doc()->searchText(inputRange, pattern, enabledOptions);
00402 const Range & match = resultRanges[0];
00403
00404 bool found = false;
00405 if (match.isValid()) {
00406 selectRange(m_view, match);
00407 const bool NOT_WRAPPED = false;
00408 indicateMatch(NOT_WRAPPED);
00409 found = true;
00410 } else {
00411
00412 if (fromCursor) {
00413
00414 inputRange = m_view->doc()->documentRange();
00415 const QVector<Range> resultRanges2 = m_view->doc()->searchText(inputRange, pattern, enabledOptions);
00416 const Range & match2 = resultRanges2[0];
00417 if (match2.isValid()) {
00418 selectRange(m_view, match2);
00419 const bool WRAPPED = true;
00420 indicateMatch(WRAPPED);
00421 found = true;
00422 } else {
00423 indicateMismatch();
00424 }
00425 } else {
00426 indicateMismatch();
00427 }
00428 }
00429
00430
00431 if (found && isChecked(m_incMenuHighlightAll)) {
00432 highlightAllMatches(pattern, enabledOptions);
00433 }
00434 }
00435 }
00436
00437
00438
00439 void KateSearchBar::onIncNext() {
00440 const bool FIND = false;
00441 onStep(FIND);
00442 }
00443
00444
00445
00446 void KateSearchBar::onIncPrev() {
00447 const bool FIND = false;
00448 const bool BACKWARDS = false;
00449 onStep(FIND, BACKWARDS);
00450 }
00451
00452
00453
00454 void KateSearchBar::onIncMatchCaseToggle(bool invokedByUserAction) {
00455 if (invokedByUserAction) {
00456 sendConfig();
00457
00458
00459 const QString pattern = m_incUi->pattern->displayText();
00460 onIncPatternChanged(pattern);
00461 }
00462 }
00463
00464
00465
00466 void KateSearchBar::onIncHighlightAllToggle(bool checked, bool invokedByUserAction) {
00467 if (invokedByUserAction) {
00468 sendConfig();
00469
00470 if (checked) {
00471 const QString pattern = m_incUi->pattern->displayText();
00472 if (!pattern.isEmpty()) {
00473
00474 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
00475 const bool matchCase = isChecked(m_incMenuMatchCase);
00476 if (!matchCase) {
00477 enabledOptions |= Search::CaseInsensitive;
00478 }
00479
00480
00481 resetHighlights();
00482 highlightAllMatches(pattern, enabledOptions);
00483 }
00484 } else {
00485 resetHighlights();
00486 }
00487 }
00488 }
00489
00490
00491
00492 void KateSearchBar::onIncFromCursorToggle(bool invokedByUserAction) {
00493 if (invokedByUserAction) {
00494 sendConfig();
00495 }
00496 }
00497
00498
00499
00500 void KateSearchBar::fixForSingleLine(Range & range, bool forwards) {
00501 FAST_DEBUG("Single-line workaround checking BEFORE" << range);
00502 if (forwards) {
00503 const int line = range.start().line();
00504 const int col = range.start().column();
00505 const int maxColWithNewline = m_view->doc()->lineLength(line) + 1;
00506 if (col == maxColWithNewline) {
00507 FAST_DEBUG("Starting on a newline" << range);
00508 const int maxLine = m_view->doc()->lines() - 1;
00509 if (line < maxLine) {
00510 range.setRange(Cursor(line + 1, 0), range.end());
00511 FAST_DEBUG("Search range fixed to " << range);
00512 } else {
00513 FAST_DEBUG("Already at last line");
00514 range = Range::invalid();
00515 }
00516 }
00517 } else {
00518 const int col = range.end().column();
00519 if (col == 0) {
00520 FAST_DEBUG("Ending after a newline" << range);
00521 const int line = range.end().line();
00522 if (line > 0) {
00523 const int maxColWithNewline = m_view->doc()->lineLength(line - 1);
00524 range.setRange(range.start(), Cursor(line - 1, maxColWithNewline));
00525 FAST_DEBUG("Search range fixed to " << range);
00526 } else {
00527 FAST_DEBUG("Already at first line");
00528 range = Range::invalid();
00529 }
00530 }
00531 }
00532 FAST_DEBUG("Single-line workaround checking AFTER" << range);
00533 }
00534
00535
00536
00537 void KateSearchBar::onReturnPressed() {
00538 const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
00539 const bool shiftDown = (modifiers & Qt::ShiftModifier) != 0;
00540 const bool controlDown = (modifiers & Qt::ControlModifier) != 0;
00541
00542 if (shiftDown) {
00543
00544 if (m_powerUi != NULL) {
00545 onPowerFindPrev();
00546 } else {
00547 onIncPrev();
00548 }
00549 } else {
00550
00551 if (m_powerUi != NULL) {
00552 onPowerFindNext();
00553 } else {
00554 onIncNext();
00555 }
00556 }
00557
00558 if (controlDown) {
00559 hideBar();
00560 }
00561 }
00562
00563
00564
00565 bool KateSearchBar::onStep(bool replace, bool forwards) {
00566
00567 const QString pattern = (m_powerUi != NULL)
00568 ? m_powerUi->pattern->currentText()
00569 : m_incUi->pattern->displayText();
00570 if (pattern.isEmpty()) {
00571 return false;
00572 }
00573
00574
00575 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
00576 const bool matchCase = (m_powerUi != NULL)
00577 ? isChecked(m_powerUi->matchCase)
00578 : isChecked(m_incMenuMatchCase);
00579 if (!matchCase) {
00580 enabledOptions |= Search::CaseInsensitive;
00581 }
00582
00583 if (!forwards) {
00584 enabledOptions |= Search::Backwards;
00585 }
00586
00587 bool multiLinePattern = false;
00588 bool regexMode = false;
00589 if (m_powerUi != NULL) {
00590 switch (m_powerUi->searchMode->currentIndex()) {
00591 case MODE_WHOLE_WORDS:
00592 enabledOptions |= Search::WholeWords;
00593 break;
00594
00595 case MODE_ESCAPE_SEQUENCES:
00596 enabledOptions |= Search::EscapeSequences;
00597 break;
00598
00599 case MODE_REGEX:
00600 {
00601
00602 QString patternCopy(pattern);
00603 KateDocument::repairPattern(patternCopy, multiLinePattern);
00604 regexMode = true;
00605 }
00606 enabledOptions |= Search::Regex;
00607 break;
00608
00609 case MODE_PLAIN_TEXT:
00610 default:
00611 break;
00612
00613 }
00614 }
00615
00616
00617
00618 Range inputRange;
00619 Range selection;
00620 const bool selected = m_view->selection();
00621 const bool selectionOnly = (m_powerUi != NULL)
00622 ? isChecked(m_powerUi->selectionOnly)
00623 : false;
00624 if (selected) {
00625 selection = m_view->selectionRange();
00626 if (selectionOnly) {
00627
00628 inputRange = selection;
00629 } else {
00630
00631 if (forwards) {
00632 inputRange.setRange(selection.start(), m_view->doc()->documentEnd());
00633 } else {
00634 inputRange.setRange(Cursor(0, 0), selection.end());
00635 }
00636 }
00637 } else {
00638
00639 const bool fromCursor = (m_powerUi != NULL)
00640 ? isChecked(m_powerUi->fromCursor)
00641 : isChecked(m_incMenuFromCursor);
00642 if (fromCursor) {
00643 const Cursor cursorPos = m_view->cursorPosition();
00644 if (forwards) {
00645 inputRange.setRange(cursorPos, m_view->doc()->documentEnd());
00646 } else {
00647 inputRange.setRange(Cursor(0, 0), cursorPos);
00648 }
00649 } else {
00650 inputRange = m_view->doc()->documentRange();
00651 }
00652 }
00653 FAST_DEBUG("Search range is" << inputRange);
00654
00655
00656 if (regexMode && !multiLinePattern) {
00657 fixForSingleLine(inputRange, forwards);
00658 }
00659
00660
00661
00662 const QVector<Range> resultRanges = m_view->doc()->searchText(inputRange, pattern, enabledOptions);
00663 const Range & match = resultRanges[0];
00664 bool wrap = false;
00665 bool found = false;
00666 SmartRange * afterReplace = NULL;
00667 if (match.isValid()) {
00668
00669 if (selected && !selectionOnly && (match == selection)) {
00670
00671 if (replace) {
00672
00673 const QString replacement = m_powerUi->replacement->currentText();
00674 afterReplace = m_view->doc()->newSmartRange(match);
00675 afterReplace->setInsertBehavior(SmartRange::ExpandRight | SmartRange::ExpandLeft);
00676 replaceMatch(resultRanges, replacement);
00677
00678
00679 if (forwards) {
00680 inputRange.setRange(afterReplace->end(), inputRange.end());
00681 } else {
00682 inputRange.setRange(inputRange.start(), afterReplace->start());
00683 }
00684 } else {
00685
00686 if (forwards) {
00687 inputRange.setRange(selection.end(), inputRange.end());
00688 } else {
00689 inputRange.setRange(inputRange.start(), selection.start());
00690 }
00691 }
00692
00693
00694 fixForSingleLine(inputRange, forwards);
00695
00696 const QVector<Range> resultRanges2 = m_view->doc()->searchText(inputRange, pattern, enabledOptions);
00697 const Range & match2 = resultRanges2[0];
00698 if (match2.isValid()) {
00699 selectRange(m_view, match2);
00700 found = true;
00701 const bool NOT_WRAPPED = false;
00702 indicateMatch(NOT_WRAPPED);
00703 } else {
00704
00705 wrap = true;
00706 }
00707 } else {
00708 selectRange(m_view, match);
00709 found = true;
00710 const bool NOT_WRAPPED = false;
00711 indicateMatch(NOT_WRAPPED);
00712 }
00713 } else if (!selected || !selectionOnly) {
00714
00715 wrap = true;
00716 }
00717
00718
00719 if (wrap) {
00720 inputRange = m_view->doc()->documentRange();
00721 const QVector<Range> resultRanges3 = m_view->doc()->searchText(inputRange, pattern, enabledOptions);
00722 const Range & match3 = resultRanges3[0];
00723 if (match3.isValid()) {
00724
00725 if (selected && !selectionOnly && (match3 == selection)) {
00726
00727 } else {
00728 selectRange(m_view, match3);
00729 found = true;
00730 }
00731 const bool WRAPPED = true;
00732 indicateMatch(WRAPPED);
00733 } else {
00734 indicateMismatch();
00735 }
00736 }
00737
00738
00739 const bool highlightAll = (m_powerUi != NULL)
00740 ? isChecked(m_powerUi->highlightAll)
00741 : isChecked(m_incMenuHighlightAll);
00742 if ((found && highlightAll) || (afterReplace != NULL)) {
00743
00744 if (found && highlightAll) {
00745 highlightAllMatches(pattern, enabledOptions);
00746 }
00747
00748
00749 if (found && (afterReplace != NULL)) {
00750
00751 if (!(found && highlightAll)) {
00752 resetHighlights();
00753 }
00754
00755 highlightReplacement(*afterReplace);
00756 }
00757
00758 }
00759
00760 delete afterReplace;
00761
00762 return true;
00763 }
00764
00765
00766
00767 void KateSearchBar::onPowerPatternChanged(const QString & pattern) {
00768 givePatternFeedback(pattern);
00769 indicateNothing();
00770 }
00771
00772
00773
00774 void KateSearchBar::givePatternFeedback(const QString & pattern) {
00775 bool enabled = true;
00776
00777 if (pattern.isEmpty()) {
00778 enabled = false;
00779 } else {
00780 switch (m_powerUi->searchMode->currentIndex()) {
00781 case MODE_WHOLE_WORDS:
00782 if (pattern.trimmed() != pattern) {
00783 enabled = false;
00784 }
00785 break;
00786
00787 case MODE_REGEX:
00788 m_patternTester.setPattern(pattern);
00789 enabled = m_patternTester.isValid();
00790 break;
00791
00792 case MODE_ESCAPE_SEQUENCES:
00793 case MODE_PLAIN_TEXT:
00794 default:
00795 ;
00796
00797 }
00798 }
00799
00800
00801 m_powerUi->findNext->setDisabled(!enabled);
00802 m_powerUi->findPrev->setDisabled(!enabled);
00803 m_powerUi->replaceNext->setDisabled(!enabled);
00804 m_powerUi->replaceAll->setDisabled(!enabled);
00805 }
00806
00807
00808
00809 void KateSearchBar::addCurrentTextToHistory(QComboBox * combo) {
00810 const QString text = combo->currentText();
00811 const int index = combo->findText(text);
00812 if (index != -1) {
00813 combo->removeItem(index);
00814 }
00815 combo->insertItem(0, text);
00816 combo->setCurrentIndex(0);
00817 }
00818
00819
00820
00821 void KateSearchBar::backupConfig(bool ofPower) {
00822 if (ofPower) {
00823 m_powerMatchCase = isChecked(m_powerUi->matchCase);
00824 m_powerFromCursor = isChecked(m_powerUi->fromCursor);
00825 m_powerHighlightAll = isChecked(m_powerUi->highlightAll);
00826 m_powerUsePlaceholders = isChecked(m_powerUi->usePlaceholders);
00827 m_powerMode = m_powerUi->searchMode->currentIndex();
00828 } else {
00829 m_incHighlightAll = isChecked(m_incMenuHighlightAll);
00830 m_incFromCursor = isChecked(m_incMenuFromCursor);
00831 m_incMatchCase = isChecked(m_incMenuMatchCase);
00832 }
00833 }
00834
00835
00836
00837 void KateSearchBar::sendConfig() {
00838 KateViewConfig * const globalConfig = KateGlobal::self()->viewConfig();
00839 const long pastFlags = globalConfig->searchFlags();
00840 long futureFlags = pastFlags;
00841
00842 if (m_powerUi != NULL) {
00843 const bool OF_POWER = true;
00844 backupConfig(OF_POWER);
00845
00846
00847 const long incFlagsOnly = pastFlags
00848 & (KateViewConfig::IncHighlightAll
00849 | KateViewConfig::IncFromCursor
00850 | KateViewConfig::IncMatchCase);
00851
00852 futureFlags = incFlagsOnly
00853 | (m_powerMatchCase ? KateViewConfig::PowerMatchCase : 0)
00854 | (m_powerFromCursor ? KateViewConfig::PowerFromCursor : 0)
00855 | (m_powerHighlightAll ? KateViewConfig::PowerHighlightAll : 0)
00856 | (m_powerUsePlaceholders ? KateViewConfig::PowerUsePlaceholders : 0)
00857 | ((m_powerMode == MODE_REGEX)
00858 ? KateViewConfig::PowerModeRegularExpression
00859 : ((m_powerMode == MODE_ESCAPE_SEQUENCES)
00860 ? KateViewConfig::PowerModeEscapeSequences
00861 : ((m_powerMode == MODE_WHOLE_WORDS)
00862 ? KateViewConfig::PowerModeWholeWords
00863 : KateViewConfig::PowerModePlainText)));
00864
00865 } else if (m_incUi != NULL) {
00866 const bool OF_INCREMENTAL = false;
00867 backupConfig(OF_INCREMENTAL);
00868
00869
00870 const long powerFlagsOnly = pastFlags
00871 & (KateViewConfig::PowerMatchCase
00872 | KateViewConfig::PowerFromCursor
00873 | KateViewConfig::PowerHighlightAll
00874 | KateViewConfig::PowerUsePlaceholders
00875 | KateViewConfig::PowerModeRegularExpression
00876 | KateViewConfig::PowerModeEscapeSequences
00877 | KateViewConfig::PowerModeWholeWords
00878 | KateViewConfig::PowerModePlainText);
00879
00880 futureFlags = powerFlagsOnly
00881 | (m_incHighlightAll ? KateViewConfig::IncHighlightAll : 0)
00882 | (m_incFromCursor ? KateViewConfig::IncFromCursor : 0)
00883 | (m_incMatchCase ? KateViewConfig::IncMatchCase : 0);
00884 }
00885
00886
00887 globalConfig->setSearchFlags(futureFlags);
00888 }
00889
00890
00891
00892 void KateSearchBar::onPowerFindNext() {
00893 const bool FIND = false;
00894 if (onStep(FIND)) {
00895
00896 addCurrentTextToHistory(m_powerUi->pattern);
00897 }
00898 }
00899
00900
00901
00902 void KateSearchBar::onPowerFindPrev() {
00903 const bool FIND = false;
00904 const bool BACKWARDS = false;
00905 if (onStep(FIND, BACKWARDS)) {
00906
00907 addCurrentTextToHistory(m_powerUi->pattern);
00908 }
00909 }
00910
00911
00912
00913 void KateSearchBar::onPowerReplaceNext() {
00914 const bool REPLACE = true;
00915 if (onStep(REPLACE)) {
00916
00917 addCurrentTextToHistory(m_powerUi->pattern);
00918
00919
00920 addCurrentTextToHistory(m_powerUi->replacement);
00921 }
00922 }
00923
00924
00925
00926
00927
00928 void KateSearchBar::onForAll(const QString & pattern, Range inputRange,
00929 Search::SearchOptions enabledOptions,
00930 const QString * replacement) {
00931 bool multiLinePattern = false;
00932 const bool regexMode = enabledOptions.testFlag(Search::Regex);
00933 if (regexMode) {
00934
00935 QString patternCopy(pattern);
00936 KateDocument::repairPattern(patternCopy, multiLinePattern);
00937 }
00938
00939
00940 if (enabledOptions.testFlag(Search::Backwards)) {
00941 enabledOptions &= ~Search::SearchOptions(Search::Backwards);
00942 }
00943
00944
00945 resetHighlights();
00946
00947 SmartRange * const workingRange = m_view->doc()->newSmartRange(inputRange);
00948 int matchCounter = 0;
00949 for (;;) {
00950 const QVector<Range> resultRanges = m_view->doc()->searchText(*workingRange, pattern, enabledOptions);
00951 Range match = resultRanges[0];
00952 if (!match.isValid()) {
00953 break;
00954 }
00955
00956
00957 if (replacement != NULL) {
00958 if (matchCounter == 0) {
00959 m_view->doc()->editBegin();
00960 }
00961
00962
00963 SmartRange * const afterReplace = m_view->doc()->newSmartRange(match);
00964 afterReplace->setInsertBehavior(SmartRange::ExpandRight | SmartRange::ExpandLeft);
00965
00966
00967 replaceMatch(resultRanges, *replacement, ++matchCounter);
00968
00969
00970 highlightReplacement(match = *afterReplace);
00971 delete afterReplace;
00972 } else {
00973
00974 highlightMatch(match);
00975 matchCounter++;
00976 }
00977
00978
00979 SmartCursor & workingStart = workingRange->smartStart();
00980 workingStart.setPosition(match.end());
00981 if (workingStart == match.start()) {
00982
00983
00984 workingStart.advance(1);
00985 } else if (regexMode && !multiLinePattern && workingStart.atEndOfLine()) {
00986
00987
00988 workingStart.advance(1);
00989 }
00990
00991 if (!workingRange->isValid() || workingStart.atEndOfDocument()) {
00992 break;
00993 }
00994 }
00995
00996
00997 if (matchCounter > 0) {
00998 if (replacement != NULL) {
00999 m_view->doc()->editEnd();
01000 }
01001 }
01002
01003 delete workingRange;
01004 }
01005
01006
01007
01008 void KateSearchBar::onPowerReplaceAll() {
01009
01010 const QString pattern = m_powerUi->pattern->currentText();
01011 const QString replacement = m_powerUi->replacement->currentText();
01012
01013
01014
01015 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
01016 const bool matchCase = isChecked(m_powerUi->matchCase);
01017 if (!matchCase) {
01018 enabledOptions |= Search::CaseInsensitive;
01019 }
01020
01021 if (m_powerUi != NULL) {
01022 switch (m_powerUi->searchMode->currentIndex()) {
01023 case MODE_WHOLE_WORDS:
01024 enabledOptions |= Search::WholeWords;
01025 break;
01026
01027 case MODE_ESCAPE_SEQUENCES:
01028 enabledOptions |= Search::EscapeSequences;
01029 break;
01030
01031 case MODE_REGEX:
01032 enabledOptions |= Search::Regex;
01033 break;
01034
01035 case MODE_PLAIN_TEXT:
01036 default:
01037 break;
01038
01039 }
01040 }
01041
01042
01043
01044 Range selection;
01045 const bool selected = m_view->selection();
01046 const bool selectionOnly = isChecked(m_powerUi->selectionOnly);
01047 Range inputRange = (selected && selectionOnly)
01048 ? m_view->selectionRange()
01049 : m_view->doc()->documentRange();
01050
01051
01052
01053 onForAll(pattern, inputRange, enabledOptions, &replacement);
01054
01055
01056
01057 addCurrentTextToHistory(m_powerUi->pattern);
01058
01059
01060 addCurrentTextToHistory(m_powerUi->replacement);
01061 }
01062
01063
01064
01065 struct ParInfo {
01066 int openIndex;
01067 bool capturing;
01068 int captureNumber;
01069 };
01070
01071
01072
01073 QVector<QString> KateSearchBar::getCapturePatterns(const QString & pattern) {
01074 QVector<QString> capturePatterns;
01075 capturePatterns.reserve(9);
01076 QStack<ParInfo> parInfos;
01077
01078 const int inputLen = pattern.length();
01079 int input = 0;
01080 bool insideClass = false;
01081 int captureCount = 0;
01082
01083 while (input < inputLen) {
01084 if (insideClass) {
01085
01086 if (pattern[input].unicode() == L']') {
01087 insideClass = false;
01088 }
01089 input++;
01090 }
01091 else
01092 {
01093 switch (pattern[input].unicode())
01094 {
01095 case L'\\':
01096
01097 input += 2;
01098 break;
01099
01100 case L'(':
01101 ParInfo curInfo;
01102 curInfo.openIndex = input;
01103 curInfo.capturing = (input + 1 >= inputLen) || (pattern[input + 1].unicode() != '?');
01104 if (curInfo.capturing) {
01105 captureCount++;
01106 }
01107 curInfo.captureNumber = captureCount;
01108 parInfos.push(curInfo);
01109
01110 input++;
01111 break;
01112
01113 case L')':
01114 if (!parInfos.empty()) {
01115 ParInfo & top = parInfos.top();
01116 if (top.capturing && (top.captureNumber <= 9)) {
01117 const int start = top.openIndex + 1;
01118 const int len = input - start;
01119 if (capturePatterns.size() < top.captureNumber) {
01120 capturePatterns.resize(top.captureNumber);
01121 }
01122 capturePatterns[top.captureNumber - 1] = pattern.mid(start, len);
01123 }
01124 parInfos.pop();
01125 }
01126
01127 input++;
01128 break;
01129
01130 case L'[':
01131 input++;
01132 insideClass = true;
01133 break;
01134
01135 default:
01136 input++;
01137 break;
01138
01139 }
01140 }
01141 }
01142
01143 return capturePatterns;
01144 }
01145
01146
01147
01148 void KateSearchBar::addMenuEntry(QMenu * menu, QVector<QString> & insertBefore, QVector<QString> & insertAfter,
01149 uint & walker, const QString & before, const QString after, const QString description,
01150 const QString & realBefore, const QString & realAfter) {
01151 QAction * const action = menu->addAction(before + after + '\t' + description);
01152 insertBefore[walker] = QString(realBefore.isEmpty() ? before : realBefore);
01153 insertAfter[walker] = QString(realAfter.isEmpty() ? after : realAfter);
01154 action->setData(QVariant(walker++));
01155 }
01156
01157
01158
01159 void KateSearchBar::showAddMenu(bool forPattern) {
01160 QVector<QString> insertBefore(35);
01161 QVector<QString> insertAfter(35);
01162 uint walker = 0;
01163
01164
01165 QMenu * const popupMenu = new QMenu();
01166 const bool regexMode = (m_powerUi->searchMode->currentIndex() == MODE_REGEX);
01167
01168 if (forPattern) {
01169 if (regexMode) {
01170 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "^", "", i18n("Beginning of line"));
01171 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "$", "", i18n("End of line"));
01172 popupMenu->addSeparator();
01173 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, ".", "", i18n("Any single character (excluding line breaks)"));
01174 popupMenu->addSeparator();
01175 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "+", "", i18n("One or more occurrences"));
01176 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "*", "", i18n("Zero or more occurrences"));
01177 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "?", "", i18n("Zero or one occurrences"));
01178 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "{a", ",b}", i18n("<a> through <b> occurrences"), "{", ",}");
01179 popupMenu->addSeparator();
01180 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "(", ")", i18n("Group, capturing"));
01181 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "|", "", i18n("Or"));
01182 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "[", "]", i18n("Set of characters"));
01183 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "[^", "]", i18n("Negative set of characters"));
01184 popupMenu->addSeparator();
01185 }
01186 } else {
01187 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\0", "", i18n("Whole match reference"));
01188 popupMenu->addSeparator();
01189 if (regexMode) {
01190 const QString pattern = m_powerUi->pattern->currentText();
01191 const QVector<QString> capturePatterns = getCapturePatterns(pattern);
01192
01193 const int captureCount = capturePatterns.count();
01194 for (int i = 1; i <= 9; i++) {
01195 const QString number = QString::number(i);
01196 const QString & captureDetails = (i <= captureCount)
01197 ? (QString(" = (") + capturePatterns[i - 1].left(30)) + QString(")")
01198 : QString();
01199 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\" + number, "",
01200 i18n("Reference") + ' ' + number + captureDetails);
01201 }
01202
01203 popupMenu->addSeparator();
01204 }
01205 }
01206
01207 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\n", "", i18n("Line break"));
01208 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\t", "", i18n("Tab"));
01209
01210 if (forPattern && regexMode) {
01211 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\b", "", i18n("Word boundary"));
01212 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\B", "", i18n("Not word boundary"));
01213 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\d", "", i18n("Digit"));
01214 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\D", "", i18n("Non-digit"));
01215 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\s", "", i18n("Whitespace (excluding line breaks)"));
01216 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\S", "", i18n("Non-whitespace (excluding line breaks)"));
01217 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\w", "", i18n("Word character (alphanumerics plus '_')"));
01218 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\W", "", i18n("Non-word character"));
01219 }
01220
01221 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\0???", "", i18n("Octal character 000 to 377 (2^8-1)"), "\\0");
01222 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\x????", "", i18n("Hex character 0000 to FFFF (2^16-1)"), "\\x");
01223 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\\\", "", i18n("Backslash"));
01224
01225 if (forPattern && regexMode) {
01226 popupMenu->addSeparator();
01227 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "(?:E", ")", i18n("Group, non-capturing"), "(?:");
01228 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "(?=E", ")", i18n("Lookahead"), "(?=");
01229 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "(?!E", ")", i18n("Negative lookahead"), "(?!");
01230 }
01231
01232 if (!forPattern) {
01233 popupMenu->addSeparator();
01234 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\L", "", i18n("Begin lowercase conversion"));
01235 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\U", "", i18n("Begin uppercase conversion"));
01236 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\E", "", i18n("End case conversion"));
01237 addMenuEntry(popupMenu, insertBefore, insertAfter, walker, "\\#[#..]", "", i18n("Replacement counter (for Replace all)"), "\\#");
01238 }
01239
01240
01241
01242 const QPoint topLeftGlobal = m_powerUi->patternAdd->mapToGlobal(QPoint(0, 0));
01243 QAction * const result = popupMenu->exec(topLeftGlobal);
01244 if (result != NULL) {
01245 QLineEdit * const lineEdit = forPattern
01246 ? m_powerUi->pattern->lineEdit()
01247 : m_powerUi->replacement->lineEdit();
01248 Q_ASSERT(lineEdit != NULL);
01249 const int cursorPos = lineEdit->cursorPosition();
01250 const int index = result->data().toUInt();
01251 const QString & before = insertBefore[index];
01252 const QString & after = insertAfter[index];
01253 lineEdit->insert(before + after);
01254 lineEdit->setCursorPosition(cursorPos + before.count());
01255 lineEdit->setFocus();
01256 }
01257
01258
01259
01260 delete popupMenu;
01261 }
01262
01263
01264
01265 void KateSearchBar::onPowerAddToPatternClicked() {
01266 const bool FOR_PATTERN = true;
01267 showAddMenu(FOR_PATTERN);
01268 }
01269
01270
01271
01272 void KateSearchBar::onPowerAddToReplacementClicked() {
01273 const bool FOR_REPLACEMENT = false;
01274 showAddMenu(FOR_REPLACEMENT);
01275 }
01276
01277
01278
01279 void KateSearchBar::onPowerUsePlaceholdersToggle(int state, bool invokedByUserAction) {
01280 const bool disabled = (state != Qt::Checked);
01281 m_powerUi->replacementAdd->setDisabled(disabled);
01282
01283 if (invokedByUserAction) {
01284 sendConfig();
01285 }
01286 }
01287
01288
01289
01290 void KateSearchBar::onPowerMatchCaseToggle(bool invokedByUserAction) {
01291 if (invokedByUserAction) {
01292 sendConfig();
01293 indicateNothing();
01294 }
01295 }
01296
01297
01298
01299 void KateSearchBar::onPowerHighlightAllToggle(int state, bool invokedByUserAction) {
01300 if (invokedByUserAction) {
01301 sendConfig();
01302
01303 const bool wanted = (state == Qt::Checked);
01304 if (wanted) {
01305 const QString pattern = m_powerUi->pattern->currentText();
01306 if (!pattern.isEmpty()) {
01307
01308 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
01309 const bool matchCase = isChecked(m_powerUi->matchCase);
01310 if (!matchCase) {
01311 enabledOptions |= Search::CaseInsensitive;
01312 }
01313
01314 switch (m_powerUi->searchMode->currentIndex()) {
01315 case MODE_WHOLE_WORDS:
01316 enabledOptions |= Search::WholeWords;
01317 break;
01318
01319 case MODE_ESCAPE_SEQUENCES:
01320 enabledOptions |= Search::EscapeSequences;
01321 break;
01322
01323 case MODE_REGEX:
01324 enabledOptions |= Search::Regex;
01325 break;
01326
01327 case MODE_PLAIN_TEXT:
01328 default:
01329 break;
01330
01331 }
01332
01333
01334 resetHighlights();
01335 highlightAllMatches(pattern, enabledOptions);
01336 }
01337 } else {
01338 resetHighlights();
01339 }
01340 }
01341 }
01342
01343
01344
01345 void KateSearchBar::onPowerFromCursorToggle(bool invokedByUserAction) {
01346 if (invokedByUserAction) {
01347 sendConfig();
01348 }
01349 }
01350
01351
01352
01353 void KateSearchBar::onPowerModeChanged(int index, bool invokedByUserAction) {
01354 const bool disabled = (index == MODE_PLAIN_TEXT)
01355 || (index == MODE_WHOLE_WORDS);
01356 m_powerUi->patternAdd->setDisabled(disabled);
01357
01358 if (invokedByUserAction) {
01359 switch (index) {
01360 case MODE_REGEX:
01361 setChecked(m_powerUi->matchCase, true);
01362
01363
01364 case MODE_ESCAPE_SEQUENCES:
01365 setChecked(m_powerUi->usePlaceholders, true);
01366 break;
01367
01368 case MODE_WHOLE_WORDS:
01369 case MODE_PLAIN_TEXT:
01370 default:
01371 ;
01372 }
01373
01374 sendConfig();
01375 indicateNothing();
01376 }
01377
01378 givePatternFeedback(m_powerUi->pattern->currentText());
01379 }
01380
01381
01382
01383 void KateSearchBar::nextMatchForSelection(KateView * view, bool forwards) {
01384 const bool selected = view->selection();
01385 if (selected) {
01386 const QString pattern = view->selectionText();
01387
01388
01389 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
01390 if (!forwards) {
01391 enabledOptions |= Search::Backwards;
01392 }
01393
01394
01395 const Range selRange = view->selectionRange();
01396 Range inputRange;
01397 if (forwards) {
01398 inputRange.setRange(selRange.end(), view->doc()->documentEnd());
01399 } else {
01400 inputRange.setRange(Cursor(0, 0), selRange.start());
01401 }
01402
01403
01404 const QVector<Range> resultRanges = view->doc()->searchText(inputRange, pattern, enabledOptions);
01405 const Range & match = resultRanges[0];
01406
01407 if (match.isValid()) {
01408 selectRange(view, match);
01409 } else {
01410
01411 if (forwards) {
01412 inputRange.setRange(Cursor(0, 0), selRange.start());
01413 } else {
01414 inputRange.setRange(selRange.end(), view->doc()->documentEnd());
01415 }
01416 const QVector<Range> resultRanges2 = view->doc()->searchText(inputRange, pattern, enabledOptions);
01417 const Range & match2 = resultRanges2[0];
01418 if (match2.isValid()) {
01419 selectRange(view, match2);
01420 }
01421 }
01422 } else {
01423
01424 const Cursor cursorPos = view->cursorPosition();
01425 view->selectWord(cursorPos);
01426 }
01427 }
01428
01429
01430
01431 void KateSearchBar::onMutatePower() {
01432 QString initialPattern;
01433 bool selectionOnly = false;
01434
01435
01436 const bool selected = m_view->selection();
01437 if (selected) {
01438 const Range & selection = m_view->selectionRange();
01439 if (selection.onSingleLine()) {
01440
01441 initialPattern = m_view->selectionText();
01442 } else {
01443
01444 selectionOnly = true;
01445 }
01446 }
01447
01448
01449 if (initialPattern.isNull()) {
01450
01451 const bool fromReplace = (m_powerUi != NULL) && (m_widget->isVisible());
01452 if (fromReplace) {
01453 QLineEdit * const patternLineEdit = m_powerUi->pattern->lineEdit();
01454 Q_ASSERT(patternLineEdit != NULL);
01455 patternLineEdit->selectAll();
01456 m_powerUi->pattern->setFocus(Qt::MouseFocusReason);
01457 return;
01458 }
01459
01460
01461 const bool fromIncremental = (m_incUi != NULL) && (m_widget->isVisible());
01462 if (fromIncremental) {
01463 initialPattern = m_incUi->pattern->displayText();
01464 }
01465 }
01466
01467
01468 const bool create = (m_powerUi == NULL);
01469 if (create) {
01470
01471 if (m_incUi != NULL) {
01472
01473 const bool OF_INCREMENTAL = false;
01474 backupConfig(OF_INCREMENTAL);
01475
01476
01477 delete m_incUi;
01478 delete m_incMenu;
01479 m_incUi = NULL;
01480 m_incMenu = NULL;
01481 m_incMenuMatchCase = NULL;
01482 m_incMenuFromCursor = NULL;
01483 m_incMenuHighlightAll = NULL;
01484 m_layout->removeWidget(m_widget);
01485 m_widget->deleteLater();
01486 }
01487
01488
01489 m_widget = new QWidget(this);
01490 m_powerUi = new Ui::PowerSearchBar;
01491 m_powerUi->setupUi(m_widget);
01492 m_layout->addWidget(m_widget);
01493
01494
01495 const int MAX_HISTORY_SIZE = 100;
01496 QStringListModel * const patternHistoryModel = KateHistoryModel::getPatternHistoryModel();
01497 QStringListModel * const replacementHistoryModel = KateHistoryModel::getReplacementHistoryModel();
01498 m_powerUi->pattern->setMaxCount(MAX_HISTORY_SIZE);
01499 m_powerUi->pattern->setModel(patternHistoryModel);
01500 m_powerUi->replacement->setMaxCount(MAX_HISTORY_SIZE);
01501 m_powerUi->replacement->setModel(replacementHistoryModel);
01502
01503
01504 m_powerUi->mutate->setIcon(KIcon("arrow-down-double"));
01505 m_powerUi->findNext->setIcon(KIcon("go-down"));
01506 m_powerUi->findPrev->setIcon(KIcon("go-up"));
01507 m_powerUi->patternAdd->setIcon(KIcon("list-add"));
01508 m_powerUi->replacementAdd->setIcon(KIcon("list-add"));
01509
01510
01511 centralWidget()->setFocusProxy(m_powerUi->pattern);
01512
01513
01514 QLineEdit * const patternLineEdit = m_powerUi->pattern->lineEdit();
01515 Q_ASSERT(patternLineEdit != NULL);
01516 patternLineEdit->completer()->setCaseSensitivity(Qt::CaseSensitive);
01517
01518 QLineEdit * const replacementLineEdit = m_powerUi->pattern->lineEdit();
01519 Q_ASSERT(replacementLineEdit != NULL);
01520 replacementLineEdit->completer()->setCaseSensitivity(Qt::CaseSensitive);
01521 }
01522
01523 setChecked(m_powerUi->selectionOnly, selectionOnly);
01524
01525
01526 if (create) {
01527 setChecked(m_powerUi->matchCase, m_powerMatchCase);
01528 setChecked(m_powerUi->highlightAll, m_powerHighlightAll);
01529 setChecked(m_powerUi->usePlaceholders, m_powerUsePlaceholders);
01530 setChecked(m_powerUi->fromCursor, m_powerFromCursor);
01531 m_powerUi->searchMode->setCurrentIndex(m_powerMode);
01532 }
01533
01534
01535 QLineEdit * const patternLineEdit = m_powerUi->pattern->lineEdit();
01536 Q_ASSERT(patternLineEdit != NULL);
01537 patternLineEdit->setText(initialPattern);
01538 patternLineEdit->selectAll();
01539
01540
01541 QLineEdit * const replacementLineEdit = m_powerUi->replacement->lineEdit();
01542 Q_ASSERT(replacementLineEdit != NULL);
01543 replacementLineEdit->setText("");
01544
01545
01546 onPowerPatternChanged(initialPattern);
01547 const bool NOT_INVOKED_BY_USER_ACTION = false;
01548 onPowerUsePlaceholdersToggle(m_powerUi->usePlaceholders->checkState(), NOT_INVOKED_BY_USER_ACTION);
01549 onPowerModeChanged(m_powerUi->searchMode->currentIndex(), NOT_INVOKED_BY_USER_ACTION);
01550
01551 if (create) {
01552
01553 connect(m_powerUi->mutate, SIGNAL(clicked()), this, SLOT(onMutateIncremental()));
01554 connect(patternLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(onPowerPatternChanged(const QString &)));
01555 connect(m_powerUi->findNext, SIGNAL(clicked()), this, SLOT(onPowerFindNext()));
01556 connect(m_powerUi->findPrev, SIGNAL(clicked()), this, SLOT(onPowerFindPrev()));
01557 connect(m_powerUi->replaceNext, SIGNAL(clicked()), this, SLOT(onPowerReplaceNext()));
01558 connect(m_powerUi->replaceAll, SIGNAL(clicked()), this, SLOT(onPowerReplaceAll()));
01559 connect(m_powerUi->searchMode, SIGNAL(currentIndexChanged(int)), this, SLOT(onPowerModeChanged(int)));
01560 connect(m_powerUi->patternAdd, SIGNAL(clicked()), this, SLOT(onPowerAddToPatternClicked()));
01561 connect(m_powerUi->usePlaceholders, SIGNAL(stateChanged(int)), this, SLOT(onPowerUsePlaceholdersToggle(int)));
01562 connect(m_powerUi->matchCase, SIGNAL(stateChanged(int)), this, SLOT(onPowerMatchCaseToggle()));
01563 connect(m_powerUi->highlightAll, SIGNAL(stateChanged(int)), this, SLOT(onPowerHighlightAllToggle(int)));
01564 connect(m_powerUi->fromCursor, SIGNAL(stateChanged(int)), this, SLOT(onPowerFromCursorToggle()));
01565 connect(m_powerUi->replacementAdd, SIGNAL(clicked()), this, SLOT(onPowerAddToReplacementClicked()));
01566
01567
01568 connect(patternLineEdit, SIGNAL(returnPressed()), this, SLOT(onReturnPressed()));
01569 connect(replacementLineEdit, SIGNAL(returnPressed()), this, SLOT(onPowerReplaceNext()));
01570 }
01571
01572
01573 if (m_widget->isVisible()) {
01574 m_powerUi->pattern->setFocus(Qt::MouseFocusReason);
01575 }
01576 }
01577
01578
01579
01580 void KateSearchBar::onMutateIncremental() {
01581 QString initialPattern;
01582
01583
01584 const bool selected = m_view->selection();
01585 if (selected) {
01586 const Range & selection = m_view->selectionRange();
01587 if (selection.onSingleLine()) {
01588
01589 initialPattern = m_view->selectionText();
01590 }
01591 }
01592
01593
01594 if (initialPattern.isNull()) {
01595
01596 const bool fromIncremental = (m_incUi != NULL) && (m_widget->isVisible());
01597 if (fromIncremental) {
01598 m_incUi->pattern->selectAll();
01599 m_incUi->pattern->setFocus(Qt::MouseFocusReason);
01600 return;
01601 }
01602
01603
01604 const bool fromReplace = (m_powerUi != NULL) && (m_widget->isVisible());
01605 if (fromReplace) {
01606 initialPattern = m_powerUi->pattern->currentText();
01607 }
01608 }
01609
01610
01611 const bool create = (m_incUi == NULL);
01612 if (create) {
01613
01614 if (m_powerUi != NULL) {
01615
01616 const bool OF_POWER = true;
01617 backupConfig(OF_POWER);
01618
01619
01620 delete m_powerUi;
01621 m_powerUi = NULL;
01622 m_layout->removeWidget(m_widget);
01623 m_widget->deleteLater();
01624 }
01625
01626
01627 m_widget = new QWidget(this);
01628 m_incUi = new Ui::IncrementalSearchBar;
01629 m_incUi->setupUi(m_widget);
01630 m_layout->addWidget(m_widget);
01631
01632
01633 m_incMenu = new QMenu();
01634 m_incUi->options->setMenu(m_incMenu);
01635 m_incMenuHighlightAll = m_incMenu->addAction(i18n("Hi&ghlight all"));
01636 m_incMenuHighlightAll->setCheckable(true);
01637 m_incMenuMatchCase = m_incMenu->addAction(i18n("&Match case"));
01638 m_incMenuMatchCase->setCheckable(true);
01639 m_incMenuFromCursor = m_incMenu->addAction(i18n("From &cursor"));
01640 m_incMenuFromCursor->setCheckable(true);
01641
01642
01643 m_incUi->mutate->setIcon(KIcon("arrow-up-double"));
01644 m_incUi->next->setIcon(KIcon("go-down"));
01645 m_incUi->prev->setIcon(KIcon("go-up"));
01646
01647
01648 centralWidget()->setFocusProxy(m_incUi->pattern);
01649 }
01650
01651
01652 if (create) {
01653 setChecked(m_incMenuHighlightAll, m_incHighlightAll);
01654 setChecked(m_incMenuFromCursor, m_incFromCursor);
01655 setChecked(m_incMenuMatchCase, m_incMatchCase);
01656 }
01657
01658
01659 m_incUi->pattern->setText(initialPattern);
01660 m_incUi->pattern->selectAll();
01661
01662
01663 const bool NOT_INVOKED_BY_USER_ACTION = false;
01664 onIncPatternChanged(initialPattern, NOT_INVOKED_BY_USER_ACTION);
01665
01666 if (create) {
01667
01668 connect(m_incUi->mutate, SIGNAL(clicked()), this, SLOT(onMutatePower()));
01669 connect(m_incUi->pattern, SIGNAL(returnPressed()), this, SLOT(onReturnPressed()));
01670 connect(m_incUi->pattern, SIGNAL(textChanged(const QString &)), this, SLOT(onIncPatternChanged(const QString &)));
01671 connect(m_incUi->next, SIGNAL(clicked()), this, SLOT(onIncNext()));
01672 connect(m_incUi->prev, SIGNAL(clicked()), this, SLOT(onIncPrev()));
01673 connect(m_incMenuMatchCase, SIGNAL(changed()), this, SLOT(onIncMatchCaseToggle()));
01674 connect(m_incMenuFromCursor, SIGNAL(changed()), this, SLOT(onIncFromCursorToggle()));
01675 connect(m_incMenuHighlightAll, SIGNAL(toggled(bool)), this, SLOT(onIncHighlightAllToggle(bool)));
01676
01677
01678
01679 connect(m_incUi->options, SIGNAL(clicked()), m_incUi->options, SLOT(showMenu()));
01680 }
01681
01682
01683 if (m_widget->isVisible()) {
01684 m_incUi->pattern->setFocus(Qt::MouseFocusReason);
01685 }
01686 }
01687
01688
01689
01690 bool KateSearchBar::isChecked(QCheckBox * checkbox) {
01691 Q_ASSERT(checkbox != NULL);
01692 return checkbox->checkState() == Qt::Checked;
01693 }
01694
01695
01696
01697 bool KateSearchBar::isChecked(QAction * menuAction) {
01698 Q_ASSERT(menuAction != NULL);
01699 return menuAction->isChecked();
01700 }
01701
01702
01703
01704 void KateSearchBar::setChecked(QCheckBox * checkbox, bool checked) {
01705 Q_ASSERT(checkbox != NULL);
01706 checkbox->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
01707 }
01708
01709
01710
01711 void KateSearchBar::setChecked(QAction * menuAction, bool checked) {
01712 Q_ASSERT(menuAction != NULL);
01713 menuAction->setChecked(checked);
01714 }
01715
01716
01717
01718 void KateSearchBar::enableHighlights(bool enable) {
01719 if (enable) {
01720 m_view->addInternalHighlight(m_topRange);
01721 } else {
01722 m_view->removeInternalHighlight(m_topRange);
01723 m_topRange->deleteChildRanges();
01724 }
01725 }
01726
01727
01728
01729 void KateSearchBar::resetHighlights() {
01730 enableHighlights(false);
01731 enableHighlights(true);
01732 }
01733
01734
01735
01736 void KateSearchBar::showEvent(QShowEvent * event) {
01737
01738 if (m_incUi != NULL) {
01739 m_incInitCursor = m_view->cursorPosition();
01740 }
01741
01742 enableHighlights(true);
01743 KateViewBarWidget::showEvent(event);
01744 }
01745
01746
01747
01748 void KateSearchBar::hideEvent(QHideEvent * event) {
01749 enableHighlights(false);
01750 KateViewBarWidget::hideEvent(event);
01751 }
01752
01753
01754
01755
01756 #ifdef FAST_DEBUG_ENABLE
01757 # undef FAST_DEBUG_ENABLE
01758 #endif
01759 #undef FAST_DEBUG
01760
01761
01762
01763 #include "katesearchbar.moc"
01764