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 
00036 #include <kregexpeditorinterface.h>
00037 #include <kparts/componentfactory.h>
00038 
00039 class KFindDialog::KFindDialogPrivate
00040 {
00041 public:
00042     KFindDialogPrivate() : m_regexpDialog(0),
00043         m_regexpDialogQueryDone(false), m_hasCursor(true), m_hasSelection(false),
00044         m_initialShowDone(false) {}
00045     QDialog* m_regexpDialog;
00046     bool m_regexpDialogQueryDone;
00047     bool m_hasCursor;
00048     bool m_hasSelection;
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 }
00063 
00064 KFindDialog::KFindDialog(bool modal, QWidget *parent, const char *name, long options, const QStringList &findStrings, bool hasSelection) :
00065     KDialogBase(parent, name, modal, i18n("Find Text"), Ok | Cancel, Ok),
00066     m_findExtension (0),
00067     m_replaceExtension (0)
00068 {
00069     d = new KFindDialogPrivate;
00070     init(false, findStrings, hasSelection);
00071     setOptions(options);
00072 }
00073 
00074 KFindDialog::KFindDialog(QWidget *parent, const char *name, bool ) :
00075     KDialogBase(parent, name, true, i18n("Replace Text"), Ok | Cancel, Ok),
00076     m_findExtension (0),
00077     m_replaceExtension (0)
00078 {
00079     d = new KFindDialogPrivate;
00080 }
00081 
00082 KFindDialog::~KFindDialog()
00083 {
00084     delete d;
00085 }
00086 
00087 QWidget *KFindDialog::findExtension()
00088 {
00089     if (!m_findExtension)
00090     {
00091       m_findExtension = new QWidget(m_findGrp);
00092       m_findLayout->addMultiCellWidget(m_findExtension, 3, 3, 0, 1);
00093     }
00094 
00095     return m_findExtension;
00096 }
00097 
00098 QStringList KFindDialog::findHistory() const
00099 {
00100     return m_find->historyItems();
00101 }
00102 
00103 void KFindDialog::init(bool forReplace, const QStringList &findStrings, bool hasSelection)
00104 {
00105     QVBoxLayout *topLayout;
00106     QGridLayout *optionsLayout;
00107 
00108     
00109     QWidget *page = new QWidget(this);
00110     setMainWidget(page);
00111 
00112     topLayout = new QVBoxLayout(page);
00113     topLayout->setSpacing( KDialog::spacingHint() );
00114     topLayout->setMargin( 0 );
00115 
00116     m_findGrp = new QGroupBox(0, Qt::Vertical, i18n("Find"), page);
00117     m_findGrp->layout()->setSpacing( KDialog::spacingHint() );
00118    
00119     m_findLayout = new QGridLayout(m_findGrp->layout());
00120     m_findLayout->setSpacing( KDialog::spacingHint() );
00121    
00122 
00123     m_findLabel = new QLabel(i18n("&Text to find:"), m_findGrp);
00124     m_find = new KHistoryCombo(true, m_findGrp);
00125     m_find->setMaxCount(10);
00126     m_find->setDuplicatesEnabled(false);
00127     m_regExp = new QCheckBox(i18n("Regular e&xpression"), m_findGrp);
00128     m_regExpItem = new QPushButton(i18n("&Edit..."), m_findGrp);
00129     m_regExpItem->setEnabled(false);
00130 
00131     m_findLayout->addWidget(m_findLabel, 0, 0);
00132     m_findLayout->addMultiCellWidget(m_find, 1, 1, 0, 1);
00133     m_findLayout->addWidget(m_regExp, 2, 0);
00134     m_findLayout->addWidget(m_regExpItem, 2, 1);
00135     topLayout->addWidget(m_findGrp);
00136 
00137     m_replaceGrp = new QGroupBox(0, Qt::Vertical, i18n("Replace With"), page);
00138     m_replaceGrp->layout()->setSpacing( KDialog::spacingHint() );
00139   
00140     m_replaceLayout = new QGridLayout(m_replaceGrp->layout());
00141     m_replaceLayout->setSpacing( KDialog::spacingHint() );
00142 
00143 
00144     m_replaceLabel = new QLabel(i18n("Replace&ment text:"), m_replaceGrp);
00145     m_replace = new KHistoryCombo(true, m_replaceGrp);
00146     m_replace->setMaxCount(10);
00147     m_replace->setDuplicatesEnabled(false);
00148     m_backRef = new QCheckBox(i18n("Use p&laceholders"), m_replaceGrp);
00149     m_backRefItem = new QPushButton(i18n("Insert Place&holder"), m_replaceGrp);
00150     m_backRefItem->setEnabled(false);
00151 
00152     m_replaceLayout->addWidget(m_replaceLabel, 0, 0);
00153     m_replaceLayout->addMultiCellWidget(m_replace, 1, 1, 0, 1);
00154     m_replaceLayout->addWidget(m_backRef, 2, 0);
00155     m_replaceLayout->addWidget(m_backRefItem, 2, 1);
00156     topLayout->addWidget(m_replaceGrp);
00157 
00158     m_optionGrp = new QGroupBox(0, Qt::Vertical, i18n("Options"), page);
00159     m_optionGrp->layout()->setSpacing(KDialog::spacingHint());
00160   
00161     optionsLayout = new QGridLayout(m_optionGrp->layout());
00162     optionsLayout->setSpacing( KDialog::spacingHint() );
00163    
00164 
00165     m_caseSensitive = new QCheckBox(i18n("C&ase sensitive"), m_optionGrp);
00166     m_wholeWordsOnly = new QCheckBox(i18n("&Whole words only"), m_optionGrp);
00167     m_fromCursor = new QCheckBox(i18n("From c&ursor"), m_optionGrp);
00168     m_findBackwards = new QCheckBox(i18n("Find &backwards"), m_optionGrp);
00169     m_selectedText = new QCheckBox(i18n("&Selected text"), m_optionGrp);
00170     setHasSelection( hasSelection );
00171     
00172     
00173     m_selectedText->setChecked( hasSelection );
00174     slotSelectedTextToggled( hasSelection );
00175 
00176     m_promptOnReplace = new QCheckBox(i18n("&Prompt on replace"), m_optionGrp);
00177     m_promptOnReplace->setChecked( true );
00178 
00179     optionsLayout->addWidget(m_caseSensitive, 0, 0);
00180     optionsLayout->addWidget(m_wholeWordsOnly, 1, 0);
00181     optionsLayout->addWidget(m_fromCursor, 2, 0);
00182     optionsLayout->addWidget(m_findBackwards, 0, 1);
00183     optionsLayout->addWidget(m_selectedText, 1, 1);
00184     optionsLayout->addWidget(m_promptOnReplace, 2, 1);
00185     topLayout->addWidget(m_optionGrp);
00186 
00187     
00188     m_patterns = 0L;
00189     m_placeholders = 0L;
00190 
00191     
00192     connect(m_selectedText, SIGNAL(toggled(bool)), this, SLOT(slotSelectedTextToggled(bool)));
00193     connect(m_regExp, SIGNAL(toggled(bool)), m_regExpItem, SLOT(setEnabled(bool)));
00194     connect(m_backRef, SIGNAL(toggled(bool)), m_backRefItem, SLOT(setEnabled(bool)));
00195     connect(m_regExpItem, SIGNAL(clicked()), this, SLOT(showPatterns()));
00196     connect(m_backRefItem, SIGNAL(clicked()), this, SLOT(showPlaceholders()));
00197 
00198     connect(m_find, SIGNAL(textChanged ( const QString & )),this, SLOT(textSearchChanged( const QString & )));
00199 
00200     
00201     setTabOrder(m_find, m_regExp);
00202     setTabOrder(m_regExp, m_regExpItem);
00203     setTabOrder(m_regExpItem, m_replace);
00204     setTabOrder(m_replace, m_backRef);
00205     setTabOrder(m_backRef, m_backRefItem);
00206     setTabOrder(m_backRefItem, m_caseSensitive);
00207     setTabOrder(m_caseSensitive, m_wholeWordsOnly);
00208     setTabOrder(m_wholeWordsOnly, m_fromCursor);
00209     setTabOrder(m_fromCursor, m_findBackwards);
00210     setTabOrder(m_findBackwards, m_selectedText);
00211     setTabOrder(m_selectedText, m_promptOnReplace);
00212 
00213     
00214     m_findLabel->setBuddy(m_find);
00215     m_replaceLabel->setBuddy(m_replace);
00216 
00217     if (!forReplace)
00218     {
00219         m_promptOnReplace->hide();
00220         m_replaceGrp->hide();
00221     }
00222 
00223     d->findStrings = findStrings;
00224     m_find->setFocus();
00225     enableButtonOK( !pattern().isEmpty() );
00226     if (forReplace)
00227     {
00228        setButtonOKText(i18n("&Replace"),
00229                     i18n("Start replace"),
00230                     i18n("<qt>If you press the <b>Replace</b> button, the text you entered "
00231                          "above is searched for within the document and any occurrence is "
00232                          "replaced with the replacement text.</qt>"));
00233     }
00234     else
00235     {
00236        setButtonOKText(i18n("&Find"),
00237                     i18n("Start searching"),
00238                     i18n("<qt>If you press the <b>Find</b> button, the text you entered "
00239                          "above is searched for within the document.</qt>"));
00240     }
00241 }
00242 
00243 void KFindDialog::textSearchChanged( const QString & text)
00244 {
00245     enableButtonOK( !text.isEmpty() );
00246 }
00247 
00248 void KFindDialog::showEvent( QShowEvent *e )
00249 {
00250     if ( !d->m_initialShowDone )
00251     {
00252         d->m_initialShowDone = true; 
00253         kdDebug() << "showEvent\n";
00254         if (!d->findStrings.isEmpty())
00255             setFindHistory(d->findStrings);
00256         d->findStrings = QStringList();
00257         if (!d->pattern.isEmpty()) {
00258             m_find->lineEdit()->setText( d->pattern );
00259             m_find->lineEdit()->selectAll();
00260             d->pattern = QString::null;
00261         }
00262     }
00263     KDialogBase::showEvent(e);
00264 }
00265 
00266 long KFindDialog::options() const
00267 {
00268     long options = 0;
00269 
00270     if (m_caseSensitive->isChecked())
00271         options |= CaseSensitive;
00272     if (m_wholeWordsOnly->isChecked())
00273         options |= WholeWordsOnly;
00274     if (m_fromCursor->isChecked())
00275         options |= FromCursor;
00276     if (m_findBackwards->isChecked())
00277         options |= FindBackwards;
00278     if (m_selectedText->isChecked())
00279         options |= SelectedText;
00280     if (m_regExp->isChecked())
00281         options |= RegularExpression;
00282     return options;
00283 }
00284 
00285 QString KFindDialog::pattern() const
00286 {
00287     return m_find->currentText();
00288 }
00289 
00290 void KFindDialog::setPattern (const QString &pattern)
00291 {
00292     m_find->lineEdit()->setText( pattern );
00293     m_find->lineEdit()->selectAll();
00294     d->pattern = pattern;
00295     kdDebug() << "setPattern " << pattern<<endl;
00296 }
00297 
00298 void KFindDialog::setFindHistory(const QStringList &strings)
00299 {
00300     if (strings.count() > 0)
00301     {
00302         m_find->setHistoryItems(strings, true);
00303         m_find->lineEdit()->setText( strings.first() );
00304         m_find->lineEdit()->selectAll();
00305     }
00306     else
00307         m_find->clearHistory();
00308 }
00309 
00310 void KFindDialog::setHasSelection(bool hasSelection)
00311 {
00312     d->m_hasSelection = hasSelection;
00313     m_selectedText->setEnabled( hasSelection );
00314     if ( !hasSelection )
00315     {
00316         m_selectedText->setChecked( false );
00317         slotSelectedTextToggled( hasSelection );
00318     }
00319 }
00320 
00321 void KFindDialog::slotSelectedTextToggled(bool selec)
00322 {
00323     
00324     m_fromCursor->setEnabled( !selec && d->m_hasCursor );
00325     if ( selec ) 
00326         m_fromCursor->setChecked( false );
00327 }
00328 
00329 void KFindDialog::setHasCursor(bool hasCursor)
00330 {
00331     d->m_hasCursor = hasCursor;
00332     m_fromCursor->setEnabled( hasCursor );
00333     m_fromCursor->setChecked( hasCursor && (options() & FromCursor) );
00334 }
00335 
00336 void KFindDialog::setOptions(long options)
00337 {
00338     m_caseSensitive->setChecked(options & CaseSensitive);
00339     m_wholeWordsOnly->setChecked(options & WholeWordsOnly);
00340     m_fromCursor->setChecked(d->m_hasCursor && (options & FromCursor));
00341     m_findBackwards->setChecked(options & FindBackwards);
00342     m_selectedText->setChecked(d->m_hasSelection && (options & SelectedText));
00343     m_regExp->setChecked(options & RegularExpression);
00344 }
00345 
00346 
00347 
00348 void KFindDialog::showPatterns()
00349 {
00350     if ( !d->m_regexpDialogQueryDone )
00351     {
00352         d->m_regexpDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor", QString::null, this );
00353         d->m_regexpDialogQueryDone = true;
00354     }
00355 
00356     if ( d->m_regexpDialog )
00357     {
00358         KRegExpEditorInterface *iface = static_cast<KRegExpEditorInterface *>( d->m_regexpDialog->qt_cast( "KRegExpEditorInterface" ) );
00359         assert( iface );
00360 
00361         iface->setRegExp( pattern() );
00362         if ( d->m_regexpDialog->exec() == QDialog::Accepted )
00363             setPattern( iface->regExp() );
00364     }
00365     else 
00366     {
00367         typedef struct
00368         {
00369             const char *description;
00370             const char *regExp;
00371             int cursorAdjustment;
00372         } term;
00373         static const term items[] =
00374             {
00375                 { I18N_NOOP("Any Character"),                 ".",        0 },
00376                 { I18N_NOOP("Start of Line"),                 "^",        0 },
00377                 { I18N_NOOP("End of Line"),                   "$",        0 },
00378                 { I18N_NOOP("Set of Characters"),             "[]",       -1 },
00379                 { I18N_NOOP("Repeats, Zero or More Times"),   "*",        0 },
00380                 { I18N_NOOP("Repeats, One or More Times"),    "+",        0 },
00381                 { I18N_NOOP("Optional"),                      "?",        0 },
00382                 { I18N_NOOP("Escape"),                        "\\",       0 },
00383                 { I18N_NOOP("TAB"),                           "\\t",      0 },
00384                 { I18N_NOOP("Newline"),                       "\\n",      0 },
00385                 { I18N_NOOP("Carriage Return"),               "\\r",      0 },
00386                 { I18N_NOOP("White Space"),                   "\\s",      0 },
00387                 { I18N_NOOP("Digit"),                         "\\d",      0 },
00388             };
00389         int i;
00390 
00391         
00392         if (!m_patterns)
00393         {
00394             m_patterns = new QPopupMenu(this);
00395             for (i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++)
00396             {
00397                 m_patterns->insertItem(i18n(items[i].description), i, i);
00398             }
00399         }
00400 
00401         
00402         i = m_patterns->exec(m_regExpItem->mapToGlobal(m_regExpItem->rect().bottomLeft()));
00403         if (i != -1)
00404         {
00405             QLineEdit *editor = m_find->lineEdit();
00406 
00407             editor->insert(items[i].regExp);
00408             editor->setCursorPosition(editor->cursorPosition() + items[i].cursorAdjustment);
00409         }
00410     }
00411 }
00412 
00413 
00414 
00415 void KFindDialog::showPlaceholders()
00416 {
00417     typedef struct
00418     {
00419         const char *description;
00420         const char *backRef;
00421     } term;
00422     static const term items[] =
00423     {
00424         { I18N_NOOP("Complete text found"),             "\\0" },
00425     };
00426     int i;
00427 
00428     
00429     if (!m_placeholders)
00430     {
00431         m_placeholders = new QPopupMenu(this);
00432         for (i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++)
00433         {
00434             m_placeholders->insertItem(i18n(items[i].description), i, i);
00435         }
00436     }
00437 
00438     
00439     i = m_placeholders->exec(m_backRefItem->mapToGlobal(m_backRefItem->rect().bottomLeft()));
00440     if (i != -1)
00441     {
00442         QLineEdit *editor = m_replace->lineEdit();
00443 
00444         editor->insert(items[i].backRef);
00445     }
00446 }
00447 
00448 void KFindDialog::slotOk()
00449 {
00450     
00451     if (pattern().isEmpty())
00452     {
00453         KMessageBox::error(this, i18n("You must enter some text to search for."));
00454         return;
00455     }
00456 
00457     if (m_regExp->isChecked())
00458     {
00459         
00460         QRegExp regExp(pattern());
00461 
00462         if (!regExp.isValid())
00463         {
00464             KMessageBox::error(this, i18n("Invalid regular expression."));
00465             return;
00466         }
00467     }
00468     m_find->addToHistory(pattern());
00469     emit okClicked();
00470     if ( testWFlags( WShowModal ) )
00471         accept();
00472 }
00473 
00474 #include "kfinddialog.moc"