22 #include "kfinddialog_p.h"
24 #include <QtGui/QCheckBox>
25 #include <QtGui/QCursor>
26 #include <QtGui/QGroupBox>
27 #include <QtGui/QLabel>
28 #include <QtGui/QLayout>
29 #include <QtGui/QLineEdit>
30 #include <QtGui/QMenu>
31 #include <QtGui/QPushButton>
32 #include <QtCore/QRegExp>
40 #include <kregexpeditorinterface.h>
45 d(new KFindDialogPrivate(this))
51 d->init(replaceDialog, findStrings, hasSelection);
63 if (!d->findExtension)
65 d->findExtension =
new QWidget(d->findGrp);
66 d->findLayout->addWidget(d->findExtension, 3, 0, 1, 2);
69 return d->findExtension;
74 return d->find->historyItems();
77 void KFindDialog::KFindDialogPrivate::init(
bool forReplace,
const QStringList &_findStrings,
bool hasSelection)
79 QVBoxLayout *topLayout;
80 QGridLayout *optionsLayout;
84 q->setMainWidget(page);
86 topLayout =
new QVBoxLayout(page);
87 topLayout->setMargin( 0 );
90 findLayout =
new QGridLayout(findGrp);
94 find->setMaxCount(10);
95 find->setDuplicatesEnabled(
false);
96 regExp =
new QCheckBox(
i18n(
"Regular e&xpression"), findGrp);
98 regExpItem->setEnabled(
false);
100 findLayout->addWidget(findLabel, 0, 0);
101 findLayout->addWidget(
find, 1, 0, 1, 2);
102 findLayout->addWidget(regExp, 2, 0);
103 findLayout->addWidget(regExpItem, 2, 1);
104 topLayout->addWidget(findGrp);
107 replaceLayout =
new QGridLayout(replaceGrp);
112 replace->setDuplicatesEnabled(
false);
113 backRef =
new QCheckBox(
i18n(
"Use p&laceholders"), replaceGrp);
114 backRefItem =
new QPushButton(
i18n(
"Insert Place&holder"), replaceGrp);
115 backRefItem->setEnabled(
false);
117 replaceLayout->addWidget(replaceLabel, 0, 0);
118 replaceLayout->addWidget(
replace, 1, 0, 1, 2);
119 replaceLayout->addWidget(backRef, 2, 0);
120 replaceLayout->addWidget(backRefItem, 2, 1);
121 topLayout->addWidget(replaceGrp);
124 optionsLayout =
new QGridLayout(optionGrp);
126 caseSensitive =
new QCheckBox(
i18n(
"C&ase sensitive"), optionGrp);
127 wholeWordsOnly =
new QCheckBox(
i18n(
"&Whole words only"), optionGrp);
128 fromCursor =
new QCheckBox(
i18n(
"From c&ursor"), optionGrp);
129 findBackwards =
new QCheckBox(
i18n(
"Find &backwards"), optionGrp);
130 selectedText =
new QCheckBox(
i18n(
"&Selected text"), optionGrp);
131 q->setHasSelection( hasSelection );
134 selectedText->setChecked( hasSelection );
135 _k_slotSelectedTextToggled( hasSelection );
137 promptOnReplace =
new QCheckBox(
i18n(
"&Prompt on replace"), optionGrp);
138 promptOnReplace->setChecked(
true );
140 optionsLayout->addWidget(caseSensitive, 0, 0);
141 optionsLayout->addWidget(wholeWordsOnly, 1, 0);
142 optionsLayout->addWidget(fromCursor, 2, 0);
143 optionsLayout->addWidget(findBackwards, 0, 1);
144 optionsLayout->addWidget(selectedText, 1, 1);
145 optionsLayout->addWidget(promptOnReplace, 2, 1);
146 topLayout->addWidget(optionGrp);
153 q->connect(selectedText, SIGNAL(toggled(
bool)), q, SLOT(_k_slotSelectedTextToggled(
bool)));
154 q->connect(regExp, SIGNAL(toggled(
bool)), regExpItem, SLOT(setEnabled(
bool)));
155 q->connect(backRef, SIGNAL(toggled(
bool)), backRefItem, SLOT(setEnabled(
bool)));
156 q->connect(regExpItem, SIGNAL(clicked()), q, SLOT(_k_showPatterns()));
157 q->connect(backRefItem, SIGNAL(clicked()), q, SLOT(_k_showPlaceholders()));
159 q->connect(
find, SIGNAL(editTextChanged(
QString)), q, SLOT(_k_textSearchChanged(
QString)));
161 q->connect(regExp, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
162 q->connect(backRef, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
163 q->connect(caseSensitive, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
164 q->connect(wholeWordsOnly, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
165 q->connect(fromCursor, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
166 q->connect(findBackwards, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
167 q->connect(selectedText, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
168 q->connect(promptOnReplace, SIGNAL(toggled(
bool)), q, SIGNAL(optionsChanged()));
171 q->setTabOrder(
find, regExp);
172 q->setTabOrder(regExp, regExpItem);
173 q->setTabOrder(regExpItem,
replace);
174 q->setTabOrder(
replace, backRef);
175 q->setTabOrder(backRef, backRefItem);
176 q->setTabOrder(backRefItem, caseSensitive);
177 q->setTabOrder(caseSensitive, wholeWordsOnly);
178 q->setTabOrder(wholeWordsOnly, fromCursor);
179 q->setTabOrder(fromCursor, findBackwards);
180 q->setTabOrder(findBackwards, selectedText);
181 q->setTabOrder(selectedText, promptOnReplace);
184 findLabel->setBuddy(
find);
185 replaceLabel->setBuddy(
replace);
189 promptOnReplace->hide();
193 findStrings = _findStrings;
195 q->enableButtonOk( !q->pattern().isEmpty() );
199 i18n(
"Start replace"),
200 i18n(
"<qt>If you press the <b>Replace</b> button, the text you entered "
201 "above is searched for within the document and any occurrence is "
202 "replaced with the replacement text.</qt>")));
207 i18n(
"Start searching"),
208 i18n(
"<qt>If you press the <b>Find</b> button, the text you entered "
209 "above is searched for within the document.</qt>")));
214 "Enter a pattern to search for, or select a previous pattern from "
216 regExp->setWhatsThis(
i18n(
217 "If enabled, search for a regular expression.") );
218 regExpItem->setWhatsThis(
i18n(
219 "Click here to edit your regular expression using a graphical editor.") );
221 "Enter a replacement string, or select a previous one from the list.") );
222 backRef->setWhatsThis(
i18n(
223 "<qt>If enabled, any occurrence of <code><b>\\N</b></code>, where "
224 "<code><b>N</b></code> is an integer number, will be replaced with "
225 "the corresponding capture (\"parenthesized substring\") from the "
226 "pattern.<p>To include (a literal <code><b>\\N</b></code> in your "
227 "replacement, put an extra backslash in front of it, like "
228 "<code><b>\\\\N</b></code>.</p></qt>") );
229 backRefItem->setWhatsThis(
i18n(
230 "Click for a menu of available captures.") );
231 wholeWordsOnly->setWhatsThis(
i18n(
232 "Require word boundaries in both ends of a match to succeed.") );
233 fromCursor->setWhatsThis(
i18n(
234 "Start searching at the current cursor location rather than at the top.") );
235 selectedText->setWhatsThis(
i18n(
236 "Only search within the current selection.") );
237 caseSensitive->setWhatsThis(
i18n(
238 "Perform a case sensitive search: entering the pattern "
239 "'Joe' will not match 'joe' or 'JOE', only 'Joe'.") );
240 findBackwards->setWhatsThis(
i18n(
241 "Search backwards.") );
242 promptOnReplace->setWhatsThis(
i18n(
243 "Ask before replacing each match found.") );
245 q->connect(q, SIGNAL(okClicked()), q, SLOT(_k_slotOk()));
246 _k_textSearchChanged(
find->lineEdit()->text());
249 void KFindDialog::KFindDialogPrivate::_k_textSearchChanged(
const QString & text)
251 q->enableButtonOk( !text.isEmpty() );
256 if ( !d->initialShowDone )
258 d->initialShowDone =
true;
259 kDebug() <<
"showEvent\n";
260 if (!d->findStrings.isEmpty())
263 if (!d->pattern.isEmpty()) {
264 d->find->lineEdit()->setText( d->pattern );
265 d->find->lineEdit()->selectAll();
269 if (d->findExtension) {
271 foreach(
QWidget* child, d->findExtension->findChildren<
QWidget*>()) {
272 setTabOrder(prev, child);
275 setTabOrder(prev, d->replace);
285 if (d->caseSensitive->isChecked())
287 if (d->wholeWordsOnly->isChecked())
289 if (d->fromCursor->isChecked())
291 if (d->findBackwards->isChecked())
293 if (d->selectedText->isChecked())
295 if (d->regExp->isChecked())
302 return d->find->currentText();
307 d->find->lineEdit()->setText( pattern );
308 d->find->lineEdit()->selectAll();
315 if (strings.count() > 0)
317 d->find->setHistoryItems(strings,
true);
318 d->find->lineEdit()->setText( strings.first() );
319 d->find->lineEdit()->selectAll();
322 d->find->clearHistory();
328 else d->enabled &= ~
KFind::SelectedText;
329 d->selectedText->setEnabled( hasSelection );
332 d->selectedText->setChecked(
false );
333 d->_k_slotSelectedTextToggled( hasSelection );
337 void KFindDialog::KFindDialogPrivate::_k_slotSelectedTextToggled(
bool selec)
342 fromCursor->setChecked(
false );
347 if (hasCursor) d->enabled |= KFind::FromCursor;
348 else d->enabled &= ~
KFind::FromCursor;
349 d->fromCursor->setEnabled( hasCursor );
350 d->fromCursor->setChecked( hasCursor && (
options() & KFind::FromCursor) );
357 else d->enabled &= ~
KFind::FindBackwards;
358 d->findBackwards->setEnabled( supports );
366 else d->enabled &= ~
KFind::CaseSensitive;
367 d->caseSensitive->setEnabled( supports );
375 else d->enabled &= ~
KFind::WholeWordsOnly;
376 d->wholeWordsOnly->setEnabled( supports );
383 else d->enabled &= ~
KFind::RegularExpression;
384 d->regExp->setEnabled( supports );
388 d->regExpItem->hide();
393 d->regExpItem->show();
402 d->fromCursor->setChecked((d->enabled & KFind::FromCursor) && (options & KFind::FromCursor));
410 void KFindDialog::KFindDialogPrivate::_k_showPatterns()
412 if ( !regexpDialogQueryDone )
414 regexpDialog = KServiceTypeTrader::createInstanceFromQuery<QDialog>(
"KRegExpEditor/KRegExpEditor",
QString(), q );
415 regexpDialogQueryDone =
true;
420 KRegExpEditorInterface *iface = qobject_cast<KRegExpEditorInterface*>( regexpDialog );
423 iface->setRegExp( q->pattern() );
424 if ( regexpDialog->exec() == QDialog::Accepted )
425 q->setPattern( iface->regExp() );
431 const char *description;
433 int cursorAdjustment;
435 static const term items[] =
440 {
I18N_NOOP(
"Set of Characters"),
"[]", -1 },
441 {
I18N_NOOP(
"Repeats, Zero or More Times"),
"*", 0 },
442 {
I18N_NOOP(
"Repeats, One or More Times"),
"+", 0 },
447 {
I18N_NOOP(
"Carriage Return"),
"\\r", 0 },
453 class RegExpAction :
public QAction
457 :
QAction( text, parent ), mText( text ), mRegExp( regExp ), mCursor( cursor )
461 QString text()
const {
return mText; }
462 QString regExp()
const {
return mRegExp; }
463 int cursor()
const {
return mCursor; }
476 patterns =
new QMenu(q);
477 for (i = 0; (unsigned)i <
sizeof(items) /
sizeof(items[0]); i++)
479 patterns->addAction(
new RegExpAction(patterns,
i18n(items[i].description),
481 items[i].cursorAdjustment));
486 QAction *action = patterns->exec(regExpItem->mapToGlobal(regExpItem->rect().bottomLeft()));
489 RegExpAction *regExpAction =
static_cast<RegExpAction*
>( action );
490 if ( regExpAction ) {
493 editor->insert(regExpAction->regExp());
494 editor->setCursorPosition(editor->cursorPosition() + regExpAction->cursor());
500 class PlaceHolderAction :
public QAction
504 :
QAction( text, parent ), mText( text ), mId( id )
508 QString text()
const {
return mText; }
509 int id()
const {
return mId; }
518 void KFindDialog::KFindDialogPrivate::_k_showPlaceholders()
523 placeholders =
new QMenu(q);
524 q->connect( placeholders, SIGNAL(aboutToShow()), q, SLOT(_k_slotPlaceholdersAboutToShow()) );
528 QAction *action = placeholders->exec(backRefItem->mapToGlobal(backRefItem->rect().bottomLeft()));
531 PlaceHolderAction *placeHolderAction =
static_cast<PlaceHolderAction*
>(action);
532 if (placeHolderAction) {
534 editor->insert(
QString(
"\\%1").arg( placeHolderAction->id() ) );
539 void KFindDialog::KFindDialogPrivate::_k_slotPlaceholdersAboutToShow()
541 placeholders->clear();
542 placeholders->addAction(
new PlaceHolderAction(placeholders,
i18n(
"Complete Match"), 0));
544 QRegExp r( q->pattern() );
545 uint n = r.numCaptures();
546 for ( uint i=0; i < n; i++ )
547 placeholders->addAction(
new PlaceHolderAction(placeholders,
i18n(
"Captured Text (%1)", i+1 ), i+1 ) );
550 void KFindDialog::KFindDialogPrivate::_k_slotOk()
553 if (q->pattern().isEmpty())
559 if (regExp->isChecked())
562 QRegExp _regExp(q->pattern());
564 if (!_regExp.isValid())
570 find->addToHistory(q->pattern());
571 if ( q->windowModality() != Qt::NonModal )
575 #include "kfinddialog.moc"