00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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), 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>\\\\\\<</b> - Matches the beginning of a word<br>"
00182 "<b>\\\\\\></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
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->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
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
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 *, char *buffer, int buflen)
00408 {
00409 buf += QCString(buffer, buflen+1);
00410 processOutput();
00411 }
00412
00413 void GrepTool::receivedErrOutput(KProcess *, 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"