kate Library API Documentation

kategrepdialog.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00003    Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
00004    Copyright (C) 2001, 2004 Anders Lund <anders.lund@lund.tdcadsl.dk>
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 "kategrepdialog.h"
00022 #include "katemainwindow.h"
00023 
00024 #include <qobject.h>
00025 #include <qlayout.h>
00026 #include <qlineedit.h>
00027 #include <qlabel.h>
00028 #include <qcombobox.h>
00029 #include <qcheckbox.h>
00030 #include <qevent.h>
00031 #include <qlistbox.h>
00032 #include <qregexp.h>
00033 #include <qwhatsthis.h>
00034 #include <qcursor.h>
00035 
00036 #include <kapplication.h>
00037 #include <kaccelmanager.h>
00038 #include <kbuttonbox.h>
00039 #include <kfiledialog.h>
00040 #include <kprocess.h>
00041 #include <kapplication.h>
00042 #include <klocale.h>
00043 #include <kiconloader.h>
00044 #include <kmessagebox.h>
00045 #include <kpushbutton.h>
00046 #include <kurlrequester.h>
00047 #include <kurlcompletion.h>
00048 #include <kcombobox.h>
00049 #include <klineedit.h>
00050 
00051 const char *template_desc[] = {
00052   "normal",
00053   "assignment",
00054   "->MEMBER(",
00055   "class::MEMBER(",
00056   "OBJECT->member(",
00057   0
00058 };
00059 
00060 const char *strTemplate[] = {
00061   "%s",
00062   "\\<%s\\>[\t ]*=[^=]",
00063   "\\->[\\t ]*\\<%s\\>[\\t ]*(",
00064   "[a-z0-9_$]\\+[\\t ]*::[\\t ]*\\<%s\\>[\\t ]*(",
00065   "\\<%s\\>[\\t ]*\\->[\\t ]*[a-z0-9_$]\\+[\\t ]*(",
00066   0
00067 };
00068 
00069 
00070 GrepTool::GrepTool(KateMainWindow *parent, const char *name)
00071   : QWidget(parent, name/*, false*/), childproc(0)
00072 {
00073   setCaption(i18n("Find in Files"));
00074   config = KGlobal::config();
00075   config->setGroup("GrepTool");
00076   lastSearchItems = config->readListEntry("LastSearchItems");
00077   lastSearchPaths = config->readListEntry("LastSearchPaths");
00078   lastSearchFiles = config->readListEntry("LastSearchFiles");
00079 
00080   QGridLayout *layout = new QGridLayout(this, 6, 3, 4, 4);
00081   layout->setColStretch(0, 10);
00082   layout->addColSpacing(1, 10);
00083   layout->setColStretch(1, 0);
00084   layout->setColStretch(2, 1);
00085   layout->setRowStretch(1, 0);
00086   layout->setRowStretch(2, 10);
00087   layout->setRowStretch(4, 0);
00088 
00089   QGridLayout *loInput = new QGridLayout(4, 2, 4);
00090   layout->addLayout(loInput, 0, 0);
00091   loInput->setColStretch(0, 0);
00092   loInput->setColStretch(1, 20);
00093 
00094   QLabel *lPattern = new QLabel(i18n("Pattern:"), this);
00095   lPattern->setFixedSize(lPattern->sizeHint());
00096   loInput->addWidget(lPattern, 0, 0, AlignRight | AlignVCenter);
00097 
00098   QBoxLayout *loPattern = new QHBoxLayout( 4 );
00099   loInput->addLayout( loPattern, 0, 1 );
00100   cmbPattern = new QComboBox(true, this);
00101   cmbPattern->setDuplicatesEnabled(false);
00102   cmbPattern->insertStringList(lastSearchItems);
00103   cmbPattern->setEditText(QString::null);
00104   cmbPattern->setInsertionPolicy(QComboBox::NoInsertion);
00105   lPattern->setBuddy(cmbPattern);
00106   cmbPattern->setFocus();
00107   cmbPattern->setMinimumSize(cmbPattern->sizeHint());
00108   loPattern->addWidget( cmbPattern );
00109 
00110   cbCasesensitive = new QCheckBox(i18n("Case sensitive"), this);
00111   cbCasesensitive->setMinimumWidth(cbCasesensitive->sizeHint().width());
00112   cbCasesensitive->setChecked(config->readBoolEntry("CaseSensitive", true));
00113   loPattern->addWidget(cbCasesensitive);
00114 
00115   cbRegex = new QCheckBox( i18n("Regular expression"), this );
00116   cbRegex->setMinimumWidth( cbRegex->sizeHint().width() );
00117   cbRegex->setChecked( config->readBoolEntry( "Regex", true ) );
00118   loPattern->addWidget( cbRegex );
00119   loPattern->setStretchFactor( cmbPattern, 100 );
00120 
00121   QLabel *lTemplate = new QLabel(i18n("Template:"), this);
00122   lTemplate->setFixedSize(lTemplate->sizeHint());
00123   loInput->addWidget(lTemplate, 1, 0, AlignRight | AlignVCenter);
00124 
00125   QBoxLayout *loTemplate = new QHBoxLayout(4);
00126   loInput->addLayout(loTemplate, 1, 1);
00127 
00128   leTemplate = new QLineEdit(this);
00129   lTemplate->setBuddy(leTemplate);
00130   leTemplate->setText(strTemplate[0]);
00131   leTemplate->setMinimumSize(leTemplate->sizeHint());
00132   loTemplate->addWidget(leTemplate);
00133 
00134   QComboBox *cmbTemplate = new QComboBox(false, this);
00135   cmbTemplate->insertStrList(template_desc);
00136   cmbTemplate->adjustSize();
00137   cmbTemplate->setFixedSize(cmbTemplate->size());
00138   loTemplate->addWidget(cmbTemplate);
00139 
00140   QLabel *lFiles = new QLabel(i18n("Files:"), this);
00141   lFiles->setFixedSize(lFiles->sizeHint());
00142   loInput->addWidget(lFiles, 2, 0, AlignRight | AlignVCenter);
00143 
00144   cmbFiles = new QComboBox(true, this);
00145   lFiles->setBuddy(cmbFiles->focusProxy());
00146   cmbFiles->setMinimumSize(cmbFiles->sizeHint());
00147   cmbFiles->setDuplicatesEnabled(false);
00148   cmbFiles->insertStringList(lastSearchFiles);
00149   cmbFiles->insertItem("*.h,*.hxx,*.cpp,*.cc,*.C,*.cxx,*.idl,*.c");
00150   cmbFiles->insertItem("*.cpp,*.cc,*.C,*.cxx,*.c");
00151   cmbFiles->insertItem("*.h,*.hxx,*.idl");
00152   cmbFiles->insertItem("*");
00153   loInput->addWidget(cmbFiles, 2, 1);
00154 
00155   QLabel *lDir = new QLabel(i18n("Directory:"), this);
00156   lDir->setFixedSize(lDir->sizeHint());
00157   loInput->addWidget(lDir, 3, 0, AlignRight | AlignVCenter);
00158 
00159   QBoxLayout *loDir = new QHBoxLayout(3);
00160   loInput->addLayout(loDir, 3, 1);
00161 
00162   KComboBox* cmbUrl = new KComboBox(true, this);
00163   cmbUrl->setMinimumWidth(80); // make sure that 800x600 res works
00164   cmbUrl->setDuplicatesEnabled(false);
00165   cmbDir = new KURLRequester( cmbUrl, this, "dir combo" );
00166   cmbDir->completionObject()->setMode(KURLCompletion::DirCompletion);
00167   cmbDir->comboBox()->insertStringList(lastSearchPaths);
00168   cmbDir->setMode( KFile::Directory|KFile::LocalOnly );
00169   loDir->addWidget(cmbDir, 1);
00170   lDir->setBuddy(cmbDir);
00171 
00172   cbRecursive = new QCheckBox(i18n("Recursive"), this);
00173   cbRecursive->setMinimumWidth(cbRecursive->sizeHint().width());
00174   cbRecursive->setChecked(config->readBoolEntry("Recursive", true));
00175   loDir->addWidget(cbRecursive);
00176 
00177   KButtonBox *actionbox = new KButtonBox(this, Qt::Vertical);
00178   layout->addWidget(actionbox, 0, 2);
00179   actionbox->addStretch();
00180   btnSearch = static_cast<KPushButton*>(actionbox->addButton(KGuiItem(i18n("Find"),"find")));
00181   btnSearch->setDefault(true);
00182   btnClear = static_cast<KPushButton*>(actionbox->addButton( KStdGuiItem::clear() ));
00183   actionbox->addStretch();
00184   actionbox->layout();
00185 
00186   lbResult = new QListBox(this);
00187   QFontMetrics rb_fm(lbResult->fontMetrics());
00188   layout->addMultiCellWidget(lbResult, 2, 2, 0, 2);
00189 
00190   layout->activate();
00191 
00192   KAcceleratorManager::manage( this );
00193 
00194   QWhatsThis::add(lPattern,
00195     i18n("<p>Enter the expression you want to search for here."
00196      "<p>If 'regular expression' is unchecked, any non-space letters in your "
00197      "expression will be escaped with a backslash character."
00198      "<p>Possible meta characters are:<br>"
00199      "<b>.</b> - Matches any character<br>"
00200      "<b>^</b> - Matches the beginning of a line<br>"
00201      "<b>$</b> - Matches the end of a line<br>"
00202      "<b>\\&lt;</b> - Matches the beginning of a word<br>"
00203      "<b>\\&gt;</b> - Matches the end of a word"
00204      "<p>The following repetition operators exist:<br>"
00205      "<b>?</b> - The preceding item is matched at most once<br>"
00206      "<b>*</b> - The preceding item is matched zero or more times<br>"
00207      "<b>+</b> - The preceding item is matched one or more times<br>"
00208      "<b>{<i>n</i>}</b> - The preceding item is matched exactly <i>n</i> times<br>"
00209      "<b>{<i>n</i>,}</b> - The preceding item is matched <i>n</i> or more times<br>"
00210      "<b>{,<i>n</i>}</b> - The preceding item is matched at most <i>n</i> times<br>"
00211      "<b>{<i>n</i>,<i>m</i>}</b> - The preceding item is matched at least <i>n</i>, "
00212      "but at most <i>m</i> times."
00213      "<p>Furthermore, backreferences to bracketed subexpressions are available "
00214      "via the notation <code>\\#</code>."
00215      "<p>See the grep(1) documentation for the full documentation."
00216      ));
00217   QWhatsThis::add(lFiles,
00218     i18n("Enter the file name pattern of the files to search here.\n"
00219      "You may give several patterns separated by commas."));
00220   QWhatsThis::add(lTemplate,
00221     i18n("You can choose a template for the pattern from the combo box\n"
00222      "and edit it here. The string %s in the template is replaced\n"
00223      "by the pattern input field, resulting in the regular expression\n"
00224      "to search for."));
00225   QWhatsThis::add(lDir,
00226     i18n("Enter the directory which contains the files you want to search in."));
00227   QWhatsThis::add(cbRecursive,
00228     i18n("Check this box to search in all subdirectories."));
00229   QWhatsThis::add(cbCasesensitive,
00230     i18n("If this option is enabled (the default), the search will be case sensitive."));
00231   QWhatsThis::add( cbRegex, i18n(
00232       "<p>If this is enabled, your pattern will be passed unmodified to "
00233       "<em>grep(1)</em>. Otherwise, all characters that are not letters will be "
00234       "escaped using a backslash character to prevent grep from interpreting "
00235       "them as part of the expression.") );
00236   QWhatsThis::add(lbResult,
00237     i18n("The results of the grep run are listed here. Select a\n"
00238      "filename/line number combination and press Enter or doubleclick\n"
00239      "on the item to show the respective line in the editor."));
00240 
00241   // event filter, do something relevant for RETURN
00242   cmbPattern->installEventFilter( this );
00243   leTemplate->installEventFilter( this );
00244   cmbPattern->installEventFilter( this );
00245   cmbFiles->installEventFilter( this );
00246   cmbDir->comboBox()->installEventFilter( this );
00247 
00248   connect( cmbTemplate, SIGNAL(activated(int)),
00249            SLOT(templateActivated(int)) );
00250   connect( lbResult, SIGNAL(selected(const QString&)),
00251            SLOT(itemSelected(const QString&)) );
00252   connect( btnSearch, SIGNAL(clicked()),
00253            SLOT(slotSearch()) );
00254   connect( btnClear, SIGNAL(clicked()),
00255            SLOT(slotClear()) );
00256   connect( cmbPattern->lineEdit(), SIGNAL(textChanged ( const QString & )),
00257            SLOT( patternTextChanged( const QString & )));
00258 
00259   patternTextChanged( cmbPattern->lineEdit()->text());
00260 }
00261 
00262 
00263 GrepTool::~GrepTool()
00264 {
00265   delete childproc;
00266 }
00267 
00268 void GrepTool::patternTextChanged( const QString & _text)
00269 {
00270   btnSearch->setEnabled( !_text.isEmpty() );
00271 }
00272 
00273 void GrepTool::templateActivated(int index)
00274 {
00275   leTemplate->setText(strTemplate[index]);
00276 }
00277 
00278 void GrepTool::itemSelected(const QString& item)
00279 {
00280   int pos;
00281   QString filename, linenumber;
00282 
00283   QString str = item;
00284   if ( (pos = str.find(':')) != -1)
00285   {
00286     filename = str.left(pos);
00287     str = str.mid(pos+1);
00288     if ( (pos = str.find(':')) != -1)
00289     {
00290       filename = m_workingDir + QDir::separator() + filename;
00291       linenumber = str.left(pos);
00292       emit itemSelected(filename,linenumber.toInt()-1);
00293     }
00294   }
00295 }
00296 
00297 void GrepTool::processOutput()
00298 {
00299   int pos;
00300   while ( (pos = buf.find('\n')) != -1)
00301   {
00302     QString item = buf.mid(2,pos-2);
00303     if (!item.isEmpty())
00304       lbResult->insertItem(item);
00305     buf = buf.mid(pos+1);
00306   }
00307   kapp->processEvents();
00308 }
00309 
00310 void GrepTool::slotSearch()
00311 {
00312   if ( cmbPattern->currentText().isEmpty() )
00313   {
00314     cmbPattern->setFocus();
00315     return;
00316   }
00317 
00318   if ( cmbDir->url().isEmpty() || ! QDir(cmbDir->url()).exists() )
00319   {
00320     cmbDir->setFocus();
00321     return;
00322   }
00323 
00324   if ( ! leTemplate->text().contains("%s") )
00325   {
00326     leTemplate->setFocus();
00327     return;
00328   }
00329 
00330   if ( childproc && childproc->isRunning() )
00331   {
00332     childproc->kill();
00333     return;
00334   }
00335 
00336   slotClear ();
00337 
00338   m_workingDir = cmbDir->url();
00339 
00340   QString s = cmbPattern->currentText();
00341   if ( ! cbRegex->isChecked() )
00342     s.replace( QRegExp( "([^\\w'])" ), "\\\\1" );
00343   QString pattern = leTemplate->text();
00344   pattern.replace( "%s", s );
00345 
00346   childproc = new KProcess();
00347   childproc->setWorkingDirectory( m_workingDir );
00348   *childproc << "find" << ".";
00349   if (!cbRecursive->isChecked())
00350     *childproc << "-maxdepth" << "1";
00351   if (!cmbFiles->currentText().isEmpty() )
00352   {
00353     QStringList files = QStringList::split ( ",", cmbFiles->currentText(), FALSE );
00354     *childproc << "(";
00355     bool first = true;
00356     for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it )
00357     {
00358       if (!first)
00359         *childproc << "-o";
00360       *childproc << "-name" << (*it);
00361       first = false;
00362     }
00363     *childproc << ")";
00364   }
00365   *childproc << "-exec" << "grep";
00366   if (!cbCasesensitive->isChecked())
00367     *childproc << "-i";
00368   *childproc << "-n" << "-e" << pattern << "{}";
00369   *childproc << "/dev/null"; //trick to have grep always display the filename
00370   *childproc << ";";
00371 
00372   connect( childproc, SIGNAL(processExited(KProcess *)),
00373            SLOT(childExited()) );
00374   connect( childproc, SIGNAL(receivedStdout(KProcess *, char *, int)),
00375            SLOT(receivedOutput(KProcess *, char *, int)) );
00376   connect( childproc, SIGNAL(receivedStderr(KProcess *, char *, int)),
00377            SLOT(receivedErrOutput(KProcess *, char *, int)) );
00378 
00379   // actually it should be checked whether the process was started successfully
00380   lbResult->setCursor( QCursor(Qt::WaitCursor) );
00381   btnClear->setEnabled( false );
00382   btnSearch->setGuiItem( KGuiItem(i18n("Cancel"), "button_cancel"));
00383   childproc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
00384 }
00385 
00386 void GrepTool::slotSearchFor(const QString &pattern)
00387 {
00388   slotClear();
00389   cmbPattern->setEditText(pattern);
00390   slotSearch();
00391 }
00392 
00393 void GrepTool::finish()
00394 {
00395   btnSearch->setEnabled( !cmbPattern->lineEdit()->text().isEmpty() );
00396 
00397   buf += '\n';
00398   processOutput();
00399   delete childproc;
00400   childproc = 0;
00401 
00402   config->setGroup("GrepTool");
00403 
00404   if (lastSearchItems.contains(cmbPattern->currentText()) == 0)
00405   {
00406     cmbPattern->insertItem(cmbPattern->currentText(), 0);
00407     lastSearchItems.prepend(cmbPattern->currentText());
00408     if (lastSearchItems.count() > 10) {
00409       lastSearchItems.remove(lastSearchItems.fromLast());
00410       cmbPattern->removeItem(cmbPattern->count() - 1);
00411     }
00412     config->writeEntry("LastSearchItems", lastSearchItems);
00413   }
00414 
00415   if (lastSearchPaths.contains(cmbDir->url()) == 0)
00416   {
00417     cmbDir->comboBox()->insertItem(cmbDir->url(), 0);
00418     lastSearchPaths.prepend(cmbDir->url());
00419     if (lastSearchPaths.count() > 10)
00420     {
00421       lastSearchPaths.remove(lastSearchPaths.fromLast());
00422       cmbDir->comboBox()->removeItem(cmbDir->comboBox()->count() - 1);
00423     }
00424     config->writeEntry("LastSearchPaths", lastSearchPaths);
00425   }
00426 
00427   if (lastSearchFiles.contains(cmbFiles->currentText()) == 0)
00428   {
00429     cmbFiles->insertItem(cmbFiles->currentText(), 0);
00430     lastSearchFiles.prepend(cmbFiles->currentText());
00431     if (lastSearchItems.count() > 10) {
00432       lastSearchFiles.remove(lastSearchFiles.fromLast());
00433       cmbFiles->removeItem(cmbFiles->count() - 1);
00434     }
00435     config->writeEntry("LastSearchFiles", lastSearchFiles);
00436   }
00437 
00438   config->writeEntry("Recursive", cbRecursive->isChecked());
00439   config->writeEntry("CaseSensitive", cbCasesensitive->isChecked());
00440   config->writeEntry( "Regex", cbRegex->isChecked() );
00441 }
00442 
00443 void GrepTool::slotCancel()
00444 {
00445   finish();
00446 }
00447 
00448 void GrepTool::childExited()
00449 {
00450 //   int status = childproc->exitStatus();
00451   lbResult->unsetCursor();
00452   btnClear->setEnabled( true );
00453   btnSearch->setGuiItem( KGuiItem(i18n("Find"), "find") );
00454 
00455   if ( ! errbuf.isEmpty() )
00456   {
00457     KMessageBox::information( parentWidget(), i18n("<strong>Error:</strong><p>") + errbuf, i18n("Grep Tool Error") );
00458     errbuf.truncate(0);
00459   }
00460   else
00461     finish();
00462 }
00463 
00464 void GrepTool::receivedOutput(KProcess */*proc*/, char *buffer, int buflen)
00465 {
00466   buf += QCString(buffer, buflen+1);
00467   processOutput();
00468 }
00469 
00470 void GrepTool::receivedErrOutput(KProcess */*proc*/, char *buffer, int buflen)
00471 {
00472   errbuf += QCString( buffer, buflen + 1 );
00473 }
00474 
00475 void GrepTool::slotClear()
00476 {
00477   finish();
00478   lbResult->clear();
00479 }
00480 
00481 void GrepTool::updateDirName(const QString &dir)
00482 {
00483   if (m_lastUpdatedDir != dir)
00484   {
00485     setDirName (dir);
00486     m_lastUpdatedDir = dir;
00487   }
00488 }
00489 
00490 void GrepTool::setDirName(const QString &dir){
00491   cmbDir->setURL(dir);
00492 }
00493 
00494 bool GrepTool::eventFilter( QObject *o, QEvent *e )
00495 {
00496   if ( e->type() == QEvent::KeyPress && (
00497        ((QKeyEvent*)e)->key() == Qt::Key_Return ||
00498        ((QKeyEvent*)e)->key() == Qt::Key_Enter ) )
00499   {
00500     slotSearch();
00501     return true;
00502   }
00503 
00504   return QWidget::eventFilter( o, e );
00505 }
00506 
00507 #include "kategrepdialog.moc"
KDE Logo
This file is part of the documentation for kate Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jun 14 01:19:50 2006 by doxygen 1.4.0 written by Dimitri van Heesch, © 1997-2003