00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "kfind.h"
00022
#include "kfinddialog.h"
00023
#include <kapplication.h>
00024
#include <klocale.h>
00025
#include <kmessagebox.h>
00026
#include <qlabel.h>
00027
#include <qregexp.h>
00028
#include <qstylesheet.h>
00029
#include <qguardedptr.h>
00030
#include <kdebug.h>
00031
00032
00033
00034
#define INDEX_NOMATCH -1
00035
00036
class KFindNextDialog :
public KDialogBase
00037 {
00038
public:
00039 KFindNextDialog(
const QString &pattern,
QWidget *parent);
00040 };
00041
00042
00043 KFindNextDialog::KFindNextDialog(
const QString &pattern,
QWidget *parent) :
00044
KDialogBase(parent, 0, false,
00045 i18n(
"Find Next"),
00046 User1 | Close,
00047 User1,
00048 false,
00049 i18n(
"&Find"))
00050 {
00051
setMainWidget(
new QLabel( i18n(
"<qt>Find next occurrence of '<b>%1</b>'?</qt>").arg(pattern),
this ) );
00052 }
00053
00055
00056
struct KFind::Private {
00057 Private() {
00058 findDialog = 0;
00059 }
00060
QGuardedPtr<QWidget> findDialog;
00061 };
00063
00064 KFind::KFind(
const QString &pattern,
long options,
QWidget *parent )
00065 :
QObject( parent )
00066 {
00067 d =
new KFind::Private;
00068 m_options = options;
00069 init( pattern );
00070 }
00071
00072 KFind::KFind(
const QString &pattern,
long options,
QWidget *parent,
QWidget *findDialog )
00073 :
QObject( parent )
00074 {
00075 d =
new KFind::Private;
00076 d->findDialog = findDialog;
00077 m_options = options;
00078 init( pattern );
00079 }
00080
00081
void KFind::init(
const QString& pattern )
00082 {
00083 m_matches = 0;
00084 m_pattern = pattern;
00085 m_dialog = 0;
00086 m_dialogClosed =
false;
00087 m_index = INDEX_NOMATCH;
00088 m_lastResult = NoMatch;
00089
if (m_options & KFindDialog::RegularExpression)
00090 m_regExp =
new QRegExp(pattern, m_options & KFindDialog::CaseSensitive);
00091
else {
00092 m_regExp = 0;
00093 }
00094 }
00095
00096 KFind::~KFind()
00097 {
00098
delete m_dialog;
00099
delete d;
00100 }
00101
00102 bool KFind::needData()
const
00103
{
00104
00105
if (m_options & KFindDialog::FindBackwards)
00106
00107
00108
return ( m_index < 0 && m_lastResult != Match );
00109
else
00110
00111
00112
return m_index == INDEX_NOMATCH;
00113 }
00114
00115 void KFind::setData(
const QString& data,
int startPos )
00116 {
00117 m_text = data;
00118
if ( startPos != -1 )
00119 m_index = startPos;
00120
else if (m_options & KFindDialog::FindBackwards)
00121 m_index = QMAX( (
int)m_text.
length() - 1, 0 );
00122
else
00123 m_index = 0;
00124
#ifdef DEBUG_FIND
00125
kdDebug() <<
"setData: '" << m_text <<
"' m_index=" << m_index <<
endl;
00126
#endif
00127
Q_ASSERT( m_index != INDEX_NOMATCH );
00128 m_lastResult = NoMatch;
00129 }
00130
00131 KDialogBase*
KFind::findNextDialog(
bool create )
00132 {
00133
if ( !m_dialog && create )
00134 {
00135 m_dialog =
new KFindNextDialog( m_pattern, parentWidget() );
00136
connect( m_dialog, SIGNAL( user1Clicked() ),
this, SLOT( slotFindNext() ) );
00137
connect( m_dialog, SIGNAL( finished() ),
this, SLOT( slotDialogClosed() ) );
00138 }
00139
return m_dialog;
00140 }
00141
00142 KFind::Result
KFind::find()
00143 {
00144 Q_ASSERT( m_index != INDEX_NOMATCH );
00145
if ( m_lastResult == Match )
00146 {
00147
00148
if (m_options & KFindDialog::FindBackwards) {
00149 m_index--;
00150
if ( m_index == -1 )
00151 {
00152 m_lastResult = NoMatch;
00153
return NoMatch;
00154 }
00155 }
else
00156 m_index++;
00157 }
00158
00159
#ifdef DEBUG_FIND
00160
kdDebug() <<
k_funcinfo <<
"m_index=" << m_index <<
endl;
00161
#endif
00162
do
00163 {
00164
00165
if ( m_options & KFindDialog::RegularExpression )
00166 m_index =
KFind::find(m_text, *m_regExp, m_index, m_options, &m_matchedLength);
00167
else
00168 m_index =
KFind::find(m_text, m_pattern, m_index, m_options, &m_matchedLength);
00169
if ( m_index != -1 )
00170 {
00171
00172
if (
validateMatch( m_text, m_index, m_matchedLength ) )
00173 {
00174 m_matches++;
00175
00176
00177 emit
highlight(m_text, m_index, m_matchedLength);
00178
00179
if ( !m_dialogClosed )
00180
findNextDialog(
true)->
show();
00181
00182
#ifdef DEBUG_FIND
00183
kdDebug() <<
k_funcinfo <<
"Match. Next m_index=" << m_index <<
endl;
00184
#endif
00185
m_lastResult = Match;
00186
return Match;
00187 }
00188
else
00189
if (m_options & KFindDialog::FindBackwards)
00190 m_index--;
00191
else
00192 m_index++;
00193 }
else
00194 m_index = INDEX_NOMATCH;
00195 }
00196
while (m_index != INDEX_NOMATCH);
00197
00198
#ifdef DEBUG_FIND
00199
kdDebug() <<
k_funcinfo <<
"NoMatch. m_index=" << m_index <<
endl;
00200
#endif
00201
m_lastResult = NoMatch;
00202
return NoMatch;
00203 }
00204
00205
00206 int KFind::find(
const QString &text,
const QString &pattern,
int index,
long options,
int *matchedLength)
00207 {
00208
00209
if (options & KFindDialog::RegularExpression)
00210 {
00211
QRegExp regExp(pattern, options & KFindDialog::CaseSensitive);
00212
00213
return find(text, regExp, index, options, matchedLength);
00214 }
00215
00216
bool caseSensitive = (options & KFindDialog::CaseSensitive);
00217
00218
if (options & KFindDialog::WholeWordsOnly)
00219 {
00220
if (options & KFindDialog::FindBackwards)
00221 {
00222
00223
while (index >= 0)
00224 {
00225
00226 index = text.
findRev(pattern, index, caseSensitive);
00227
if (index == -1)
00228
break;
00229
00230
00231 *matchedLength = pattern.
length();
00232
if (isWholeWords(text, index, *matchedLength))
00233
break;
00234 index--;
00235 }
00236 }
00237
else
00238 {
00239
00240
while (index < (
int)text.
length())
00241 {
00242
00243 index = text.
find(pattern, index, caseSensitive);
00244
if (index == -1)
00245
break;
00246
00247
00248 *matchedLength = pattern.
length();
00249
if (isWholeWords(text, index, *matchedLength))
00250
break;
00251 index++;
00252 }
00253
if (index >= (
int)text.
length())
00254 index = -1;
00255 }
00256 }
00257
else
00258 {
00259
00260
if (options & KFindDialog::FindBackwards)
00261 {
00262 index = text.
findRev(pattern, index, caseSensitive);
00263 }
00264
else
00265 {
00266 index = text.
find(pattern, index, caseSensitive);
00267 }
00268
if (index != -1)
00269 {
00270 *matchedLength = pattern.
length();
00271 }
00272 }
00273
return index;
00274 }
00275
00276
00277
int KFind::find(
const QString &text,
const QRegExp &pattern,
int index,
long options,
int *matchedLength)
00278 {
00279
if (options & KFindDialog::WholeWordsOnly)
00280 {
00281
if (options & KFindDialog::FindBackwards)
00282 {
00283
00284
while (index >= 0)
00285 {
00286
00287 index = text.
findRev(pattern, index);
00288
if (index == -1)
00289
break;
00290
00291
00292
00293 pattern.
search( text.
mid(index) );
00294 *matchedLength = pattern.
matchedLength();
00295
if (isWholeWords(text, index, *matchedLength))
00296
break;
00297 index--;
00298 }
00299 }
00300
else
00301 {
00302
00303
while (index < (
int)text.
length())
00304 {
00305
00306 index = text.
find(pattern, index);
00307
if (index == -1)
00308
break;
00309
00310
00311
00312 pattern.
search( text.
mid(index) );
00313 *matchedLength = pattern.
matchedLength();
00314
if (isWholeWords(text, index, *matchedLength))
00315
break;
00316 index++;
00317 }
00318
if (index >= (
int)text.
length())
00319 index = -1;
00320 }
00321 }
00322
else
00323 {
00324
00325
if (options & KFindDialog::FindBackwards)
00326 {
00327 index = text.
findRev(pattern, index);
00328 }
00329
else
00330 {
00331 index = text.
find(pattern, index);
00332 }
00333
if (index != -1)
00334 {
00335
00336 pattern.
search( text.
mid(index) );
00337 *matchedLength = pattern.
matchedLength();
00338 }
00339 }
00340
return index;
00341 }
00342
00343
bool KFind::isInWord(
QChar ch)
00344 {
00345
return ch.
isLetter() || ch.
isDigit() || ch ==
'_';
00346 }
00347
00348
bool KFind::isWholeWords(
const QString &text,
int starts,
int matchedLength)
00349 {
00350
if ((starts == 0) || (!isInWord(text[starts - 1])))
00351 {
00352
int ends = starts + matchedLength;
00353
00354
if ((ends == (
int)text.
length()) || (!isInWord(text[ends])))
00355
return true;
00356 }
00357
return false;
00358 }
00359
00360
void KFind::slotFindNext()
00361 {
00362 emit findNext();
00363 }
00364
00365
void KFind::slotDialogClosed()
00366 {
00367 emit
dialogClosed();
00368 m_dialogClosed =
true;
00369 }
00370
00371 void KFind::displayFinalDialog()
const
00372
{
00373
QString message;
00374
if (
numMatches() )
00375 message = i18n(
"1 match found.",
"%n matches found.",
numMatches() );
00376
else
00377 message = i18n(
"<qt>No matches found for '<b>%1</b>'.</qt>").
arg(QStyleSheet::escape(m_pattern));
00378
KMessageBox::information(dialogsParent(), message);
00379 }
00380
00381 bool KFind::shouldRestart(
bool forceAsking,
bool showNumMatches )
const
00382
{
00383
00384
00385
00386
if ( !forceAsking && (m_options & KFindDialog::FromCursor) == 0 )
00387 {
00388
displayFinalDialog();
00389
return false;
00390 }
00391
QString message;
00392
if ( showNumMatches )
00393 {
00394
if (
numMatches() )
00395 message = i18n(
"1 match found.",
"%n matches found.",
numMatches() );
00396
else
00397 message = i18n(
"No matches found for '<b>%1</b>'.").
arg(QStyleSheet::escape(m_pattern));
00398 }
00399
else
00400 {
00401
if ( m_options & KFindDialog::FindBackwards )
00402 message = i18n(
"Beginning of document reached." );
00403
else
00404 message = i18n(
"End of document reached." );
00405 }
00406
00407 message +=
"\n";
00408
00409 message +=
00410 ( m_options & KFindDialog::FindBackwards ) ?
00411 i18n(
"Do you want to restart search from the end?")
00412 : i18n(
"Do you want to restart search at the beginning?");
00413
00414
int ret =
KMessageBox::questionYesNo( dialogsParent(),
QString(
"<qt>")+message+
QString(
"</qt>") );
00415
bool yes = ( ret == KMessageBox::Yes );
00416
if ( yes )
00417 const_cast<KFind*>(
this)->m_options &= ~
KFindDialog::FromCursor;
00418
return yes;
00419 }
00420
00421 void KFind::setOptions(
long options )
00422 {
00423 m_options = options;
00424
if (m_options & KFindDialog::RegularExpression)
00425 m_regExp =
new QRegExp(m_pattern, m_options & KFindDialog::CaseSensitive);
00426
else {
00427
delete m_regExp;
00428 m_regExp = 0;
00429 }
00430 }
00431
00432 void KFind::closeFindNextDialog()
00433 {
00434
delete m_dialog;
00435 m_dialog = 0L;
00436 m_dialogClosed =
true;
00437 }
00438
00439 int KFind::index()
const
00440
{
00441
return m_index;
00442 }
00443
00444 void KFind::setPattern(
const QString& pattern )
00445 {
00446 m_pattern = pattern;
00447
setOptions(
options() );
00448 }
00449
00450
QWidget* KFind::dialogsParent()
const
00451
{
00452
00453
00454
00455
return d->findDialog ? (
QWidget*)d->findDialog : ( m_dialog ? m_dialog : parentWidget() );
00456 }
00457
00458
#include "kfind.moc"