• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katesearchbar.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2007 Sebastian Pipping <webmaster@hartwork.org>
00003    Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
00004    Copyright (C) 2007 Thomas Friedrichsmeier <thomas.friedrichsmeier@ruhr-uni-bochum.de>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License version 2 as published by the Free Software Foundation.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
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 #include <ktexteditor/rangefeedback.h>
00031 
00032 #include <QtGui/QVBoxLayout>
00033 #include <QtGui/QComboBox>
00034 #include <QtGui/QCheckBox>
00035 #include <QtGui/QKeySequence>
00036 #include <QtGui/QShortcut>
00037 #include <QtGui/QCursor>
00038 #include <QStringListModel>
00039 #include <QCompleter>
00040 
00041 using namespace KTextEditor;
00042 
00043 
00044 
00045 // Turn debug messages on/off here
00046 // #define FAST_DEBUG_ENABLE
00047 
00048 #ifdef FAST_DEBUG_ENABLE
00049 # define FAST_DEBUG(x) (kDebug() << x)
00050 #else
00051 # define FAST_DEBUG(x)
00052 #endif
00053 
00054 
00055 
00056 namespace {
00057 
00058 class AddMenuManager {
00059 
00060 private:
00061     QVector<QString> m_insertBefore;
00062     QVector<QString> m_insertAfter;
00063     QSet<QAction *> m_actionPointers;
00064     uint m_indexWalker;
00065     QMenu * m_menu;
00066 
00067 public:
00068     AddMenuManager(QMenu * parent, int expectedItemCount)
00069             : m_insertBefore(QVector<QString>(expectedItemCount)),
00070             m_insertAfter(QVector<QString>(expectedItemCount)),
00071             m_indexWalker(0),
00072             m_menu(NULL) {
00073         Q_ASSERT(parent != NULL);
00074         m_menu = parent->addMenu(i18n("Add..."));
00075         if (m_menu == NULL) {
00076             return;
00077         }
00078         m_menu->setIcon(KIcon("list-add"));
00079     }
00080 
00081     void enableMenu(bool enabled) {
00082         if (m_menu == NULL) {
00083             return;
00084         }
00085         m_menu->setEnabled(enabled);
00086     }
00087 
00088     void addEntry(const QString & before, const QString after,
00089             const QString description, const QString & realBefore = QString(),
00090             const QString & realAfter = QString()) {
00091         if (m_menu == NULL) {
00092             return;
00093         }
00094         QAction * const action = m_menu->addAction(before + after + '\t' + description);
00095         m_insertBefore[m_indexWalker] = QString(realBefore.isEmpty() ? before : realBefore);
00096         m_insertAfter[m_indexWalker] = QString(realAfter.isEmpty() ? after : realAfter);
00097         action->setData(QVariant(m_indexWalker++));
00098         m_actionPointers.insert(action);
00099     }
00100 
00101     void addSeparator() {
00102         if (m_menu == NULL) {
00103             return;
00104         }
00105         m_menu->addSeparator();
00106     }
00107 
00108     void handle(QAction * action, QLineEdit * lineEdit) {
00109         if (!m_actionPointers.contains(action)) {
00110             return;
00111         }
00112 
00113         const int cursorPos = lineEdit->cursorPosition();
00114         const int index = action->data().toUInt();
00115         const QString & before = m_insertBefore[index];
00116         const QString & after = m_insertAfter[index];
00117         lineEdit->insert(before + after);
00118         lineEdit->setCursorPosition(cursorPos + before.count());
00119         lineEdit->setFocus();
00120     }
00121 };
00122 
00123 } // anon namespace
00124 
00125 
00126 
00127 KateSearchBar::KateSearchBar(bool initAsPower, KateView* kateView, QWidget* parent)
00128         : KateViewBarWidget(true, kateView, parent),
00129         m_topRange(NULL),
00130         m_rangeNotifier(new KTextEditor::SmartRangeNotifier),
00131         m_layout(new QVBoxLayout()),
00132         m_widget(NULL),
00133         m_incUi(NULL),
00134         m_incMenu(NULL),
00135         m_incMenuMatchCase(NULL),
00136         m_incMenuFromCursor(NULL),
00137         m_incMenuHighlightAll(NULL),
00138         m_incInitCursor(0, 0),
00139         m_powerUi(NULL),
00140         m_powerMenu(NULL),
00141         m_powerMenuFromCursor(NULL),
00142         m_powerMenuHighlightAll(NULL),
00143         m_powerMenuSelectionOnly(NULL),
00144         m_incHighlightAll(false),
00145         m_incFromCursor(true),
00146         m_incMatchCase(false),
00147         m_powerMatchCase(true),
00148         m_powerFromCursor(false),
00149         m_powerHighlightAll(false),
00150         m_powerMode(0) {
00151 
00152     connect(m_rangeNotifier,SIGNAL(rangeContentsChanged(KTextEditor::SmartRange*)),
00153       this,SLOT(rangeContentsChanged(KTextEditor::SmartRange*)));
00154 
00155     // Modify parent
00156     QWidget * const widget = centralWidget();
00157     widget->setLayout(m_layout);
00158     m_layout->setMargin(2);
00159 
00160     // Init highlight
00161     m_topRange = view()->doc()->newSmartRange(view()->doc()->documentRange());
00162     static_cast<KateSmartRange*>(m_topRange)->setInternal();
00163     m_topRange->setInsertBehavior(SmartRange::ExpandLeft | SmartRange::ExpandRight);
00164     enableHighlights(true);
00165 
00166 
00167     // Copy global to local config backup
00168     KateViewConfig * const globalConfig = KateGlobal::self()->viewConfig();
00169     const long searchFlags = globalConfig->searchFlags();
00170     m_incHighlightAll = (searchFlags & KateViewConfig::IncHighlightAll) != 0;
00171     m_incFromCursor = (searchFlags & KateViewConfig::IncFromCursor) != 0;
00172     m_incMatchCase = (searchFlags & KateViewConfig::IncMatchCase) != 0;
00173     m_powerMatchCase = (searchFlags & KateViewConfig::PowerMatchCase) != 0;
00174     m_powerFromCursor = (searchFlags & KateViewConfig::PowerFromCursor) != 0;
00175     m_powerHighlightAll = (searchFlags & KateViewConfig::PowerHighlightAll) != 0;
00176     m_powerMode = ((searchFlags & KateViewConfig::PowerModeRegularExpression) != 0)
00177             ? MODE_REGEX
00178             : (((searchFlags & KateViewConfig::PowerModeEscapeSequences) != 0)
00179                 ? MODE_ESCAPE_SEQUENCES
00180                 : (((searchFlags & KateViewConfig::PowerModeWholeWords) != 0)
00181                     ? MODE_WHOLE_WORDS
00182                     : MODE_PLAIN_TEXT));
00183 
00184 
00185     // Load one of either dialogs
00186     if (initAsPower) {
00187         onMutatePower();
00188     } else {
00189         onMutateIncremental();
00190     }
00191 }
00192 
00193 
00194 
00195 KateSearchBar::~KateSearchBar() {
00196 //  delete m_topRange; this gets deleted somewhere else (bug #176027)
00197     delete m_layout;
00198     delete m_widget;
00199 
00200     delete m_incUi;
00201     delete m_incMenu;
00202 
00203     delete m_powerUi;
00204     delete m_powerMenu;
00205 }
00206 
00207 
00208 
00209 void KateSearchBar::findNext() {
00210     if (m_incUi != NULL) {
00211         onIncNext();
00212     } else {
00213         onPowerFindNext();
00214     }
00215 }
00216 
00217 
00218 
00219 void KateSearchBar::findPrevious() {
00220     if (m_incUi != NULL) {
00221         onIncPrev();
00222     } else {
00223         onPowerFindPrev();
00224     }
00225 }
00226 
00227 
00228 
00229 void KateSearchBar::highlight(const Range & range, const QColor & color) {
00230     SmartRange * const highlight = view()->doc()->newSmartRange(range, m_topRange);
00231     highlight->setInsertBehavior(SmartRange::DoNotExpand);
00232     Attribute::Ptr attribute(new Attribute());
00233     attribute->setBackground(color);
00234     highlight->setAttribute(attribute);
00235     highlight->addNotifier(m_rangeNotifier);
00236 }
00237 
00238 
00239 
00240 void KateSearchBar::highlightMatch(const Range & range) {
00241     highlight(range, Qt::yellow); // TODO make this part of the color scheme
00242 }
00243 
00244 
00245 
00246 void KateSearchBar::highlightReplacement(const Range & range) {
00247     highlight(range, Qt::green); // TODO make this part of the color scheme
00248 }
00249 
00250 
00251 
00252 void KateSearchBar::highlightAllMatches(const QString & pattern,
00253         Search::SearchOptions searchOptions) {
00254     onForAll(pattern, view()->doc()->documentRange(),
00255             searchOptions, NULL);
00256 }
00257 
00258 void KateSearchBar::rangeContentsChanged(KTextEditor::SmartRange* range) {
00259   neutralMatch();
00260   Attribute::Ptr attribute(new Attribute());
00261   //attribute->setBackground(color);
00262   range->setAttribute(attribute);
00263 
00264 }
00265 
00266 void KateSearchBar::neutralMatch() {
00267     if (m_incUi != NULL) {
00268         QPalette background(m_incUi->pattern->palette());
00269         KColorScheme::adjustBackground(background, KColorScheme::NeutralBackground);
00270         m_incUi->pattern->setPalette(background);
00271     } else {
00272         QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00273         Q_ASSERT(lineEdit != NULL);
00274         QPalette background(lineEdit->palette());
00275         KColorScheme::adjustBackground(background, KColorScheme::NeutralBackground);
00276         lineEdit->setPalette(background);
00277     }
00278 }
00279 
00280 void KateSearchBar::indicateMatch(bool wrapped) {
00281     if (m_incUi != NULL) {
00282         // Green background for line edit
00283         QPalette background(m_incUi->pattern->palette());
00284         KColorScheme::adjustBackground(background, KColorScheme::PositiveBackground);
00285         m_incUi->pattern->setPalette(background);
00286 
00287         // Update status label
00288         m_incUi->status->setText(wrapped
00289                 ? i18n("Reached bottom, continued from top")
00290                 : "");
00291     } else {
00292         // Green background for line edit
00293         QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00294         Q_ASSERT(lineEdit != NULL);
00295         QPalette background(lineEdit->palette());
00296         KColorScheme::adjustBackground(background, KColorScheme::PositiveBackground);
00297         lineEdit->setPalette(background);
00298     }
00299 }
00300 
00301 
00302 
00303 void KateSearchBar::indicateMismatch() {
00304     if (m_incUi != NULL) {
00305         // Red background for line edit
00306         QPalette background(m_incUi->pattern->palette());
00307         KColorScheme::adjustBackground(background, KColorScheme::NegativeBackground);
00308         m_incUi->pattern->setPalette(background);
00309 
00310         // Update status label
00311         m_incUi->status->setText(i18n("Not found"));
00312     } else {
00313         // Red background for line edit
00314         QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00315         Q_ASSERT(lineEdit != NULL);
00316         QPalette background(lineEdit->palette());
00317         KColorScheme::adjustBackground(background, KColorScheme::NegativeBackground);
00318         lineEdit->setPalette(background);
00319     }
00320 }
00321 
00322 
00323 
00324 void KateSearchBar::indicateNothing() {
00325     if (m_incUi != NULL) {
00326         // Reset background of line edit
00327         m_incUi->pattern->setPalette(QPalette());
00328 
00329         // Update status label
00330         m_incUi->status->setText("");
00331     } else {
00332         // Reset background of line edit
00333         QLineEdit * const lineEdit = m_powerUi->pattern->lineEdit();
00334         Q_ASSERT(lineEdit != NULL);
00335         // ### this is fragile (depends on knowledge of QPalette::ColorGroup)
00336         // ...would it better to cache the original palette?
00337         QColor color = QPalette().color(QPalette::Base);
00338         QPalette background(lineEdit->palette());
00339         background.setBrush(QPalette::Active, QPalette::Base, QPalette().brush(QPalette::Active, QPalette::Base));
00340         background.setBrush(QPalette::Inactive, QPalette::Base, QPalette().brush(QPalette::Inactive, QPalette::Base));
00341         background.setBrush(QPalette::Disabled, QPalette::Base, QPalette().brush(QPalette::Disabled, QPalette::Base));
00342         lineEdit->setPalette(background);
00343     }
00344 }
00345 
00346 
00347 
00348 /*static*/ void KateSearchBar::selectRange(KateView * view, const KTextEditor::Range & range) {
00349     view->setCursorPositionInternal(range.start(), 1);
00350 
00351     // don't make a selection if the vi input mode is used
00352     if (!view->viInputMode())
00353         view->setSelection(range);
00354 }
00355 
00356 
00357 
00358 void KateSearchBar::buildReplacement(QString & output, QList<ReplacementPart> & parts,
00359         const QVector<Range> & details, int replacementCounter) {
00360     const int MIN_REF_INDEX = 0;
00361     const int MAX_REF_INDEX = details.count() - 1;
00362 
00363     output.clear();
00364     ReplacementPart::Type caseConversion = ReplacementPart::KeepCase;
00365     for (QList<ReplacementPart>::iterator iter = parts.begin(); iter != parts.end(); iter++) {
00366         ReplacementPart & curPart = *iter;
00367         switch (curPart.type) {
00368         case ReplacementPart::Reference:
00369             if ((curPart.index < MIN_REF_INDEX) || (curPart.index > MAX_REF_INDEX)) {
00370                 // Insert just the number to be consistent with QRegExp ("\c" becomes "c")
00371                 output.append(QString::number(curPart.index));
00372             } else {
00373                 const Range & captureRange = details[curPart.index];
00374                 if (captureRange.isValid()) {
00375                     // Copy capture content
00376                     const bool blockMode = view()->blockSelection();
00377                     const QString content = view()->doc()->text(captureRange, blockMode);
00378                     switch (caseConversion) {
00379                     case ReplacementPart::UpperCase:
00380                         // Copy as uppercase
00381                         output.append(content.toUpper());
00382                         break;
00383 
00384                     case ReplacementPart::LowerCase:
00385                         // Copy as lowercase
00386                         output.append(content.toLower());
00387                         break;
00388 
00389                     case ReplacementPart::KeepCase: // FALLTHROUGH
00390                     default:
00391                         // Copy unmodified
00392                         output.append(content);
00393                         break;
00394 
00395                     }
00396                 }
00397             }
00398             break;
00399 
00400         case ReplacementPart::UpperCase: // FALLTHROUGH
00401         case ReplacementPart::LowerCase: // FALLTHROUGH
00402         case ReplacementPart::KeepCase:
00403             caseConversion = curPart.type;
00404             break;
00405 
00406         case ReplacementPart::Counter:
00407             {
00408                 // Zero padded counter value
00409                 const int minWidth = curPart.index;
00410                 const int number = replacementCounter;
00411                 output.append(QString("%1").arg(number, minWidth, 10, QLatin1Char('0')));
00412             }
00413             break;
00414 
00415         case ReplacementPart::Text: // FALLTHROUGH
00416         default:
00417             switch (caseConversion) {
00418             case ReplacementPart::UpperCase:
00419                 // Copy as uppercase
00420                 output.append(curPart.text.toUpper());
00421                 break;
00422 
00423             case ReplacementPart::LowerCase:
00424                 // Copy as lowercase
00425                 output.append(curPart.text.toLower());
00426                 break;
00427 
00428             case ReplacementPart::KeepCase: // FALLTHROUGH
00429             default:
00430                 // Copy unmodified
00431                 output.append(curPart.text);
00432                 break;
00433 
00434             }
00435             break;
00436 
00437         }
00438     }
00439 }
00440 
00441 
00442 
00443 void KateSearchBar::replaceMatch(const QVector<Range> & match, const QString & replacement,
00444         int replacementCounter) {
00445     // Placeholders depending on search mode
00446     bool usePlaceholders = false;
00447     switch (m_powerUi->searchMode->currentIndex()) {
00448     case MODE_REGEX: // FALLTHROUGH
00449     case MODE_ESCAPE_SEQUENCES:
00450         usePlaceholders = true;
00451         break;
00452 
00453     default:
00454         break;
00455 
00456     }
00457 
00458     const Range & targetRange = match[0];
00459     QString finalReplacement;
00460     if (usePlaceholders) {
00461         // Resolve references and escape sequences
00462         QList<ReplacementPart> parts;
00463         QString writableHack(replacement);
00464         const bool REPLACEMENT_GOODIES = true;
00465         KateDocument::escapePlaintext(writableHack, &parts, REPLACEMENT_GOODIES);
00466         buildReplacement(finalReplacement, parts, match, replacementCounter);
00467     } else {
00468         // Plain text replacement
00469         finalReplacement = replacement;
00470     }
00471 
00472     const bool blockMode = (view()->blockSelection() && !targetRange.onSingleLine());
00473     view()->doc()->replaceText(targetRange, finalReplacement, blockMode);
00474 }
00475 
00476 
00477 
00478 void KateSearchBar::onIncPatternChanged(const QString & pattern, bool invokedByUserAction) {
00479     if (pattern.isEmpty()) {
00480         if (invokedByUserAction) {
00481             // Kill selection
00482             view()->setSelection(Range::invalid());
00483 
00484             // Kill highlight
00485             resetHighlights();
00486         }
00487 
00488         // Reset edit color
00489         indicateNothing();
00490 
00491         // Disable next/prev
00492         m_incUi->next->setDisabled(true);
00493         m_incUi->prev->setDisabled(true);
00494         return;
00495     }
00496 
00497     // Enable next/prev
00498     m_incUi->next->setDisabled(false);
00499     m_incUi->prev->setDisabled(false);
00500 
00501     if (invokedByUserAction) {
00502         // How to find?
00503         Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
00504         const bool matchCase = isChecked(m_incMenuMatchCase);
00505         if (!matchCase) {
00506             enabledOptions |= Search::CaseInsensitive;
00507         }
00508 
00509 
00510         // Where to find?
00511         Range inputRange;
00512         const bool fromCursor = isChecked(m_incMenuFromCursor);
00513         if (fromCursor) {
00514             inputRange.setRange(m_incInitCursor, view()->doc()->documentEnd());
00515         } else {
00516             inputRange = view()->doc()->documentRange();
00517         }
00518 
00519         // Find, first try
00520         const QVector<Range> resultRanges = view()->doc()->searchText(inputRange, pattern, enabledOptions);
00521         const Range & match = resultRanges[0];
00522 
00523         bool found = false;
00524         if (match.isValid()) {
00525             selectRange(view(), match);
00526             const bool NOT_WRAPPED = false;
00527             indicateMatch(NOT_WRAPPED);
00528             found = true;
00529         } else {
00530             // Wrap if it makes sense
00531             if (fromCursor) {
00532                 // Find, second try
00533                 inputRange = view()->doc()->documentRange();
00534                 const QVector<Range> resultRanges2 = view()->doc()->searchText(inputRange, pattern, enabledOptions);
00535                 const Range & match2 = resultRanges2[0];
00536                 if (match2.isValid()) {
00537                     selectRange(view(), match2);
00538                     const bool WRAPPED = true;
00539                     indicateMatch(WRAPPED);
00540                     found = true;
00541                 } else {
00542                     indicateMismatch();
00543                 }
00544             } else {
00545                 indicateMismatch();
00546             }
00547         }
00548 
00549         // Highlight all
00550         if (isChecked(m_incMenuHighlightAll)) {
00551             if (found ) {
00552                 highlightAllMatches(pattern, enabledOptions);
00553             } else {
00554                 resetHighlights();
00555             }
00556         }
00557         if (!found) {
00558           view()->setSelection(Range::invalid());
00559         }
00560     }
00561 }
00562 
00563 
00564 
00565 void KateSearchBar::onIncNext() {
00566     const bool FIND = false;
00567     onStep(FIND);
00568 }
00569 
00570 
00571 
00572 void KateSearchBar::onIncPrev() {
00573     const bool FIND = false;
00574     const bool BACKWARDS = false;
00575     onStep(FIND, BACKWARDS);
00576 }
00577 
00578 
00579 
00580 void KateSearchBar::onIncMatchCaseToggle(bool invokedByUserAction) {
00581     if (invokedByUserAction) {
00582         sendConfig();
00583 
00584         // Re-search with new settings
00585         const QString pattern = m_incUi->pattern->displayText();
00586         onIncPatternChanged(pattern);
00587     }
00588 }
00589 
00590 
00591 
00592 void KateSearchBar::onIncHighlightAllToggle(bool checked, bool invokedByUserAction) {
00593     if (invokedByUserAction) {
00594         sendConfig();
00595 
00596         if (checked) {
00597             const QString pattern = m_incUi->pattern->displayText();
00598             if (!pattern.isEmpty()) {
00599                 // How to search while highlighting?
00600                 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
00601                 const bool matchCase = isChecked(m_incMenuMatchCase);
00602                 if (!matchCase) {
00603                     enabledOptions |= Search::CaseInsensitive;
00604                 }
00605 
00606                 // Highlight them all
00607                 resetHighlights();
00608                 highlightAllMatches(pattern, enabledOptions);
00609             }
00610         } else {
00611             resetHighlights();
00612         }
00613     }
00614 }
00615 
00616 
00617 
00618 void KateSearchBar::onIncFromCursorToggle(bool invokedByUserAction) {
00619     if (invokedByUserAction) {
00620         sendConfig();
00621     }
00622 }
00623 
00624 
00625 
00626 void KateSearchBar::fixForSingleLine(Range & range, bool forwards) {
00627     FAST_DEBUG("Single-line workaround checking BEFORE" << range);
00628     if (forwards) {
00629         const int line = range.start().line();
00630         const int col = range.start().column();
00631         const int maxColWithNewline = view()->doc()->lineLength(line) + 1;
00632         if (col == maxColWithNewline) {
00633             FAST_DEBUG("Starting on a newline" << range);
00634             const int maxLine = view()->doc()->lines() - 1;
00635             if (line < maxLine) {
00636                 range.setRange(Cursor(line + 1, 0), range.end());
00637                 FAST_DEBUG("Search range fixed to " << range);
00638             } else {
00639                 FAST_DEBUG("Already at last line");
00640                 range = Range::invalid();
00641             }
00642         }
00643     } else {
00644         const int col = range.end().column();
00645         if (col == 0) {
00646             FAST_DEBUG("Ending after a newline" << range);
00647             const int line = range.end().line();
00648             if (line > 0) {
00649                 const int maxColWithNewline = view()->doc()->lineLength(line - 1);
00650                 range.setRange(range.start(), Cursor(line - 1, maxColWithNewline));
00651                 FAST_DEBUG("Search range fixed to " << range);
00652             } else {
00653                 FAST_DEBUG("Already at first line");
00654                 range = Range::invalid();
00655             }
00656         }
00657     }
00658     FAST_DEBUG("Single-line workaround checking  AFTER" << range);
00659 }
00660 
00661 
00662 
00663 void KateSearchBar::onReturnPressed() {
00664     const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
00665     const bool shiftDown = (modifiers & Qt::ShiftModifier) != 0;
00666     const bool controlDown = (modifiers & Qt::ControlModifier) != 0;
00667 
00668     if (shiftDown) {
00669         // Shift down, search backwards
00670         if (m_powerUi != NULL) {
00671             onPowerFindPrev();
00672         } else {
00673             onIncPrev();
00674         }
00675     } else {
00676         // Shift up, search forwards
00677         if (m_powerUi != NULL) {
00678             onPowerFindNext();
00679         } else {
00680             onIncNext();
00681         }
00682     }
00683 
00684     if (controlDown) {
00685         emit hideMe();
00686     }
00687 }
00688 
00689 
00690 
00691 bool KateSearchBar::onStep(bool replace, bool forwards) {
00692     // What to find?
00693     const QString pattern = (m_powerUi != NULL)
00694             ? m_powerUi->pattern->currentText()
00695             : m_incUi->pattern->displayText();
00696     if (pattern.isEmpty()) {
00697         return false; // == Pattern error
00698     }
00699 
00700     // How to find?
00701     Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
00702     const bool matchCase = (m_powerUi != NULL)
00703             ? isChecked(m_powerUi->matchCase)
00704             : isChecked(m_incMenuMatchCase);
00705     if (!matchCase) {
00706         enabledOptions |= Search::CaseInsensitive;
00707     }
00708 
00709     if (!forwards) {
00710         enabledOptions |= Search::Backwards;
00711     }
00712 
00713     bool multiLinePattern = false;
00714     bool regexMode = false;
00715     if (m_powerUi != NULL) {
00716         switch (m_powerUi->searchMode->currentIndex()) {
00717         case MODE_WHOLE_WORDS:
00718             enabledOptions |= Search::WholeWords;
00719             break;
00720 
00721         case MODE_ESCAPE_SEQUENCES:
00722             enabledOptions |= Search::EscapeSequences;
00723             break;
00724 
00725         case MODE_REGEX:
00726             {
00727                 // Check if pattern multi-line
00728                 QString patternCopy(pattern);
00729                 KateDocument::repairPattern(patternCopy, multiLinePattern);
00730                 regexMode = true;
00731             }
00732             enabledOptions |= Search::Regex;
00733             break;
00734 
00735         case MODE_PLAIN_TEXT: // FALLTHROUGH
00736         default:
00737             break;
00738 
00739         }
00740     }
00741 
00742 
00743     // Where to find?
00744     Range inputRange;
00745     Range selection;
00746     const bool selected = view()->selection();
00747     const bool selectionOnly = (m_powerUi != NULL)
00748             ? isChecked(m_powerMenuSelectionOnly)
00749             : false;
00750     if (selected) {
00751         selection = view()->selectionRange();
00752         if (selectionOnly) {
00753             // First match in selection
00754             inputRange = selection;
00755         } else {
00756             // Next match after/before selection if a match was selected before
00757             if (forwards) {
00758                 inputRange.setRange(selection.start(), view()->doc()->documentEnd());
00759             } else {
00760                 inputRange.setRange(Cursor(0, 0), selection.end());
00761             }
00762         }
00763     } else {
00764         // No selection
00765         const bool fromCursor = (m_powerUi != NULL)
00766                 ? isChecked(m_powerMenuFromCursor)
00767                 : isChecked(m_incMenuFromCursor);
00768         if (fromCursor) {
00769             const Cursor cursorPos = view()->cursorPosition();
00770             if (forwards) {
00771                 // if the vi input mode is used, the cursor will stay a the first character of the
00772                 // matched pattern (no selection will be made), so the next search should start from
00773                 // match column + 1
00774                 if (!view()->viInputMode()) {
00775                     inputRange.setRange(cursorPos, view()->doc()->documentEnd());
00776                 } else {
00777                     inputRange.setRange(Cursor(cursorPos.line(), cursorPos.column()+1), view()->doc()->documentEnd());
00778                 }
00779             } else {
00780                 inputRange.setRange(Cursor(0, 0), cursorPos);
00781             }
00782         } else {
00783             inputRange = view()->doc()->documentRange();
00784         }
00785     }
00786     FAST_DEBUG("Search range is" << inputRange);
00787 
00788     // Single-line pattern workaround
00789     if (regexMode && !multiLinePattern) {
00790         fixForSingleLine(inputRange, forwards);
00791     }
00792 
00793 
00794     // Find, first try
00795     const QVector<Range> resultRanges = view()->doc()->searchText(inputRange, pattern, enabledOptions);
00796     const Range & match = resultRanges[0];
00797     bool wrap = false;
00798     bool found = false;
00799     SmartRange * afterReplace = NULL;
00800     if (match.isValid()) {
00801         // Previously selected match again?
00802         if (selected && (match == selection) && (!selectionOnly || replace)) {
00803             // Same match again
00804             if (replace) {
00805                 // Selection is match -> replace
00806                 const QString replacement = m_powerUi->replacement->currentText();
00807                 afterReplace = view()->doc()->newSmartRange(match);
00808                 afterReplace->setInsertBehavior(SmartRange::ExpandRight | SmartRange::ExpandLeft);
00809                 replaceMatch(resultRanges, replacement);
00810 
00811                 // Find, second try after replaced text
00812                 if (forwards) {
00813                     inputRange.setRange(afterReplace->end(), inputRange.end());
00814                 } else {
00815                     inputRange.setRange(inputRange.start(), afterReplace->start());
00816                 }
00817             } else {
00818                 // Find, second try after old selection
00819                 if (forwards) {
00820                     inputRange.setRange(selection.end(), inputRange.end());
00821                 } else {
00822                     inputRange.setRange(inputRange.start(), selection.start());
00823                 }
00824             }
00825 
00826             // Single-line pattern workaround
00827             fixForSingleLine(inputRange, forwards);
00828 
00829             const QVector<Range> resultRanges2 = view()->doc()->searchText(inputRange, pattern, enabledOptions);
00830             const Range & match2 = resultRanges2[0];
00831             if (match2.isValid()) {
00832                 selectRange(view(), match2);
00833                 found = true;
00834                 const bool NOT_WRAPPED = false;
00835                 indicateMatch(NOT_WRAPPED);
00836             } else {
00837                 // Find, third try from doc start on
00838                 wrap = true;
00839             }
00840         } else {
00841             selectRange(view(), match);
00842             found = true;
00843             const bool NOT_WRAPPED = false;
00844             indicateMatch(NOT_WRAPPED);
00845         }
00846     } else if (!selected || !selectionOnly) {
00847         // Find, second try from doc start on
00848         wrap = true;
00849     }
00850 
00851     // Wrap around
00852     if (wrap) {
00853         inputRange = view()->doc()->documentRange();
00854         const QVector<Range> resultRanges3 = view()->doc()->searchText(inputRange, pattern, enabledOptions);
00855         const Range & match3 = resultRanges3[0];
00856         if (match3.isValid()) {
00857             // Previously selected match again?
00858             if (selected && !selectionOnly && (match3 == selection)) {
00859                 // NOOP, same match again
00860             } else {
00861                 selectRange(view(), match3);
00862                 found = true;
00863             }
00864             const bool WRAPPED = true;
00865             indicateMatch(WRAPPED);
00866         } else {
00867             indicateMismatch();
00868         }
00869     }
00870 
00871     // Highlight all matches and/or replacement
00872     const bool highlightAll = (m_powerUi != NULL)
00873             ? isChecked(m_powerMenuHighlightAll)
00874             : isChecked(m_incMenuHighlightAll);
00875     if ((found && highlightAll) || (afterReplace != NULL)) {
00876         // Highlight all matches
00877         if (found && highlightAll) {
00878             highlightAllMatches(pattern, enabledOptions);
00879         }
00880 
00881         // Highlight replacement (on top if overlapping) if new match selected
00882         if (found && (afterReplace != NULL)) {
00883             // Note: highlightAllMatches already reset for us
00884             if (!(found && highlightAll)) {
00885                 resetHighlights();
00886             }
00887 
00888             highlightReplacement(*afterReplace);
00889         }
00890 
00891     }
00892 
00893     delete afterReplace;
00894 
00895     return true; // == No pattern error
00896 }
00897 
00898 
00899 
00900 void KateSearchBar::onPowerPatternChanged(const QString & pattern) {
00901     givePatternFeedback(pattern);
00902     indicateNothing();
00903 }
00904 
00905 
00906 
00907 void KateSearchBar::givePatternFeedback(const QString & pattern) {
00908     bool enabled = true;
00909 
00910     if (pattern.isEmpty()) {
00911         enabled = false;
00912     } else {
00913         switch (m_powerUi->searchMode->currentIndex()) {
00914         case MODE_WHOLE_WORDS:
00915             if (pattern.trimmed() != pattern) {
00916                 enabled = false;
00917             }
00918             break;
00919 
00920         case MODE_REGEX:
00921             m_patternTester.setPattern(pattern);
00922             enabled = m_patternTester.isValid();
00923             break;
00924 
00925         case MODE_ESCAPE_SEQUENCES: // FALLTHROUGH
00926         case MODE_PLAIN_TEXT: // FALLTHROUGH
00927         default:
00928             ; // NOOP
00929 
00930         }
00931     }
00932 
00933     // Enable/disable next/prev and replace next/all
00934     m_powerUi->findNext->setDisabled(!enabled);
00935     m_powerUi->findPrev->setDisabled(!enabled);
00936     m_powerUi->replaceNext->setDisabled(!enabled);
00937     m_powerUi->replaceAll->setDisabled(!enabled);
00938 }
00939 
00940 
00941 
00942 void KateSearchBar::addCurrentTextToHistory(QComboBox * combo) {
00943     const QString text = combo->currentText();
00944     const int index = combo->findText(text);
00945     if (index != -1) {
00946         combo->removeItem(index);
00947     }
00948     combo->insertItem(0, text);
00949     combo->setCurrentIndex(0);
00950 }
00951 
00952 
00953 
00954 void KateSearchBar::backupConfig(bool ofPower) {
00955     if (ofPower) {
00956         m_powerMatchCase = isChecked(m_powerUi->matchCase);
00957         m_powerFromCursor = isChecked(m_powerMenuFromCursor);
00958         m_powerHighlightAll = isChecked(m_powerMenuHighlightAll);
00959         m_powerMode = m_powerUi->searchMode->currentIndex();
00960     } else {
00961         m_incHighlightAll = isChecked(m_incMenuHighlightAll);
00962         m_incFromCursor = isChecked(m_incMenuFromCursor);
00963         m_incMatchCase = isChecked(m_incMenuMatchCase);
00964     }
00965 }
00966 
00967 
00968 
00969 void KateSearchBar::sendConfig() {
00970     KateViewConfig * const globalConfig = KateGlobal::self()->viewConfig();
00971     const long pastFlags = globalConfig->searchFlags();
00972     long futureFlags = pastFlags;
00973 
00974     if (m_powerUi != NULL) {
00975         const bool OF_POWER = true;
00976         backupConfig(OF_POWER);
00977 
00978         // Update power search flags only
00979         const long incFlagsOnly = pastFlags
00980                 & (KateViewConfig::IncHighlightAll
00981                     | KateViewConfig::IncFromCursor
00982                     | KateViewConfig::IncMatchCase);
00983 
00984         futureFlags = incFlagsOnly
00985             | (m_powerMatchCase ? KateViewConfig::PowerMatchCase : 0)
00986             | (m_powerFromCursor ? KateViewConfig::PowerFromCursor : 0)
00987             | (m_powerHighlightAll ? KateViewConfig::PowerHighlightAll : 0)
00988             | ((m_powerMode == MODE_REGEX)
00989                 ? KateViewConfig::PowerModeRegularExpression
00990                 : ((m_powerMode == MODE_ESCAPE_SEQUENCES)
00991                     ? KateViewConfig::PowerModeEscapeSequences
00992                     : ((m_powerMode == MODE_WHOLE_WORDS)
00993                         ? KateViewConfig::PowerModeWholeWords
00994                         : KateViewConfig::PowerModePlainText)));
00995 
00996     } else if (m_incUi != NULL) {
00997         const bool OF_INCREMENTAL = false;
00998         backupConfig(OF_INCREMENTAL);
00999 
01000         // Update incremental search flags only
01001         const long powerFlagsOnly = pastFlags
01002                 & (KateViewConfig::PowerMatchCase
01003                     | KateViewConfig::PowerFromCursor
01004                     | KateViewConfig::PowerHighlightAll
01005                     | KateViewConfig::PowerModeRegularExpression
01006                     | KateViewConfig::PowerModeEscapeSequences
01007                     | KateViewConfig::PowerModeWholeWords
01008                     | KateViewConfig::PowerModePlainText);
01009 
01010         futureFlags = powerFlagsOnly
01011                 | (m_incHighlightAll ? KateViewConfig::IncHighlightAll : 0)
01012                 | (m_incFromCursor ? KateViewConfig::IncFromCursor : 0)
01013                 | (m_incMatchCase ? KateViewConfig::IncMatchCase : 0);
01014     }
01015 
01016     // Adjust global config
01017     globalConfig->setSearchFlags(futureFlags);
01018 }
01019 
01020 
01021 
01022 void KateSearchBar::onPowerFindNext() {
01023     const bool FIND = false;
01024     if (onStep(FIND)) {
01025         // Add to search history
01026         addCurrentTextToHistory(m_powerUi->pattern);
01027     }
01028 }
01029 
01030 
01031 
01032 void KateSearchBar::onPowerFindPrev() {
01033     const bool FIND = false;
01034     const bool BACKWARDS = false;
01035     if (onStep(FIND, BACKWARDS)) {
01036         // Add to search history
01037         addCurrentTextToHistory(m_powerUi->pattern);
01038     }
01039 }
01040 
01041 
01042 
01043 void KateSearchBar::onPowerReplaceNext() {
01044     const bool REPLACE = true;
01045     if (onStep(REPLACE)) {
01046         // Add to search history
01047         addCurrentTextToHistory(m_powerUi->pattern);
01048 
01049         // Add to replace history
01050         addCurrentTextToHistory(m_powerUi->replacement);
01051     }
01052 }
01053 
01054 
01055 
01056 // replacement == NULL --> Highlight all matches
01057 // replacement != NULL --> Replace and highlight all matches
01058 void KateSearchBar::onForAll(const QString & pattern, Range inputRange,
01059         Search::SearchOptions enabledOptions,
01060         const QString * replacement) {
01061     bool multiLinePattern = false;
01062     const bool regexMode = enabledOptions.testFlag(Search::Regex);
01063     if (regexMode) {
01064         // Check if pattern multi-line
01065         QString patternCopy(pattern);
01066         KateDocument::repairPattern(patternCopy, multiLinePattern);
01067     }
01068 
01069     // Clear backwards flag, this algorithm is for forward mode
01070     if (enabledOptions.testFlag(Search::Backwards)) {
01071         enabledOptions &= ~Search::SearchOptions(Search::Backwards);
01072     }
01073 
01074     // Before first match
01075     resetHighlights();
01076 
01077     SmartRange * const workingRange = view()->doc()->newSmartRange(inputRange);
01078     int matchCounter = 0;
01079     for (;;) {
01080         const QVector<Range> resultRanges = view()->doc()->searchText(*workingRange, pattern, enabledOptions);
01081         Range match = resultRanges[0];
01082         if (!match.isValid()) {
01083             break;
01084         }
01085         bool const originalMatchEmpty = match.isEmpty();
01086 
01087         // Work with the match
01088         if (replacement != NULL) {
01089             if (matchCounter == 0) {
01090                 view()->doc()->editBegin();
01091             }
01092 
01093             // Track replacement operation
01094             SmartRange * const afterReplace = view()->doc()->newSmartRange(match);
01095             afterReplace->setInsertBehavior(SmartRange::ExpandRight | SmartRange::ExpandLeft);
01096 
01097             // Replace
01098             replaceMatch(resultRanges, *replacement, ++matchCounter);
01099 
01100             // Highlight and continue after adjusted match
01101             highlightReplacement(*afterReplace);
01102             match = *afterReplace;
01103             delete afterReplace;
01104         } else {
01105             // Highlight and continue after original match
01106             highlightMatch(match);
01107             matchCounter++;
01108         }
01109 
01110         // Continue after match
01111         SmartCursor & workingStart = workingRange->smartStart();
01112         workingStart.setPosition(match.end());
01113         if (originalMatchEmpty) {
01114             // Can happen for regex patterns like "^".
01115             // If we don't advance here we will loop forever...
01116             workingStart.advance(1);
01117         } else if (regexMode && !multiLinePattern && workingStart.atEndOfLine()) {
01118             // single-line regexps might match the naked line end
01119             // therefore we better advance to the next line
01120             workingStart.advance(1);
01121         }
01122 
01123         // Are we done?
01124         if (!workingRange->isValid() || workingStart.atEndOfDocument()) {
01125             break;
01126         }
01127     }
01128 
01129     // After last match
01130     if (matchCounter > 0) {
01131         if (replacement != NULL) {
01132             view()->doc()->editEnd();
01133         }
01134     }
01135 
01136     delete workingRange;
01137 }
01138 
01139 
01140 
01141 void KateSearchBar::onPowerReplaceAll() {
01142     // What to find/replace?
01143     const QString pattern = m_powerUi->pattern->currentText();
01144     const QString replacement = m_powerUi->replacement->currentText();
01145 
01146 
01147     // How to find?
01148     Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
01149     const bool matchCase = isChecked(m_powerUi->matchCase);
01150     if (!matchCase) {
01151         enabledOptions |= Search::CaseInsensitive;
01152     }
01153 
01154     if (m_powerUi != NULL) {
01155         switch (m_powerUi->searchMode->currentIndex()) {
01156         case MODE_WHOLE_WORDS:
01157             enabledOptions |= Search::WholeWords;
01158             break;
01159 
01160         case MODE_ESCAPE_SEQUENCES:
01161             enabledOptions |= Search::EscapeSequences;
01162             break;
01163 
01164         case MODE_REGEX:
01165             enabledOptions |= Search::Regex;
01166             break;
01167 
01168         case MODE_PLAIN_TEXT: // FALLTHROUGH
01169         default:
01170             break;
01171 
01172         }
01173     }
01174 
01175 
01176     // Where to replace?
01177     Range selection;
01178     const bool selected = view()->selection();
01179     const bool selectionOnly = isChecked(m_powerMenuSelectionOnly);
01180     Range inputRange = (selected && selectionOnly)
01181             ? view()->selectionRange()
01182             : view()->doc()->documentRange();
01183 
01184 
01185     // Pass on the hard work
01186     onForAll(pattern, inputRange, enabledOptions, &replacement);
01187 
01188 
01189     // Add to search history
01190     addCurrentTextToHistory(m_powerUi->pattern);
01191 
01192     // Add to replace history
01193     addCurrentTextToHistory(m_powerUi->replacement);
01194 }
01195 
01196 
01197 
01198 struct ParInfo {
01199     int openIndex;
01200     bool capturing;
01201     int captureNumber; // 1..9
01202 };
01203 
01204 
01205 
01206 QVector<QString> KateSearchBar::getCapturePatterns(const QString & pattern) {
01207     QVector<QString> capturePatterns;
01208     capturePatterns.reserve(9);
01209     QStack<ParInfo> parInfos;
01210 
01211     const int inputLen = pattern.length();
01212     int input = 0; // walker index
01213     bool insideClass = false;
01214     int captureCount = 0;
01215 
01216     while (input < inputLen) {
01217         if (insideClass) {
01218             // Wait for closing, unescaped ']'
01219             if (pattern[input].unicode() == L']') {
01220                 insideClass = false;
01221             }
01222             input++;
01223         }
01224         else
01225         {
01226             switch (pattern[input].unicode())
01227             {
01228             case L'\\':
01229                 // Skip this and any next character
01230                 input += 2;
01231                 break;
01232 
01233             case L'(':
01234                 ParInfo curInfo;
01235                 curInfo.openIndex = input;
01236                 curInfo.capturing = (input + 1 >= inputLen) || (pattern[input + 1].unicode() != '?');
01237                 if (curInfo.capturing) {
01238                     captureCount++;
01239                 }
01240                 curInfo.captureNumber = captureCount;
01241                 parInfos.push(curInfo);
01242 
01243                 input++;
01244                 break;
01245 
01246             case L')':
01247                 if (!parInfos.empty()) {
01248                     ParInfo & top = parInfos.top();
01249                     if (top.capturing && (top.captureNumber <= 9)) {
01250                         const int start = top.openIndex + 1;
01251                         const int len = input - start;
01252                         if (capturePatterns.size() < top.captureNumber) {
01253                             capturePatterns.resize(top.captureNumber);
01254                         }
01255                         capturePatterns[top.captureNumber - 1] = pattern.mid(start, len);
01256                     }
01257                     parInfos.pop();
01258                 }
01259 
01260                 input++;
01261                 break;
01262 
01263             case L'[':
01264                 input++;
01265                 insideClass = true;
01266                 break;
01267 
01268             default:
01269                 input++;
01270                 break;
01271 
01272             }
01273         }
01274     }
01275 
01276     return capturePatterns;
01277 }
01278 
01279 
01280 
01281 void KateSearchBar::showExtendedContextMenu(bool forPattern) {
01282     // Make original menu
01283     QMenu * const contextMenu = m_powerUi->pattern->lineEdit()->createStandardContextMenu();
01284     if (contextMenu == NULL) {
01285         return;
01286     }
01287 
01288     bool extendMenu = false;
01289     bool regexMode = false;
01290     switch (m_powerUi->searchMode->currentIndex()) {
01291     case MODE_REGEX: 
01292         regexMode = true;
01293         // FALLTHROUGH
01294 
01295     case MODE_ESCAPE_SEQUENCES:
01296         extendMenu = true;
01297         break;
01298 
01299     default:
01300         break;
01301     }
01302 
01303     AddMenuManager addMenuManager(contextMenu, 35);
01304     if (!extendMenu) {
01305         addMenuManager.enableMenu(extendMenu);
01306     } else {
01307         // Build menu
01308         if (forPattern) {
01309             if (regexMode) {
01310                 addMenuManager.addEntry("^", "", i18n("Beginning of line"));
01311                 addMenuManager.addEntry("$", "", i18n("End of line"));
01312                 addMenuManager.addSeparator();
01313                 addMenuManager.addEntry(".", "", i18n("Any single character (excluding line breaks)"));
01314                 addMenuManager.addSeparator();
01315                 addMenuManager.addEntry("+", "", i18n("One or more occurrences"));
01316                 addMenuManager.addEntry("*", "", i18n("Zero or more occurrences"));
01317                 addMenuManager.addEntry("?", "", i18n("Zero or one occurrences"));
01318                 addMenuManager.addEntry("{a", ",b}", i18n("<a> through <b> occurrences"), "{", ",}");
01319                 addMenuManager.addSeparator();
01320                 addMenuManager.addEntry("(", ")", i18n("Group, capturing"));
01321                 addMenuManager.addEntry("|", "", i18n("Or"));
01322                 addMenuManager.addEntry("[", "]", i18n("Set of characters"));
01323                 addMenuManager.addEntry("[^", "]", i18n("Negative set of characters"));
01324                 addMenuManager.addSeparator();
01325             }
01326         } else {
01327             addMenuManager.addEntry("\\0", "", i18n("Whole match reference"));
01328             addMenuManager.addSeparator();
01329             if (regexMode) {
01330                 const QString pattern = m_powerUi->pattern->currentText();
01331                 const QVector<QString> capturePatterns = getCapturePatterns(pattern);
01332     
01333                 const int captureCount = capturePatterns.count();
01334                 for (int i = 1; i <= 9; i++) {
01335                     const QString number = QString::number(i);
01336                     const QString & captureDetails = (i <= captureCount)
01337                             ? (QString(" = (") + capturePatterns[i - 1].left(30)) + QString(")")
01338                             : QString();
01339                     addMenuManager.addEntry("\\" + number, "",
01340                             i18n("Reference") + ' ' + number + captureDetails);
01341                 }
01342     
01343                 addMenuManager.addSeparator();
01344             }
01345         }
01346     
01347         addMenuManager.addEntry("\\n", "", i18n("Line break"));
01348         addMenuManager.addEntry("\\t", "", i18n("Tab"));
01349     
01350         if (forPattern && regexMode) {
01351             addMenuManager.addEntry("\\b", "", i18n("Word boundary"));
01352             addMenuManager.addEntry("\\B", "", i18n("Not word boundary"));
01353             addMenuManager.addEntry("\\d", "", i18n("Digit"));
01354             addMenuManager.addEntry("\\D", "", i18n("Non-digit"));
01355             addMenuManager.addEntry("\\s", "", i18n("Whitespace (excluding line breaks)"));
01356             addMenuManager.addEntry("\\S", "", i18n("Non-whitespace (excluding line breaks)"));
01357             addMenuManager.addEntry("\\w", "", i18n("Word character (alphanumerics plus '_')"));
01358             addMenuManager.addEntry("\\W", "", i18n("Non-word character"));
01359         }
01360     
01361         addMenuManager.addEntry("\\0???", "", i18n("Octal character 000 to 377 (2^8-1)"), "\\0");
01362         addMenuManager.addEntry("\\x????", "", i18n("Hex character 0000 to FFFF (2^16-1)"), "\\x");
01363         addMenuManager.addEntry("\\\\", "", i18n("Backslash"));
01364     
01365         if (forPattern && regexMode) {
01366             addMenuManager.addSeparator();
01367             addMenuManager.addEntry("(?:E", ")", i18n("Group, non-capturing"), "(?:");
01368             addMenuManager.addEntry("(?=E", ")", i18n("Lookahead"), "(?=");
01369             addMenuManager.addEntry("(?!E", ")", i18n("Negative lookahead"), "(?!");
01370         }
01371     
01372         if (!forPattern) {
01373             addMenuManager.addSeparator();
01374             addMenuManager.addEntry("\\L", "", i18n("Begin lowercase conversion"));
01375             addMenuManager.addEntry("\\U", "", i18n("Begin uppercase conversion"));
01376             addMenuManager.addEntry("\\E", "", i18n("End case conversion"));
01377             addMenuManager.addEntry("\\#[#..]", "", i18n("Replacement counter (for Replace All)"), "\\#");
01378         }
01379     }
01380 
01381     // Show menu
01382     QAction * const result = contextMenu->exec(QCursor::pos());
01383     if (result != NULL) {
01384         QLineEdit * const lineEdit = forPattern
01385                 ? m_powerUi->pattern->lineEdit()
01386                 : m_powerUi->replacement->lineEdit();
01387         Q_ASSERT(lineEdit != NULL);
01388         addMenuManager.handle(result, lineEdit);
01389     }
01390 }
01391 
01392 
01393 
01394 void KateSearchBar::onPowerMatchCaseToggle(bool invokedByUserAction) {
01395     if (invokedByUserAction) {
01396         sendConfig();
01397         indicateNothing();
01398     }
01399 }
01400 
01401 
01402 
01403 void KateSearchBar::onPowerHighlightAllToggle(bool checked, bool invokedByUserAction) {
01404     if (invokedByUserAction) {
01405         sendConfig();
01406 
01407         if (checked) {
01408             const QString pattern = m_powerUi->pattern->currentText();
01409             if (!pattern.isEmpty()) {
01410                 // How to search while highlighting?
01411                 Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
01412                 const bool matchCase = isChecked(m_powerUi->matchCase);
01413                 if (!matchCase) {
01414                     enabledOptions |= Search::CaseInsensitive;
01415                 }
01416 
01417                 switch (m_powerUi->searchMode->currentIndex()) {
01418                 case MODE_WHOLE_WORDS:
01419                     enabledOptions |= Search::WholeWords;
01420                     break;
01421 
01422                 case MODE_ESCAPE_SEQUENCES:
01423                     enabledOptions |= Search::EscapeSequences;
01424                     break;
01425 
01426                 case MODE_REGEX:
01427                     enabledOptions |= Search::Regex;
01428                     break;
01429 
01430                 case MODE_PLAIN_TEXT: // FALLTHROUGH
01431                 default:
01432                     break;
01433 
01434                 }
01435 
01436                 // Highlight them all
01437                 resetHighlights();
01438                 highlightAllMatches(pattern, enabledOptions);
01439             }
01440         } else {
01441             resetHighlights();
01442         }
01443     }
01444 }
01445 
01446 
01447 
01448 void KateSearchBar::onPowerFromCursorToggle(bool invokedByUserAction) {
01449     if (invokedByUserAction) {
01450         sendConfig();
01451     }
01452 }
01453 
01454 
01455 
01456 void KateSearchBar::onPowerModeChangedPlainText() {
01457     m_powerUi->searchMode->setCurrentIndex(MODE_PLAIN_TEXT);
01458     onPowerModeChanged();
01459 }
01460 
01461 
01462 
01463 void KateSearchBar::onPowerModeChangedWholeWords() {
01464     m_powerUi->searchMode->setCurrentIndex(MODE_WHOLE_WORDS);
01465     onPowerModeChanged();
01466 }
01467 
01468 
01469 
01470 void KateSearchBar::onPowerModeChangedEscapeSequences() {
01471     m_powerUi->searchMode->setCurrentIndex(MODE_ESCAPE_SEQUENCES);
01472     onPowerModeChanged();
01473 }
01474 
01475 
01476 
01477 void KateSearchBar::onPowerModeChangedRegularExpression() {
01478     m_powerUi->searchMode->setCurrentIndex(MODE_REGEX);
01479     onPowerModeChanged();
01480 }
01481 
01482 
01483 
01484 void KateSearchBar::onPowerModeChanged() {
01485     if (m_powerUi->searchMode->currentIndex() == MODE_REGEX) {
01486         setChecked(m_powerUi->matchCase, true);
01487     }
01488 
01489     sendConfig();
01490     indicateNothing();
01491 }
01492 
01493 
01494 
01495 void KateSearchBar::onPowerModeChanged(int /*index*/, bool invokedByUserAction) {
01496     if (invokedByUserAction) {
01497         onPowerModeChanged();
01498     }
01499 
01500     givePatternFeedback(m_powerUi->pattern->currentText());
01501 }
01502 
01503 
01504 
01505 /*static*/ void KateSearchBar::nextMatchForSelection(KateView * view, bool forwards) {
01506     const bool selected = view->selection();
01507     if (selected) {
01508         const QString pattern = view->selectionText();
01509 
01510         // How to find?
01511         Search::SearchOptions enabledOptions(KTextEditor::Search::Default);
01512         if (!forwards) {
01513             enabledOptions |= Search::Backwards;
01514         }
01515 
01516         // Where to find?
01517         const Range selRange = view->selectionRange();
01518         Range inputRange;
01519         if (forwards) {
01520             inputRange.setRange(selRange.end(), view->doc()->documentEnd());
01521         } else {
01522             inputRange.setRange(Cursor(0, 0), selRange.start());
01523         }
01524 
01525         // Find, first try
01526         const QVector<Range> resultRanges = view->doc()->searchText(inputRange, pattern, enabledOptions);
01527         const Range & match = resultRanges[0];
01528 
01529         if (match.isValid()) {
01530             selectRange(view, match);
01531         } else {
01532             // Find, second try
01533             if (forwards) {
01534                 inputRange.setRange(Cursor(0, 0), selRange.start());
01535             } else {
01536                 inputRange.setRange(selRange.end(), view->doc()->documentEnd());
01537             }
01538             const QVector<Range> resultRanges2 = view->doc()->searchText(inputRange, pattern, enabledOptions);
01539             const Range & match2 = resultRanges2[0];
01540             if (match2.isValid()) {
01541                 selectRange(view, match2);
01542             }
01543         }
01544     } else {
01545         // Select current word so we can search for that the next time
01546         const Cursor cursorPos = view->cursorPosition();
01547         view->selectWord(cursorPos);
01548     }
01549 }
01550 
01551 
01552 
01553 void KateSearchBar::onMutatePower() {
01554     QString initialPattern;
01555     bool selectionOnly = false;
01556 
01557     // Guess settings from context: init pattern with current selection
01558     const bool selected = view()->selection();
01559     if (selected) {
01560         const Range & selection = view()->selectionRange();
01561         if (selection.onSingleLine()) {
01562             // ... with current selection
01563             initialPattern = view()->selectionText();
01564         } else {
01565             // Enable selection only
01566             selectionOnly = true;
01567         }
01568     }
01569 
01570     // If there's no new selection, we'll use the existing pattern
01571     if (initialPattern.isNull()) {
01572         // Coming from power search?
01573         const bool fromReplace = (m_powerUi != NULL) && (m_widget->isVisible());
01574         if (fromReplace) {
01575             QLineEdit * const patternLineEdit = m_powerUi->pattern->lineEdit();
01576             Q_ASSERT(patternLineEdit != NULL);
01577             patternLineEdit->selectAll();
01578             m_powerUi->pattern->setFocus(Qt::MouseFocusReason);
01579             return;
01580         }
01581 
01582         // Coming from incremental search?
01583         const bool fromIncremental = (m_incUi != NULL) && (m_widget->isVisible());
01584         if (fromIncremental) {
01585             initialPattern = m_incUi->pattern->displayText();
01586         }
01587     }
01588 
01589     // Create dialog
01590     const bool create = (m_powerUi == NULL);
01591     if (create) {
01592         // Kill incremental widget
01593         if (m_incUi != NULL) {
01594             // Backup current settings
01595             const bool OF_INCREMENTAL = false;
01596             backupConfig(OF_INCREMENTAL);
01597 
01598             // Kill widget
01599             delete m_incUi;
01600             delete m_incMenu;
01601             m_incUi = NULL;
01602             m_incMenu = NULL;
01603             m_incMenuMatchCase = NULL;
01604             m_incMenuFromCursor = NULL;
01605             m_incMenuHighlightAll = NULL;
01606             m_layout->removeWidget(m_widget);
01607             m_widget->deleteLater(); // I didn't get a crash here but for symmetrie to the other mutate slot^
01608         }
01609 
01610         // Add power widget
01611         m_widget = new QWidget(this);
01612         m_powerUi = new Ui::PowerSearchBar;
01613         m_powerUi->setupUi(m_widget);
01614         m_layout->addWidget(m_widget);
01615 
01616         // Bind to shared history models
01617         const int MAX_HISTORY_SIZE = 100; // Please don't lower this value! Thanks, Sebastian
01618         QStringListModel * const patternHistoryModel = KateHistoryModel::getPatternHistoryModel();
01619         QStringListModel * const replacementHistoryModel = KateHistoryModel::getReplacementHistoryModel();
01620         m_powerUi->pattern->setMaxCount(MAX_HISTORY_SIZE);
01621         m_powerUi->pattern->setModel(patternHistoryModel);
01622         m_powerUi->replacement->setMaxCount(MAX_HISTORY_SIZE);
01623         m_powerUi->replacement->setModel(replacementHistoryModel);
01624 
01625         // Fill options menu
01626         m_powerMenu = new QMenu();
01627         m_powerUi->options->setMenu(m_powerMenu);
01628         m_powerMenuFromCursor = m_powerMenu->addAction(i18n("From &cursor"));
01629         m_powerMenuFromCursor->setCheckable(true);
01630         m_powerMenuHighlightAll = m_powerMenu->addAction(i18n("Hi&ghlight all"));
01631         m_powerMenuHighlightAll->setCheckable(true);
01632         m_powerMenuSelectionOnly = m_powerMenu->addAction(i18n("Selection &only"));
01633         m_powerMenuSelectionOnly->setCheckable(true);
01634 
01635         // Grab Alt+1 .. Alt+4 for search mode switching
01636         connect(new QShortcut(QKeySequence(Qt::ALT + Qt::Key_1), m_widget,
01637                 0, 0, Qt::WidgetWithChildrenShortcut), SIGNAL(activated()),
01638                 this, SLOT(onPowerModeChangedPlainText()));
01639         connect(new QShortcut(QKeySequence(Qt::ALT + Qt::Key_2), m_widget,
01640                 0, 0, Qt::WidgetWithChildrenShortcut), SIGNAL(activated()),
01641                 this, SLOT(onPowerModeChangedWholeWords()));
01642         connect(new QShortcut(QKeySequence(Qt::ALT + Qt::Key_3), m_widget,
01643                 0, 0, Qt::WidgetWithChildrenShortcut), SIGNAL(activated()),
01644                 this, SLOT(onPowerModeChangedEscapeSequences()));
01645         connect(new QShortcut(QKeySequence(Qt::ALT + Qt::Key_4), m_widget,
01646                 0, 0, Qt::WidgetWithChildrenShortcut), SIGNAL(activated()),
01647                 this, SLOT(onPowerModeChangedRegularExpression()));
01648 
01649         // Icons
01650         m_powerUi->mutate->setIcon(KIcon("arrow-down-double"));
01651         m_powerUi->findNext->setIcon(KIcon("go-down"));
01652         m_powerUi->findPrev->setIcon(KIcon("go-up"));
01653 
01654         // Focus proxy
01655         centralWidget()->setFocusProxy(m_powerUi->pattern);
01656 
01657         // Make completers case-sensitive
01658         QLineEdit * const patternLineEdit = m_powerUi->pattern->lineEdit();
01659         Q_ASSERT(patternLineEdit != NULL);
01660         patternLineEdit->completer()->setCaseSensitivity(Qt::CaseSensitive);
01661 
01662         QLineEdit * const replacementLineEdit = m_powerUi->pattern->lineEdit();
01663         Q_ASSERT(replacementLineEdit != NULL);
01664         replacementLineEdit->completer()->setCaseSensitivity(Qt::CaseSensitive);
01665     }
01666 
01667     setChecked(m_powerMenuSelectionOnly, selectionOnly);
01668 
01669     // Restore previous settings
01670     if (create) {
01671         setChecked(m_powerUi->matchCase, m_powerMatchCase);
01672         setChecked(m_powerMenuHighlightAll, m_powerHighlightAll);
01673         setChecked(m_powerMenuFromCursor, m_powerFromCursor);
01674         m_powerUi->searchMode->setCurrentIndex(m_powerMode);
01675     }
01676 
01677     // Set initial search pattern
01678     QLineEdit * const patternLineEdit = m_powerUi->pattern->lineEdit();
01679     Q_ASSERT(patternLineEdit != NULL);
01680     patternLineEdit->setText(initialPattern);
01681     patternLineEdit->selectAll();
01682 
01683     // Set initial replacement text
01684     QLineEdit * const replacementLineEdit = m_powerUi->replacement->lineEdit();
01685     Q_ASSERT(replacementLineEdit != NULL);
01686     replacementLineEdit->setText("");
01687 
01688     // Propagate settings (slots are still inactive on purpose)
01689     onPowerPatternChanged(initialPattern);
01690     const bool NOT_INVOKED_BY_USER_ACTION = false;
01691     onPowerModeChanged(m_powerUi->searchMode->currentIndex(), NOT_INVOKED_BY_USER_ACTION);
01692 
01693     if (create) {
01694         // Slots
01695         connect(m_powerUi->mutate, SIGNAL(clicked()), this, SLOT(onMutateIncremental()));
01696         connect(patternLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(onPowerPatternChanged(const QString &)));
01697         connect(m_powerUi->findNext, SIGNAL(clicked()), this, SLOT(onPowerFindNext()));
01698         connect(m_powerUi->findPrev, SIGNAL(clicked()), this, SLOT(onPowerFindPrev()));
01699         connect(m_powerUi->replaceNext, SIGNAL(clicked()), this, SLOT(onPowerReplaceNext()));
01700         connect(m_powerUi->replaceAll, SIGNAL(clicked()), this, SLOT(onPowerReplaceAll()));
01701         connect(m_powerUi->searchMode, SIGNAL(currentIndexChanged(int)), this, SLOT(onPowerModeChanged(int)));
01702         connect(m_powerUi->matchCase, SIGNAL(stateChanged(int)), this, SLOT(onPowerMatchCaseToggle()));
01703         connect(m_powerMenuHighlightAll, SIGNAL(toggled(bool)), this, SLOT(onPowerHighlightAllToggle(bool)));
01704         connect(m_powerMenuFromCursor, SIGNAL(changed()), this, SLOT(onPowerFromCursorToggle()));
01705 
01706         // Make button click open the menu as well. IMHO with the dropdown arrow present the button
01707         // better shows his nature than in instant popup mode.
01708         connect(m_powerUi->options, SIGNAL(clicked()), m_powerUi->options, SLOT(showMenu()));
01709 
01710         // Make [return] in pattern line edit trigger <find next> action
01711         connect(patternLineEdit, SIGNAL(returnPressed()), this, SLOT(onReturnPressed()));
01712         connect(replacementLineEdit, SIGNAL(returnPressed()), this, SLOT(onPowerReplaceNext()));
01713 
01714         // Hook into line edit context menus
01715         patternLineEdit->setContextMenuPolicy(Qt::CustomContextMenu);
01716         connect(patternLineEdit, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onPowerPatternContextMenuRequest()));
01717         replacementLineEdit->setContextMenuPolicy(Qt::CustomContextMenu);
01718         connect(replacementLineEdit, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onPowerReplacmentContextMenuRequest()));
01719     }
01720 
01721     // Focus
01722     if (m_widget->isVisible()) {
01723         m_powerUi->pattern->setFocus(Qt::MouseFocusReason);
01724     }
01725 }
01726 
01727 
01728 
01729 void KateSearchBar::onMutateIncremental() {
01730     QString initialPattern;
01731 
01732     // Guess settings from context: init pattern with current selection
01733     const bool selected = view()->selection();
01734     if (selected) {
01735         const Range & selection = view()->selectionRange();
01736         if (selection.onSingleLine()) {
01737             // ... with current selection
01738             initialPattern = view()->selectionText();
01739         }
01740     }
01741 
01742     // If there's no new selection, we'll use the existing pattern
01743     if (initialPattern.isNull()) {
01744         // Coming from incremental search?
01745         const bool fromIncremental = (m_incUi != NULL) && (m_widget->isVisible());
01746         if (fromIncremental) {
01747             m_incUi->pattern->selectAll();
01748             m_incUi->pattern->setFocus(Qt::MouseFocusReason);
01749             return;
01750         }
01751 
01752         // Coming from power search?
01753         const bool fromReplace = (m_powerUi != NULL) && (m_widget->isVisible());
01754         if (fromReplace) {
01755             initialPattern = m_powerUi->pattern->currentText();
01756         }
01757     }
01758 
01759     // Create dialog
01760     const bool create = (m_incUi == NULL);
01761     if (create) {
01762         // Kill power widget
01763         if (m_powerUi != NULL) {
01764             // Backup current settings
01765             const bool OF_POWER = true;
01766             backupConfig(OF_POWER);
01767 
01768             // Kill widget
01769             delete m_powerUi;
01770             m_powerUi = NULL;
01771             m_layout->removeWidget(m_widget);
01772             m_widget->deleteLater(); //deleteLater, because it's not a good idea too delete the widget and there for the button triggering this slot
01773         }
01774 
01775         // Add incremental widget
01776         m_widget = new QWidget(this);
01777         m_incUi = new Ui::IncrementalSearchBar;
01778         m_incUi->setupUi(m_widget);
01779         m_layout->addWidget(m_widget);
01780 
01781         new QShortcut(KStandardShortcut::paste().primary(), m_incUi->pattern, SLOT(paste()), 0, Qt::WidgetWithChildrenShortcut);
01782         if (!KStandardShortcut::paste().alternate().isEmpty())
01783             new QShortcut(KStandardShortcut::paste().alternate(), m_incUi->pattern, SLOT(paste()), 0, Qt::WidgetWithChildrenShortcut);
01784 
01785 
01786         // Fill options menu
01787         m_incMenu = new QMenu();
01788         m_incUi->options->setMenu(m_incMenu);
01789         m_incMenuFromCursor = m_incMenu->addAction(i18n("From &cursor"));
01790         m_incMenuFromCursor->setCheckable(true);
01791         m_incMenuHighlightAll = m_incMenu->addAction(i18n("Hi&ghlight all"));
01792         m_incMenuHighlightAll->setCheckable(true);
01793         m_incMenuMatchCase = m_incMenu->addAction(i18n("&Match case"));
01794         m_incMenuMatchCase->setCheckable(true);
01795 
01796         // Icons
01797         m_incUi->mutate->setIcon(KIcon("arrow-up-double"));
01798         m_incUi->next->setIcon(KIcon("go-down"));
01799         m_incUi->prev->setIcon(KIcon("go-up"));
01800 
01801     // Customize status area
01802     m_incUi->status->setTextElideMode(Qt::ElideLeft);
01803 
01804         // Focus proxy
01805         centralWidget()->setFocusProxy(m_incUi->pattern);
01806     }
01807 
01808     // Restore previous settings
01809     if (create) {
01810         setChecked(m_incMenuHighlightAll, m_incHighlightAll);
01811         setChecked(m_incMenuFromCursor, m_incFromCursor);
01812         setChecked(m_incMenuMatchCase, m_incMatchCase);
01813     }
01814 
01815     // Set initial search pattern
01816     m_incUi->pattern->setText(initialPattern);
01817     m_incUi->pattern->selectAll();
01818 
01819     // Propagate settings (slots are still inactive on purpose)
01820     const bool NOT_INVOKED_BY_USER_ACTION = false;
01821     onIncPatternChanged(initialPattern, NOT_INVOKED_BY_USER_ACTION);
01822 
01823     if (create) {
01824         // Slots
01825         connect(m_incUi->mutate, SIGNAL(clicked()), this, SLOT(onMutatePower()));
01826         connect(m_incUi->pattern, SIGNAL(returnPressed()), this, SLOT(onReturnPressed()));
01827         connect(m_incUi->pattern, SIGNAL(textChanged(const QString &)), this, SLOT(onIncPatternChanged(const QString &)));
01828         connect(m_incUi->next, SIGNAL(clicked()), this, SLOT(onIncNext()));
01829         connect(m_incUi->prev, SIGNAL(clicked()), this, SLOT(onIncPrev()));
01830         connect(m_incMenuMatchCase, SIGNAL(changed()), this, SLOT(onIncMatchCaseToggle()));
01831         connect(m_incMenuFromCursor, SIGNAL(changed()), this, SLOT(onIncFromCursorToggle()));
01832         connect(m_incMenuHighlightAll, SIGNAL(toggled(bool)), this, SLOT(onIncHighlightAllToggle(bool)));
01833 
01834         // Make button click open the menu as well. IMHO with the dropdown arrow present the button
01835         // better shows his nature than in instant popup mode.
01836         connect(m_incUi->options, SIGNAL(clicked()), m_incUi->options, SLOT(showMenu()));
01837     }
01838 
01839     // Focus
01840     if (m_widget->isVisible()) {
01841         m_incUi->pattern->setFocus(Qt::MouseFocusReason);
01842     }
01843 }
01844 
01845 
01846 
01847 bool KateSearchBar::isChecked(QCheckBox * checkbox) {
01848     Q_ASSERT(checkbox != NULL);
01849     return checkbox->checkState() == Qt::Checked;
01850 }
01851 
01852 
01853 
01854 bool KateSearchBar::isChecked(QAction * menuAction) {
01855     Q_ASSERT(menuAction != NULL);
01856     return menuAction->isChecked();
01857 }
01858 
01859 
01860 
01861 void KateSearchBar::setChecked(QCheckBox * checkbox, bool checked) {
01862     Q_ASSERT(checkbox != NULL);
01863     checkbox->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
01864 }
01865 
01866 
01867 
01868 void KateSearchBar::setChecked(QAction * menuAction, bool checked) {
01869     Q_ASSERT(menuAction != NULL);
01870     menuAction->setChecked(checked);
01871 }
01872 
01873 
01874 
01875 void KateSearchBar::enableHighlights(bool enable) {
01876     if (enable) {
01877         view()->addInternalHighlight(m_topRange);
01878     } else {
01879         view()->removeInternalHighlight(m_topRange);
01880         m_topRange->deleteChildRanges();
01881     }
01882 }
01883 
01884 
01885 
01886 void KateSearchBar::resetHighlights() {
01887     enableHighlights(false);
01888     enableHighlights(true);
01889 }
01890 
01891 
01892 
01893 void KateSearchBar::showEvent(QShowEvent * event) {
01894     // Update init cursor
01895     if (m_incUi != NULL) {
01896         m_incInitCursor = view()->cursorPosition();
01897     }
01898 
01899     connect(view(), SIGNAL(selectionChanged(KTextEditor::View *)),
01900             this, SLOT(onSelectionChanged()));
01901     connect(view(), SIGNAL(cursorPositionChanged(KTextEditor::View *, KTextEditor::Cursor const &)),
01902             this, SLOT(onCursorPositionChanged()));
01903 
01904     enableHighlights(true);
01905     KateViewBarWidget::showEvent(event);
01906 }
01907 
01908 
01909 
01910 void KateSearchBar::closed() {
01911     disconnect(view(), SIGNAL(selectionChanged(KTextEditor::View *)),
01912             this, SLOT(onSelectionChanged()));
01913     disconnect(view(), SIGNAL(cursorPositionChanged(KTextEditor::View *, KTextEditor::Cursor const &)),
01914             this, SLOT(onCursorPositionChanged()));
01915 
01916     enableHighlights(false);
01917 }
01918 
01919 
01920 
01921 void KateSearchBar::onSelectionChanged() {
01922     if (m_powerUi == NULL) {
01923         return;
01924     }
01925 
01926     // Re-init "Selection only" checkbox if power search bar open
01927     const bool selected = view()->selection();
01928     bool selectionOnly = selected;
01929     if (selected) {
01930         Range const & selection = view()->selectionRange();
01931         selectionOnly = !selection.onSingleLine();
01932     }
01933     setChecked(m_powerMenuSelectionOnly, selectionOnly);
01934 }
01935 
01936 
01937 void KateSearchBar::onCursorPositionChanged() {
01938     if (m_incUi == NULL) {
01939         return;
01940     }
01941 
01942     // Update init cursor
01943     m_incInitCursor = view()->cursorPosition();
01944 }
01945 
01946 
01947 void KateSearchBar::onPowerPatternContextMenuRequest() {
01948     const bool FOR_PATTERN = true;
01949     showExtendedContextMenu(FOR_PATTERN);
01950 }
01951 
01952 
01953 
01954 void KateSearchBar::onPowerReplacmentContextMenuRequest() {
01955     const bool FOR_REPLACEMENT = false;
01956     showExtendedContextMenu(FOR_REPLACEMENT);
01957 }
01958 
01959 
01960 #include "katesearchbar.moc"
01961 
01962 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal