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