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 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 <qpushbutton.h>
00027 #include <qlineedit.h>
00028 #include <qlabel.h>
00029 #include <qcombobox.h>
00030 #include <qcheckbox.h>
00031 #include <qevent.h>
00032 #include <qlistbox.h>
00033 #include <qregexp.h>
00034 #include <qwhatsthis.h>
00035 #include <qcursor.h>
00036 
00037 #include <kapplication.h>
00038 #include <kaccelmanager.h>
00039 #include <kbuttonbox.h>
00040 #include <kfiledialog.h>
00041 #include <kprocess.h>
00042 #include <kapplication.h>
00043 #include <klocale.h>
00044 #include <kiconloader.h>
00045 #include <kmessagebox.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 *template_str[] = {
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 
00079   QGridLayout *layout = new QGridLayout(this, 6, 3, 4, 4);
00080   layout->setColStretch(0, 10);
00081   layout->addColSpacing(1, 10);
00082   layout->setColStretch(1, 0);
00083   layout->setColStretch(2, 1);
00084   layout->setRowStretch(1, 0);
00085   layout->setRowStretch(2, 10);
00086   layout->setRowStretch(4, 0);
00087 
00088   QGridLayout *input_layout = new QGridLayout(4, 2, 4);
00089   layout->addLayout(input_layout, 0, 0);
00090   input_layout->setColStretch(0, 0);
00091   input_layout->setColStretch(1, 20);
00092 
00093   QLabel *pattern_label = new QLabel(i18n("Pattern:"), this);
00094   pattern_label->setFixedSize(pattern_label->sizeHint());
00095   input_layout->addWidget(pattern_label, 0, 0, AlignRight | AlignVCenter);
00096 
00097   pattern_combo = new QComboBox(true, this);
00098   pattern_combo->insertStringList(lastSearchItems);
00099   pattern_combo->setEditText(QString::null);
00100   pattern_combo->setInsertionPolicy(QComboBox::NoInsertion);
00101   pattern_label->setBuddy(pattern_combo);
00102   pattern_combo->setFocus();
00103   pattern_combo->setMinimumSize(pattern_combo->sizeHint());
00104   input_layout->addWidget(pattern_combo, 0, 1);
00105 
00106   QLabel *template_label = new QLabel(i18n("Template:"), this);
00107   template_label->setFixedSize(template_label->sizeHint());
00108   input_layout->addWidget(template_label, 1, 0, AlignRight | AlignVCenter);
00109 
00110   QBoxLayout *template_layout = new QHBoxLayout(4);
00111   input_layout->addLayout(template_layout, 1, 1);
00112 
00113   template_edit = new QLineEdit(this);
00114   template_label->setBuddy(template_edit);
00115   template_edit->setText(template_str[0]);
00116   template_edit->setMinimumSize(template_edit->sizeHint());
00117   template_layout->addWidget(template_edit);
00118 
00119   QComboBox *template_combo = new QComboBox(false, this);
00120   template_combo->insertStrList(template_desc);
00121   template_combo->adjustSize();
00122   template_combo->setFixedSize(template_combo->size());
00123   template_layout->addWidget(template_combo);
00124 
00125   QLabel *files_label = new QLabel(i18n("Files:"), this);
00126   files_label->setFixedSize(files_label->sizeHint());
00127   input_layout->addWidget(files_label, 2, 0, AlignRight | AlignVCenter);
00128 
00129   files_combo = new QComboBox(true, this);
00130   files_label->setBuddy(files_combo->focusProxy());
00131   files_combo->setMinimumSize(files_combo->sizeHint());
00132   files_combo->insertItem("*.h,*.hxx,*.cpp,*.cc,*.C,*.cxx,*.idl,*.c");
00133   files_combo->insertItem("*.cpp,*.cc,*.C,*.cxx,*.c");
00134   files_combo->insertItem("*.h,*.hxx,*.idl");
00135   files_combo->insertItem("*");
00136   input_layout->addWidget(files_combo, 2, 1);
00137 
00138   QLabel *dir_label = new QLabel(i18n("Directory:"), this);
00139   dir_label->setFixedSize(dir_label->sizeHint());
00140   input_layout->addWidget(dir_label, 3, 0, AlignRight | AlignVCenter);
00141 
00142   QBoxLayout *dir_layout = new QHBoxLayout(3);
00143   input_layout->addLayout(dir_layout, 3, 1);
00144 
00145   dir_combo = new KURLRequester( new KComboBox(true, this), this, "dir combo" );
00146   dir_combo->completionObject()->setMode(KURLCompletion::DirCompletion);
00147   dir_combo->comboBox()->insertStringList(lastSearchPaths);
00148   dir_combo->setMode( KFile::Directory|KFile::LocalOnly );
00149   dir_layout->addWidget(dir_combo);
00150   dir_label->setBuddy(dir_combo);
00151 
00152   recursive_box = new QCheckBox(i18n("Recursive"), this);
00153   recursive_box->setMinimumWidth(recursive_box->sizeHint().width());
00154   recursive_box->setChecked(true);
00155   dir_layout->addSpacing(10);
00156   dir_layout->addWidget(recursive_box);
00157 
00158   KButtonBox *actionbox = new KButtonBox(this, Qt::Vertical);
00159   layout->addWidget(actionbox, 0, 2);
00160   actionbox->addStretch();
00161   search_button = actionbox->addButton(i18n("Search"));
00162   search_button->setDefault(true);
00163   clear_button = actionbox->addButton(i18n("Clear"));
00164   actionbox->addStretch();
00165   actionbox->layout();
00166 
00167   resultbox = new QListBox(this);
00168   QFontMetrics rb_fm(resultbox->fontMetrics());
00169   layout->addMultiCellWidget(resultbox, 2, 2, 0, 2);
00170 
00171   layout->activate();
00172 
00173   KAcceleratorManager::manage( this );
00174 
00175   QWhatsThis::add(pattern_combo,
00176     i18n("Enter the regular expression you want to search for here.<br>"
00177      "Possible meta characters are:<br>"
00178      "<b>.</b> - Matches any character<br>"
00179      "<b>^</b> - Matches the beginning of a line<br>"
00180      "<b>$</b> - Matches the end of a line<br>"
00181      "<b>\\\\\\&lt;</b> - Matches the beginning of a word<br>"
00182      "<b>\\\\\\&gt;</b> - Matches the end of a word<br>"
00183      "<br>"
00184      "The following repetition operators exist:<br>"
00185      "<b>?</b> - The preceding item is matched at most once<br>"
00186      "<b>*</b> - The preceding item is matched zero or more times<br>"
00187      "<b>+</b> - The preceding item is matched one or more times<br>"
00188      "<b>{<i>n</i>}</b> - The preceding item is matched exactly <i>n</i> times<br>"
00189      "<b>{<i>n</i>,}</b> - The preceding item is matched <i>n</i> or more times<br>"
00190      "<b>{,<i>n</i>}</b> - The preceding item is matched at most <i>n</i> times<br>"
00191      "<b>{<i>n</i>,<i>m</i>}</b> - The preceding item is matched at least <i>n</i>,<br>"
00192      "   but at most <i>m</i> times.<br>"
00193      "<br>"
00194      "Furthermore, backreferences to bracketed subexpressions are<br>"
00195      "available via the notation \\\\<i>n</i>."
00196      ));
00197   QWhatsThis::add(files_combo,
00198     i18n("Enter the file name pattern of the files to search here.\n"
00199      "You may give several patterns separated by commas"));
00200   QWhatsThis::add(template_edit,
00201     i18n("You can choose a template for the pattern from the combo box\n"
00202      "and edit it here. The string %s in the template is replaced\n"
00203      "by the pattern input field, resulting in the regular expression\n"
00204      "to search for."));
00205   QWhatsThis::add(dir_combo,
00206     i18n("Enter the directory which contains the files you want to search in."));
00207   QWhatsThis::add(recursive_box,
00208     i18n("Check this box to search in all subdirectories."));
00209   QWhatsThis::add(resultbox,
00210     i18n("The results of the grep run are listed here. Select a\n"
00211      "filename/line number combination and press Enter or doubleclick\n"
00212      "on the item to show the respective line in the editor."));
00213 
00214   // event filter, do something relevant for RETURN
00215   pattern_combo->installEventFilter( this );
00216   template_edit->installEventFilter( this );
00217   pattern_combo->installEventFilter( this );
00218   files_combo->installEventFilter( this );
00219   dir_combo->comboBox()->installEventFilter( this );
00220 
00221   connect( template_combo, SIGNAL(activated(int)),
00222            SLOT(templateActivated(int)) );
00223   connect( resultbox, SIGNAL(selected(const QString&)),
00224            SLOT(itemSelected(const QString&)) );
00225   connect( search_button, SIGNAL(clicked()),
00226            SLOT(slotSearch()) );
00227   connect( clear_button, SIGNAL(clicked()),
00228            SLOT(slotClear()) );
00229   connect( pattern_combo->lineEdit(), SIGNAL(textChanged ( const QString & )),
00230            SLOT( patternTextChanged( const QString & )));
00231 
00232   patternTextChanged( pattern_combo->lineEdit()->text());
00233 }
00234 
00235 
00236 GrepTool::~GrepTool()
00237 {
00238   delete childproc;
00239 }
00240 
00241 void GrepTool::patternTextChanged( const QString & _text)
00242 {
00243   search_button->setEnabled( !_text.isEmpty() );
00244 }
00245 
00246 void GrepTool::templateActivated(int index)
00247 {
00248   template_edit->setText(template_str[index]);
00249 }
00250 
00251 void GrepTool::itemSelected(const QString& item)
00252 {
00253   int pos;
00254   QString filename, linenumber;
00255 
00256   QString str = item;
00257   if ( (pos = str.find(':')) != -1)
00258   {
00259     filename = str.left(pos);
00260     str = str.right(str.length()-1-pos);
00261     if ( (pos = str.find(':')) != -1)
00262     {
00263       linenumber = str.left(pos);
00264       emit itemSelected(filename,linenumber.toInt()-1);
00265     }
00266   }
00267 }
00268 
00269 void GrepTool::processOutput()
00270 {
00271   int pos;
00272   while ( (pos = buf.find('\n')) != -1)
00273   {
00274     QString item = buf.left(pos);
00275     if (!item.isEmpty())
00276       resultbox->insertItem(item);
00277     buf = buf.right(buf.length()-pos-1);
00278   }
00279   kapp->processEvents();
00280 }
00281 
00282 void GrepTool::slotSearch()
00283 {
00284   if ( childproc && childproc->isRunning() )
00285   {
00286     childproc->kill();
00287     return;
00288   }
00289   
00290   if (pattern_combo->currentText().isEmpty())
00291     return;
00292 
00293   slotClear ();
00294 
00295   QString files;
00296   QString files_temp = files_combo->currentText();
00297   if (files_temp.right(1) != ",")
00298       files_temp = files_temp + ",";
00299 
00300   QStringList tokens = QStringList::split ( ",", files_temp, FALSE );
00301   QStringList::Iterator it = tokens.begin();
00302   if (it != tokens.end())
00303       files = " '"+(*it++)+"'" ;
00304 
00305   for ( ; it != tokens.end(); it++ )
00306       files = files + " -o -name " + "'"+(*it)+ "'";
00307 
00308   QString pattern = template_edit->text();
00309   pattern.replace("%s", pattern_combo->currentText());
00310   pattern.replace("'", "'\\''");
00311 
00312   QString filepattern = "find ";
00313   filepattern += KProcess::quote(dir_combo->/*currentText*/url());
00314   if (!recursive_box->isChecked())
00315       filepattern += " -maxdepth 1";
00316   filepattern += " \\( -name ";
00317   filepattern += files;
00318   filepattern += " \\) -exec ";
00319 
00320   childproc = new KShellProcess();
00321   *childproc << filepattern;
00322   *childproc << "grep";
00323   *childproc << "-n";
00324   *childproc << "-H";
00325   *childproc << (QString("-e ") + KProcess::quote(pattern));
00326   *childproc << "{}";
00327   *childproc << "/dev/null";
00328   *childproc << "';'";
00329 
00330   connect( childproc, SIGNAL(processExited(KProcess *)),
00331            SLOT(childExited()) );
00332   connect( childproc, SIGNAL(receivedStdout(KProcess *, char *, int)),
00333            SLOT(receivedOutput(KProcess *, char *, int)) );
00334   connect( childproc, SIGNAL(receivedStderr(KProcess *, char *, int)),
00335            SLOT(receivedErrOutput(KProcess *, char *, int)) );
00336   
00337   // actually it should be checked whether the process was started successfully
00338   resultbox->setCursor( QCursor(Qt::WaitCursor) );
00339   clear_button->setEnabled( false );
00340   search_button->setText( i18n("Cancel") );
00341   childproc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
00342 }
00343 
00344 void GrepTool::slotSearchFor(const QString &pattern)
00345 {
00346   slotClear();
00347   pattern_combo->setEditText(pattern);
00348   slotSearch();
00349 }
00350 
00351 void GrepTool::finish()
00352 {
00353   search_button->setEnabled( !pattern_combo->lineEdit()->text().isEmpty() );
00354 
00355   buf += '\n';
00356   processOutput();
00357   delete childproc;
00358   childproc = 0;
00359 
00360   config->setGroup("GrepTool");
00361 
00362   if (lastSearchItems.contains(pattern_combo->currentText()) == 0)
00363   {
00364     pattern_combo->insertItem(pattern_combo->currentText(), 0);
00365     lastSearchItems.prepend(pattern_combo->currentText());
00366     if (lastSearchItems.count() > 10) {
00367       lastSearchItems.remove(lastSearchItems.fromLast());
00368       pattern_combo->removeItem(pattern_combo->count() - 1);
00369     }
00370     config->writeEntry("LastSearchItems", lastSearchItems);
00371   }
00372 
00373   if (lastSearchPaths.contains(dir_combo->url()) == 0)
00374   {
00375     dir_combo->comboBox()->insertItem(dir_combo->url(), 0);
00376     lastSearchPaths.prepend(dir_combo->url());
00377     if (lastSearchPaths.count() > 10)
00378     {
00379       lastSearchPaths.remove(lastSearchPaths.fromLast());
00380       dir_combo->comboBox()->removeItem(dir_combo->comboBox()->count() - 1);
00381     }
00382     config->writeEntry("LastSearchPaths", lastSearchPaths);
00383   }
00384 }
00385 
00386 void GrepTool::slotCancel()
00387 {
00388   finish();
00389 }
00390 
00391 void GrepTool::childExited()
00392 {
00393 //   int status = childproc->exitStatus();
00394   resultbox->unsetCursor();
00395   clear_button->setEnabled( true );
00396   search_button->setText( i18n("Search") );
00397 
00398   if ( ! errbuf.isEmpty() )
00399   {
00400     KMessageBox::information( parentWidget(), i18n("<strong>Error:</strong><p>") + errbuf, i18n("Grep tool error") );
00401     errbuf.truncate(0);
00402   }
00403   else
00404     finish();
00405 }
00406 
00407 void GrepTool::receivedOutput(KProcess */*proc*/, char *buffer, int buflen)
00408 {
00409   buf += QCString(buffer, buflen+1);
00410   processOutput();
00411 }
00412 
00413 void GrepTool::receivedErrOutput(KProcess */*proc*/, char *buffer, int buflen)
00414 {
00415   errbuf += QCString( buffer, buflen + 1 );
00416 }
00417 
00418 void GrepTool::slotClear()
00419 {
00420   finish();
00421   resultbox->clear();
00422 }
00423 
00424 void GrepTool::updateDirName(const QString &dir)
00425 {
00426   if (m_lastUpdatedDir != dir)
00427   {
00428     setDirName (dir);
00429     m_lastUpdatedDir = dir;
00430   }
00431 }
00432 
00433 void GrepTool::setDirName(const QString &dir){
00434   dir_combo->setURL(dir);
00435 }
00436 
00437 bool GrepTool::eventFilter( QObject *o, QEvent *e )
00438 {
00439   if ( e->type() == QEvent::KeyPress && (
00440        ((QKeyEvent*)e)->key() == Qt::Key_Return ||
00441        ((QKeyEvent*)e)->key() == Qt::Key_Enter ) )
00442   {
00443     if ( pattern_combo->currentText().isEmpty() )
00444       pattern_combo->setFocus();
00445     else if ( template_edit->text().isEmpty() )
00446       template_edit->setFocus();
00447     else if ( files_combo->currentText().isEmpty() )
00448       files_combo->setFocus();
00449     else if ( dir_combo->url().isEmpty() )
00450       dir_combo->setFocus();
00451 
00452     else
00453       slotSearch();
00454 
00455     return true;
00456   }
00457 
00458   return QWidget::eventFilter( o, e );
00459 }
00460 
00461 #include "kategrepdialog.moc"
KDE Logo
This file is part of the documentation for kate Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Apr 11 13:44:48 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003