kutils Library API Documentation

kfinddialog.cpp

00001 /*
00002     Copyright (C) 2001, S.R.Haque <srhaque@iee.org>.
00003     Copyright (C) 2002, David Faure <david@mandrakesoft.com>
00004     This file is part of the KDE project
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., 59 Temple Place - Suite 330,
00018     Boston, MA 02111-1307, USA.
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     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 /*forReplace*/) :
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     // Create common parts of dialog.
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    // m_findGrp->layout()->setMargin( KDialog::marginHint() );
00122     m_findLayout = new QGridLayout(m_findGrp->layout());
00123     m_findLayout->setSpacing( KDialog::spacingHint() );
00124    // m_findLayout->setMargin( KDialog::marginHint() );
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   //  m_replaceGrp->layout()->setMargin( KDialog::marginHint() );
00143     m_replaceLayout = new QGridLayout(m_replaceGrp->layout());
00144     m_replaceLayout->setSpacing( KDialog::spacingHint() );
00145 //    m_replaceLayout->setMargin( KDialog::marginHint() );
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   //  m_optionGrp->layout()->setMargin(KDialog::marginHint());
00164     optionsLayout = new QGridLayout(m_optionGrp->layout());
00165     optionsLayout->setSpacing( KDialog::spacingHint() );
00166    // optionsLayout->setMargin( KDialog::marginHint() );
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     // If we have a selection, we make 'find in selection' default
00175     // and if we don't, then the option has to be unchecked, obviously.
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     // We delay creation of these until needed.
00191     m_patterns = 0L;
00192     m_placeholders = 0L;
00193 
00194     // signals and slots connections
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     // tab order
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     // buddies
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 void KFindDialog::textSearchChanged( const QString & text)
00247 {
00248     enableButtonOK( !text.isEmpty() );
00249 }
00250 
00251 void KFindDialog::showEvent( QShowEvent *e )
00252 {
00253     if ( !d->m_initialShowDone )
00254     {
00255         d->m_initialShowDone = true; // only once
00256         kdDebug() << "showEvent\n";
00257         if (!d->findStrings.isEmpty())
00258             setFindHistory(d->findStrings);
00259         d->findStrings = QStringList();
00260         if (!d->pattern.isEmpty()) {
00261             m_find->lineEdit()->setText( d->pattern );
00262             m_find->lineEdit()->selectAll();
00263             d->pattern = QString::null;
00264         }
00265     }
00266     KDialogBase::showEvent(e);
00267 }
00268 
00269 long KFindDialog::options() const
00270 {
00271     long options = 0;
00272 
00273     if (m_caseSensitive->isChecked())
00274         options |= CaseSensitive;
00275     if (m_wholeWordsOnly->isChecked())
00276         options |= WholeWordsOnly;
00277     if (m_fromCursor->isChecked())
00278         options |= FromCursor;
00279     if (m_findBackwards->isChecked())
00280         options |= FindBackwards;
00281     if (m_selectedText->isChecked())
00282         options |= SelectedText;
00283     if (m_regExp->isChecked())
00284         options |= RegularExpression;
00285     return options;
00286 }
00287 
00288 QString KFindDialog::pattern() const
00289 {
00290     return m_find->currentText();
00291 }
00292 
00293 void KFindDialog::setPattern (const QString &pattern)
00294 {
00295     m_find->lineEdit()->setText( pattern );
00296     m_find->lineEdit()->selectAll();
00297     d->pattern = pattern;
00298     kdDebug() << "setPattern " << pattern<<endl;
00299 }
00300 
00301 void KFindDialog::setFindHistory(const QStringList &strings)
00302 {
00303     if (strings.count() > 0)
00304     {
00305         m_find->setHistoryItems(strings, true);
00306         m_find->lineEdit()->setText( strings.first() );
00307         m_find->lineEdit()->selectAll();
00308     }
00309     else
00310         m_find->clearHistory();
00311 }
00312 
00313 void KFindDialog::setHasSelection(bool hasSelection)
00314 {
00315     d->m_hasSelection = hasSelection;
00316     m_selectedText->setEnabled( hasSelection );
00317     if ( !hasSelection )
00318     {
00319         m_selectedText->setChecked( false );
00320         slotSelectedTextToggled( hasSelection );
00321     }
00322 }
00323 
00324 void KFindDialog::slotSelectedTextToggled(bool selec)
00325 {
00326     // From cursor doesn't make sense if we have a selection
00327     m_fromCursor->setEnabled( !selec && d->m_hasCursor );
00328     if ( selec ) // uncheck if disabled
00329         m_fromCursor->setChecked( false );
00330 }
00331 
00332 void KFindDialog::setHasCursor(bool hasCursor)
00333 {
00334     d->m_hasCursor = hasCursor;
00335     m_fromCursor->setEnabled( hasCursor );
00336     m_fromCursor->setChecked( hasCursor && (options() & FromCursor) );
00337 }
00338 
00339 void KFindDialog::setOptions(long options)
00340 {
00341     m_caseSensitive->setChecked(options & CaseSensitive);
00342     m_wholeWordsOnly->setChecked(options & WholeWordsOnly);
00343     m_fromCursor->setChecked(d->m_hasCursor && (options & FromCursor));
00344     m_findBackwards->setChecked(options & FindBackwards);
00345     m_selectedText->setChecked(d->m_hasSelection && (options & SelectedText));
00346     m_regExp->setChecked(options & RegularExpression);
00347 }
00348 
00349 // Create a popup menu with a list of regular expression terms, to help the user
00350 // compose a regular expression search pattern.
00351 void KFindDialog::showPatterns()
00352 {
00353     if ( !d->m_regexpDialogQueryDone )
00354     {
00355         d->m_regexpDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor", QString::null, this );
00356         d->m_regexpDialogQueryDone = true;
00357     }
00358 
00359     if ( d->m_regexpDialog )
00360     {
00361         KRegExpEditorInterface *iface = static_cast<KRegExpEditorInterface *>( d->m_regexpDialog->qt_cast( "KRegExpEditorInterface" ) );
00362         assert( iface );
00363 
00364         iface->setRegExp( pattern() );
00365         if ( d->m_regexpDialog->exec() == QDialog::Accepted )
00366             setPattern( iface->regExp() );
00367     }
00368     else // No complete regexp-editor available, bring up the old popupmenu
00369     {
00370         typedef struct
00371         {
00372             const char *description;
00373             const char *regExp;
00374             int cursorAdjustment;
00375         } term;
00376         static const term items[] =
00377             {
00378                 { I18N_NOOP("Any Character"),                 ".",        0 },
00379                 { I18N_NOOP("Start of Line"),                 "^",        0 },
00380                 { I18N_NOOP("End of Line"),                   "$",        0 },
00381                 { I18N_NOOP("Set of Characters"),             "[]",       -1 },
00382                 { I18N_NOOP("Repeats, Zero or More Times"),   "*",        0 },
00383                 { I18N_NOOP("Repeats, One or More Times"),    "+",        0 },
00384                 { I18N_NOOP("Optional"),                      "?",        0 },
00385                 { I18N_NOOP("Escape"),                        "\\",       0 },
00386                 { I18N_NOOP("TAB"),                           "\\t",      0 },
00387                 { I18N_NOOP("Newline"),                       "\\n",      0 },
00388                 { I18N_NOOP("Carriage Return"),               "\\r",      0 },
00389                 { I18N_NOOP("White Space"),                   "\\s",      0 },
00390                 { I18N_NOOP("Digit"),                         "\\d",      0 },
00391             };
00392         int i;
00393 
00394         // Populate the popup menu.
00395         if (!m_patterns)
00396         {
00397             m_patterns = new QPopupMenu(this);
00398             for (i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++)
00399             {
00400                 m_patterns->insertItem(i18n(items[i].description), i, i);
00401             }
00402         }
00403 
00404         // Insert the selection into the edit control.
00405         i = m_patterns->exec(m_regExpItem->mapToGlobal(m_regExpItem->rect().bottomLeft()));
00406         if (i != -1)
00407         {
00408             QLineEdit *editor = m_find->lineEdit();
00409 
00410             editor->insert(items[i].regExp);
00411             editor->setCursorPosition(editor->cursorPosition() + items[i].cursorAdjustment);
00412         }
00413     }
00414 }
00415 
00416 // Create a popup menu with a list of backreference terms, to help the user
00417 // compose a regular expression replacement pattern.
00418 void KFindDialog::showPlaceholders()
00419 {
00420     typedef struct
00421     {
00422         const char *description;
00423         const char *backRef;
00424     } term;
00425     static const term items[] =
00426     {
00427         { I18N_NOOP("Complete text found"),             "\\0" },
00428     };
00429     int i;
00430 
00431     // Populate the popup menu.
00432     if (!m_placeholders)
00433     {
00434         m_placeholders = new QPopupMenu(this);
00435         for (i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++)
00436         {
00437             m_placeholders->insertItem(i18n(items[i].description), i, i);
00438         }
00439     }
00440 
00441     // Insert the selection into the edit control.
00442     i = m_placeholders->exec(m_backRefItem->mapToGlobal(m_backRefItem->rect().bottomLeft()));
00443     if (i != -1)
00444     {
00445         QLineEdit *editor = m_replace->lineEdit();
00446 
00447         editor->insert(items[i].backRef);
00448     }
00449 }
00450 
00451 void KFindDialog::slotOk()
00452 {
00453     // Nothing to find?
00454     if (pattern().isEmpty())
00455     {
00456         KMessageBox::error(this, i18n("You must enter some text to search for."));
00457         return;
00458     }
00459 
00460     if (m_regExp->isChecked())
00461     {
00462         // Check for a valid regular expression.
00463         QRegExp regExp(pattern());
00464 
00465         if (!regExp.isValid())
00466         {
00467             KMessageBox::error(this, i18n("Invalid regular expression."));
00468             return;
00469         }
00470     }
00471     m_find->addToHistory(pattern());
00472     emit okClicked();
00473     if ( testWFlags( WShowModal ) )
00474         accept();
00475 }
00476 
00477 #include "kfinddialog.moc"
KDE Logo
This file is part of the documentation for kutils Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jan 22 16:48:51 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003