00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "kfinddialog.h"
00022
#include <qcheckbox.h>
00023
#include <qcursor.h>
00024
#include <qgroupbox.h>
00025
#include <qlabel.h>
00026
#include <qlayout.h>
00027
#include <qpopupmenu.h>
00028
#include <qpushbutton.h>
00029
#include <qregexp.h>
00030
#include <kcombobox.h>
00031
#include <kdebug.h>
00032
#include <klocale.h>
00033
#include <kmessagebox.h>
00034
#include <assert.h>
00035
#include <qwhatsthis.h>
00036
00037
#include <kregexpeditorinterface.h>
00038
#include <kparts/componentfactory.h>
00039
00040
class KFindDialog::KFindDialogPrivate
00041 {
00042
public:
00043 KFindDialogPrivate() : m_regexpDialog(0),
00044 m_regexpDialogQueryDone(false),
00045 m_enabled(WholeWordsOnly | FromCursor | SelectedText | CaseSensitive | FindBackwards | RegularExpression), m_initialShowDone(false) {}
00046
QDialog* m_regexpDialog;
00047
bool m_regexpDialogQueryDone;
00048
long m_enabled;
00049
bool m_initialShowDone;
00050
QStringList findStrings;
00051
QString pattern;
00052 };
00053
00054 KFindDialog::KFindDialog(
QWidget *parent,
const char *name,
long options,
const QStringList &findStrings,
bool hasSelection) :
00055
KDialogBase(parent, name, true, i18n("Find Text"), Ok | Cancel, Ok),
00056 m_findExtension (0),
00057 m_replaceExtension (0)
00058 {
00059 d =
new KFindDialogPrivate;
00060 init(
false, findStrings, hasSelection);
00061
setOptions(options);
00062 setButtonCancel( KStdGuiItem::close() );
00063 }
00064
00065 KFindDialog::KFindDialog(
bool modal,
QWidget *parent,
const char *name,
long options,
const QStringList &findStrings,
bool hasSelection) :
00066
KDialogBase(parent, name, modal, i18n("Find Text"), Ok | Cancel, Ok),
00067 m_findExtension (0),
00068 m_replaceExtension (0)
00069 {
00070 d =
new KFindDialogPrivate;
00071 init(
false, findStrings, hasSelection);
00072
setOptions(options);
00073 setButtonCancel( KStdGuiItem::close() );
00074 }
00075
00076 KFindDialog::KFindDialog(
QWidget *parent,
const char *name,
bool ) :
00077
KDialogBase(parent, name, true, i18n("Replace Text"), Ok | Cancel, Ok),
00078 m_findExtension (0),
00079 m_replaceExtension (0)
00080 {
00081 d =
new KFindDialogPrivate;
00082 setButtonCancel( KStdGuiItem::close() );
00083 }
00084
00085 KFindDialog::~KFindDialog()
00086 {
00087
delete d;
00088 }
00089
00090 QWidget *
KFindDialog::findExtension()
00091 {
00092
if (!m_findExtension)
00093 {
00094 m_findExtension =
new QWidget(m_findGrp);
00095 m_findLayout->
addMultiCellWidget(m_findExtension, 3, 3, 0, 1);
00096 }
00097
00098
return m_findExtension;
00099 }
00100
00101 QStringList KFindDialog::findHistory()
const
00102
{
00103
return m_find->
historyItems();
00104 }
00105
00106
void KFindDialog::init(
bool forReplace,
const QStringList &findStrings,
bool hasSelection)
00107 {
00108
QVBoxLayout *topLayout;
00109
QGridLayout *optionsLayout;
00110
00111
00112
QWidget *page =
new QWidget(
this);
00113 setMainWidget(page);
00114
00115 topLayout =
new QVBoxLayout(page);
00116 topLayout->setSpacing( KDialog::spacingHint() );
00117 topLayout->setMargin( 0 );
00118
00119 m_findGrp =
new QGroupBox(0, Qt::Vertical, i18n(
"Find"), page);
00120 m_findGrp->layout()->setSpacing( KDialog::spacingHint() );
00121
00122 m_findLayout =
new QGridLayout(m_findGrp->layout());
00123 m_findLayout->setSpacing( KDialog::spacingHint() );
00124
00125
00126 m_findLabel =
new QLabel(i18n(
"&Text to find:"), m_findGrp);
00127 m_find =
new KHistoryCombo(
true, m_findGrp);
00128 m_find->
setMaxCount(10);
00129 m_find->
setDuplicatesEnabled(
false);
00130 m_regExp =
new QCheckBox(i18n(
"Regular e&xpression"), m_findGrp);
00131 m_regExpItem =
new QPushButton(i18n(
"&Edit..."), m_findGrp);
00132 m_regExpItem->setEnabled(
false);
00133
00134 m_findLayout->
addWidget(m_findLabel, 0, 0);
00135 m_findLayout->
addMultiCellWidget(m_find, 1, 1, 0, 1);
00136 m_findLayout->
addWidget(m_regExp, 2, 0);
00137 m_findLayout->
addWidget(m_regExpItem, 2, 1);
00138 topLayout->addWidget(m_findGrp);
00139
00140 m_replaceGrp =
new QGroupBox(0, Qt::Vertical, i18n(
"Replace With"), page);
00141 m_replaceGrp->layout()->setSpacing( KDialog::spacingHint() );
00142
00143 m_replaceLayout =
new QGridLayout(m_replaceGrp->layout());
00144 m_replaceLayout->setSpacing( KDialog::spacingHint() );
00145
00146
00147 m_replaceLabel =
new QLabel(i18n(
"Replace&ment text:"), m_replaceGrp);
00148 m_replace =
new KHistoryCombo(
true, m_replaceGrp);
00149 m_replace->
setMaxCount(10);
00150 m_replace->
setDuplicatesEnabled(
false);
00151 m_backRef =
new QCheckBox(i18n(
"Use p&laceholders"), m_replaceGrp);
00152 m_backRefItem =
new QPushButton(i18n(
"Insert Place&holder"), m_replaceGrp);
00153 m_backRefItem->setEnabled(
false);
00154
00155 m_replaceLayout->
addWidget(m_replaceLabel, 0, 0);
00156 m_replaceLayout->
addMultiCellWidget(m_replace, 1, 1, 0, 1);
00157 m_replaceLayout->
addWidget(m_backRef, 2, 0);
00158 m_replaceLayout->
addWidget(m_backRefItem, 2, 1);
00159 topLayout->addWidget(m_replaceGrp);
00160
00161 m_optionGrp =
new QGroupBox(0, Qt::Vertical, i18n(
"Options"), page);
00162 m_optionGrp->layout()->setSpacing(KDialog::spacingHint());
00163
00164 optionsLayout =
new QGridLayout(m_optionGrp->layout());
00165 optionsLayout->setSpacing( KDialog::spacingHint() );
00166
00167
00168 m_caseSensitive =
new QCheckBox(i18n(
"C&ase sensitive"), m_optionGrp);
00169 m_wholeWordsOnly =
new QCheckBox(i18n(
"&Whole words only"), m_optionGrp);
00170 m_fromCursor =
new QCheckBox(i18n(
"From c&ursor"), m_optionGrp);
00171 m_findBackwards =
new QCheckBox(i18n(
"Find &backwards"), m_optionGrp);
00172 m_selectedText =
new QCheckBox(i18n(
"&Selected text"), m_optionGrp);
00173 setHasSelection( hasSelection );
00174
00175
00176 m_selectedText->
setChecked( hasSelection );
00177 slotSelectedTextToggled( hasSelection );
00178
00179 m_promptOnReplace =
new QCheckBox(i18n(
"&Prompt on replace"), m_optionGrp);
00180 m_promptOnReplace->
setChecked(
true );
00181
00182 optionsLayout->
addWidget(m_caseSensitive, 0, 0);
00183 optionsLayout->
addWidget(m_wholeWordsOnly, 1, 0);
00184 optionsLayout->
addWidget(m_fromCursor, 2, 0);
00185 optionsLayout->
addWidget(m_findBackwards, 0, 1);
00186 optionsLayout->
addWidget(m_selectedText, 1, 1);
00187 optionsLayout->
addWidget(m_promptOnReplace, 2, 1);
00188 topLayout->addWidget(m_optionGrp);
00189
00190
00191 m_patterns = 0L;
00192 m_placeholders = 0L;
00193
00194
00195 connect(m_selectedText, SIGNAL(toggled(
bool)),
this, SLOT(slotSelectedTextToggled(
bool)));
00196 connect(m_regExp, SIGNAL(toggled(
bool)), m_regExpItem, SLOT(setEnabled(
bool)));
00197 connect(m_backRef, SIGNAL(toggled(
bool)), m_backRefItem, SLOT(setEnabled(
bool)));
00198 connect(m_regExpItem, SIGNAL(clicked()),
this, SLOT(showPatterns()));
00199 connect(m_backRefItem, SIGNAL(clicked()),
this, SLOT(showPlaceholders()));
00200
00201 connect(m_find, SIGNAL(textChanged (
const QString & )),
this, SLOT(textSearchChanged(
const QString & )));
00202
00203
00204 setTabOrder(m_find, m_regExp);
00205 setTabOrder(m_regExp, m_regExpItem);
00206 setTabOrder(m_regExpItem, m_replace);
00207 setTabOrder(m_replace, m_backRef);
00208 setTabOrder(m_backRef, m_backRefItem);
00209 setTabOrder(m_backRefItem, m_caseSensitive);
00210 setTabOrder(m_caseSensitive, m_wholeWordsOnly);
00211 setTabOrder(m_wholeWordsOnly, m_fromCursor);
00212 setTabOrder(m_fromCursor, m_findBackwards);
00213 setTabOrder(m_findBackwards, m_selectedText);
00214 setTabOrder(m_selectedText, m_promptOnReplace);
00215
00216
00217 m_findLabel->
setBuddy(m_find);
00218 m_replaceLabel->
setBuddy(m_replace);
00219
00220
if (!forReplace)
00221 {
00222 m_promptOnReplace->hide();
00223 m_replaceGrp->hide();
00224 }
00225
00226 d->findStrings = findStrings;
00227 m_find->setFocus();
00228
enableButtonOK( !
pattern().isEmpty() );
00229
if (forReplace)
00230 {
00231
setButtonOK(
KGuiItem( i18n(
"&Replace"), QString::null,
00232 i18n(
"Start replace"),
00233 i18n(
"<qt>If you press the <b>Replace</b> button, the text you entered "
00234
"above is searched for within the document and any occurrence is "
00235
"replaced with the replacement text.</qt>")));
00236 }
00237
else
00238 {
00239
setButtonOK(
KGuiItem( i18n(
"&Find"),
"find",
00240 i18n(
"Start searching"),
00241 i18n(
"<qt>If you press the <b>Find</b> button, the text you entered "
00242
"above is searched for within the document.</qt>")));
00243 }
00244
00245
00246
QWhatsThis::add ( m_find, i18n(
00247
"Enter a pattern to search for, or select a previous pattern from "
00248
"the list.") );
00249
QWhatsThis::add ( m_regExp, i18n(
00250
"If enabled, search for a regular expression.") );
00251
QWhatsThis::add ( m_regExpItem, i18n(
00252
"Click here to edit your regular expression using a graphical editor.") );
00253
QWhatsThis::add ( m_replace, i18n(
00254
"Enter a replacement string, or select a previous one from the list.") );
00255
QWhatsThis::add( m_backRef, i18n(
00256
"<qt>If enabled, any occurrence of <code><b>\\N</b></code>, where "
00257
"<code><b>N</b></code> is a integer number, will be replaced with "
00258
"the corresponding capture (\"parenthesized substring\") from the "
00259
"pattern.<p>To include (a literal <code><b>\\N</b></code> in your "
00260
"replacement, put an extra backslash in front of it, like "
00261
"<code><b>\\\\N</b></code>.</qt>") );
00262
QWhatsThis::add ( m_backRefItem, i18n(
00263
"Click for a menu of available captures.") );
00264
QWhatsThis::add ( m_wholeWordsOnly, i18n(
00265
"Require word boundaries in both ends of a match to succeed.") );
00266
QWhatsThis::add ( m_fromCursor, i18n(
00267
"Start searching at the current cursor location rather than at the top.") );
00268
QWhatsThis::add ( m_selectedText, i18n(
00269
"Only search within the current selection.") );
00270
QWhatsThis::add ( m_caseSensitive, i18n(
00271
"Perform a case sensitive search: entering the pattern "
00272
"'Joe' will not match 'joe' or 'JOE', only 'Joe'.") );
00273
QWhatsThis::add ( m_findBackwards, i18n(
00274
"Search backwards.") );
00275
QWhatsThis::add ( m_promptOnReplace, i18n(
00276
"Ask before replacing each match found.") );
00277 }
00278
00279
void KFindDialog::textSearchChanged(
const QString & text)
00280 {
00281
enableButtonOK( !text.
isEmpty() );
00282 }
00283
00284
void KFindDialog::showEvent(
QShowEvent *e )
00285 {
00286
if ( !d->m_initialShowDone )
00287 {
00288 d->m_initialShowDone =
true;
00289
kdDebug() <<
"showEvent\n";
00290
if (!d->findStrings.isEmpty())
00291
setFindHistory(d->findStrings);
00292 d->findStrings =
QStringList();
00293
if (!d->pattern.isEmpty()) {
00294 m_find->
lineEdit()->setText( d->pattern );
00295 m_find->
lineEdit()->selectAll();
00296 d->pattern = QString::null;
00297 }
00298 }
00299 KDialogBase::showEvent(e);
00300 }
00301
00302 long KFindDialog::options()
const
00303
{
00304
long options = 0;
00305
00306
if (m_caseSensitive->
isChecked())
00307 options |= CaseSensitive;
00308
if (m_wholeWordsOnly->
isChecked())
00309 options |= WholeWordsOnly;
00310
if (m_fromCursor->
isChecked())
00311 options |= FromCursor;
00312
if (m_findBackwards->
isChecked())
00313 options |= FindBackwards;
00314
if (m_selectedText->
isChecked())
00315 options |= SelectedText;
00316
if (m_regExp->
isChecked())
00317 options |= RegularExpression;
00318
return options;
00319 }
00320
00321 QString
KFindDialog::pattern()
const
00322
{
00323
return m_find->
currentText();
00324 }
00325
00326 void KFindDialog::setPattern (
const QString &pattern)
00327 {
00328 m_find->
lineEdit()->setText( pattern );
00329 m_find->
lineEdit()->selectAll();
00330 d->pattern = pattern;
00331
kdDebug() <<
"setPattern " << pattern<<
endl;
00332 }
00333
00334 void KFindDialog::setFindHistory(
const QStringList &strings)
00335 {
00336
if (strings.count() > 0)
00337 {
00338 m_find->
setHistoryItems(strings,
true);
00339 m_find->
lineEdit()->setText( strings.first() );
00340 m_find->
lineEdit()->selectAll();
00341 }
00342
else
00343 m_find->
clearHistory();
00344 }
00345
00346 void KFindDialog::setHasSelection(
bool hasSelection)
00347 {
00348
if (hasSelection) d->m_enabled |= SelectedText;
00349
else d->m_enabled &= ~SelectedText;
00350 m_selectedText->setEnabled( hasSelection );
00351
if ( !hasSelection )
00352 {
00353 m_selectedText->
setChecked(
false );
00354 slotSelectedTextToggled( hasSelection );
00355 }
00356 }
00357
00358
void KFindDialog::slotSelectedTextToggled(
bool selec)
00359 {
00360
00361 m_fromCursor->setEnabled( !selec && (d->m_enabled & FromCursor) );
00362
if ( selec )
00363 m_fromCursor->
setChecked(
false );
00364 }
00365
00366 void KFindDialog::setHasCursor(
bool hasCursor)
00367 {
00368
if (hasCursor) d->m_enabled |= FromCursor;
00369
else d->m_enabled &= ~FromCursor;
00370 m_fromCursor->setEnabled( hasCursor );
00371 m_fromCursor->
setChecked( hasCursor && (
options() & FromCursor) );
00372 }
00373
00374 void KFindDialog::setSupportsBackwardsFind(
bool supports )
00375 {
00376
00377
if (supports) d->m_enabled |= FindBackwards;
00378
else d->m_enabled &= ~FindBackwards;
00379 m_findBackwards->setEnabled( supports );
00380 m_findBackwards->
setChecked( supports && (
options() & FindBackwards) );
00381 }
00382
00383 void KFindDialog::setSupportsCaseSensitiveFind(
bool supports )
00384 {
00385
00386
if (supports) d->m_enabled |= CaseSensitive;
00387
else d->m_enabled &= ~CaseSensitive;
00388 m_caseSensitive->setEnabled( supports );
00389 m_caseSensitive->
setChecked( supports && (
options() & CaseSensitive) );
00390 }
00391
00392 void KFindDialog::setSupportsWholeWordsFind(
bool supports )
00393 {
00394
00395
if (supports) d->m_enabled |= WholeWordsOnly;
00396
else d->m_enabled &= ~WholeWordsOnly;
00397 m_wholeWordsOnly->setEnabled( supports );
00398 m_wholeWordsOnly->
setChecked( supports && (
options() & WholeWordsOnly) );
00399 }
00400
00401 void KFindDialog::setSupportsRegularExpressionFind(
bool supports )
00402 {
00403
00404
if (supports) d->m_enabled |= RegularExpression;
00405
else d->m_enabled &= ~RegularExpression;
00406 m_regExp->setEnabled( supports );
00407 m_regExp->
setChecked( supports && (
options() & RegularExpression) );
00408 }
00409
00410 void KFindDialog::setOptions(
long options)
00411 {
00412 m_caseSensitive->
setChecked((d->m_enabled & CaseSensitive) && (options & CaseSensitive));
00413 m_wholeWordsOnly->
setChecked((d->m_enabled & WholeWordsOnly) && (options & WholeWordsOnly));
00414 m_fromCursor->
setChecked((d->m_enabled & FromCursor) && (options & FromCursor));
00415 m_findBackwards->
setChecked((d->m_enabled & FindBackwards) && (options & FindBackwards));
00416 m_selectedText->
setChecked((d->m_enabled & SelectedText) && (options & SelectedText));
00417 m_regExp->
setChecked((d->m_enabled & RegularExpression) && (options & RegularExpression));
00418 }
00419
00420
00421
00422
void KFindDialog::showPatterns()
00423 {
00424
if ( !d->m_regexpDialogQueryDone )
00425 {
00426 d->m_regexpDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>(
"KRegExpEditor/KRegExpEditor", QString::null,
this );
00427 d->m_regexpDialogQueryDone =
true;
00428 }
00429
00430
if ( d->m_regexpDialog )
00431 {
00432 KRegExpEditorInterface *iface = static_cast<KRegExpEditorInterface *>( d->m_regexpDialog->qt_cast(
"KRegExpEditorInterface" ) );
00433 assert( iface );
00434
00435 iface->setRegExp(
pattern() );
00436
if ( d->m_regexpDialog->exec() == QDialog::Accepted )
00437
setPattern( iface->regExp() );
00438 }
00439
else
00440 {
00441
typedef struct
00442
{
00443
const char *
description;
00444
const char *regExp;
00445
int cursorAdjustment;
00446 } term;
00447
static const term items[] =
00448 {
00449 {
I18N_NOOP(
"Any Character"),
".", 0 },
00450 {
I18N_NOOP(
"Start of Line"),
"^", 0 },
00451 {
I18N_NOOP(
"End of Line"),
"$", 0 },
00452 {
I18N_NOOP(
"Set of Characters"),
"[]", -1 },
00453 {
I18N_NOOP(
"Repeats, Zero or More Times"),
"*", 0 },
00454 {
I18N_NOOP(
"Repeats, One or More Times"),
"+", 0 },
00455 {
I18N_NOOP(
"Optional"),
"?", 0 },
00456 {
I18N_NOOP(
"Escape"),
"\\", 0 },
00457 {
I18N_NOOP(
"TAB"),
"\\t", 0 },
00458 {
I18N_NOOP(
"Newline"),
"\\n", 0 },
00459 {
I18N_NOOP(
"Carriage Return"),
"\\r", 0 },
00460 {
I18N_NOOP(
"White Space"),
"\\s", 0 },
00461 {
I18N_NOOP(
"Digit"),
"\\d", 0 },
00462 };
00463
int i;
00464
00465
00466
if (!m_patterns)
00467 {
00468 m_patterns =
new QPopupMenu(
this);
00469
for (i = 0; (
unsigned)i <
sizeof(items) /
sizeof(items[0]); i++)
00470 {
00471 m_patterns->
insertItem(i18n(items[i].description), i, i);
00472 }
00473 }
00474
00475
00476 i = m_patterns->
exec(m_regExpItem->mapToGlobal(m_regExpItem->rect().bottomLeft()));
00477
if (i != -1)
00478 {
00479
QLineEdit *editor = m_find->
lineEdit();
00480
00481 editor->
insert(items[i].regExp);
00482 editor->
setCursorPosition(editor->
cursorPosition() + items[i].cursorAdjustment);
00483 }
00484 }
00485 }
00486
00487
00488
00489
void KFindDialog::showPlaceholders()
00490 {
00491
00492
if (!m_placeholders)
00493 {
00494 m_placeholders =
new QPopupMenu(
this);
00495 connect( m_placeholders, SIGNAL(aboutToShow()),
this, SLOT(slotPlaceholdersAboutToShow()) );
00496 }
00497
00498
00499
int i = m_placeholders->
exec(m_backRefItem->mapToGlobal(m_backRefItem->rect().bottomLeft()));
00500
if (i != -1)
00501 {
00502
QLineEdit *editor = m_replace->
lineEdit();
00503 editor->
insert( QString(
"\\%1").arg( i ) );
00504 }
00505 }
00506
00507
void KFindDialog::slotPlaceholdersAboutToShow()
00508 {
00509 m_placeholders->
clear();
00510 m_placeholders->
insertItem( i18n(
"Complete Match"), 0 );
00511
00512
QRegExp r(
pattern() );
00513 uint n = r.
numCaptures();
00514
for ( uint i=0; i < n; i++ )
00515 m_placeholders->
insertItem( i18n(
"Captured Text (%1)").arg( i+1 ), i+1 );
00516 }
00517
00518
void KFindDialog::slotOk()
00519 {
00520
00521
if (
pattern().
isEmpty())
00522 {
00523
KMessageBox::error(
this, i18n(
"You must enter some text to search for."));
00524
return;
00525 }
00526
00527
if (m_regExp->
isChecked())
00528 {
00529
00530
QRegExp regExp(
pattern());
00531
00532
if (!regExp.
isValid())
00533 {
00534
KMessageBox::error(
this, i18n(
"Invalid regular expression."));
00535
return;
00536 }
00537 }
00538 m_find->
addToHistory(
pattern());
00539 emit
okClicked();
00540
if ( testWFlags( WShowModal ) )
00541
accept();
00542 }
00543
00544
#include "kfinddialog.moc"