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 <tqobject.h>
00025 #include <tqlayout.h>
00026 #include <tqlabel.h>
00027 #include <tqcheckbox.h>
00028 #include <tqevent.h>
00029 #include <tqlistbox.h>
00030 #include <tqregexp.h>
00031 #include <tqwhatsthis.h>
00032 #include <tqcursor.h>
00033
00034 #include <tdeapplication.h>
00035 #include <tdeaccelmanager.h>
00036 #include <kbuttonbox.h>
00037 #include <tdefiledialog.h>
00038 #include <kprocess.h>
00039 #include <tdeapplication.h>
00040 #include <tdelocale.h>
00041 #include <kiconloader.h>
00042 #include <tdemessagebox.h>
00043 #include <kpushbutton.h>
00044 #include <kurlrequester.h>
00045 #include <kurlcompletion.h>
00046 #include <kcombobox.h>
00047 #include <klineedit.h>
00048
00049 const char *template_desc[] = {
00050 "normal",
00051 "assignment",
00052 "->MEMBER(",
00053 "class::MEMBER(",
00054 "OBJECT->member(",
00055 0
00056 };
00057
00058 const char *strTemplate[] = {
00059 "%s",
00060 "\\<%s\\>[\t ]*=[^=]",
00061 "\\->[\\t ]*\\<%s\\>[\\t ]*(",
00062 "[a-z0-9_$]\\+[\\t ]*::[\\t ]*\\<%s\\>[\\t ]*(",
00063 "\\<%s\\>[\\t ]*\\->[\\t ]*[a-z0-9_$]\\+[\\t ]*(",
00064 0
00065 };
00066
00067
00068 GrepTool::GrepTool(TQWidget *parent, const char *name)
00069 : TQWidget(parent, name), m_fixFocus(true), childproc(0)
00070 {
00071 setCaption(i18n("Find in Files"));
00072 config = TDEGlobal::config();
00073 config->setGroup("GrepTool");
00074 lastSearchItems = config->readListEntry("LastSearchItems");
00075 lastSearchPaths = config->readListEntry("LastSearchPaths");
00076 lastSearchFiles = config->readListEntry("LastSearchFiles");
00077
00078 if( lastSearchFiles.isEmpty() )
00079 {
00080
00081
00082 lastSearchFiles << "*.h,*.hxx,*.cpp,*.cc,*.C,*.cxx,*.idl,*.c"
00083 << "*.cpp,*.cc,*.C,*.cxx,*.c"
00084 << "*.h,*.hxx,*.idl"
00085 << "*";
00086 }
00087
00088 TQGridLayout *layout = new TQGridLayout(this, 6, 3, 4, 4);
00089 layout->setColStretch(0, 10);
00090 layout->addColSpacing(1, 10);
00091 layout->setColStretch(1, 0);
00092 layout->setColStretch(2, 1);
00093 layout->setRowStretch(1, 0);
00094 layout->setRowStretch(2, 10);
00095 layout->setRowStretch(4, 0);
00096
00097 TQGridLayout *loInput = new TQGridLayout(4, 2, 4);
00098 layout->addLayout(loInput, 0, 0);
00099 loInput->setColStretch(0, 0);
00100 loInput->setColStretch(1, 20);
00101
00102 TQLabel *lPattern = new TQLabel(i18n("Pattern:"), this);
00103 lPattern->setFixedSize(lPattern->sizeHint());
00104 loInput->addWidget(lPattern, 0, 0, Qt::AlignRight | Qt::AlignVCenter);
00105
00106 TQBoxLayout *loPattern = new TQHBoxLayout( 4 );
00107 loInput->addLayout( loPattern, 0, 1 );
00108 cmbPattern = new KComboBox(true, this);
00109 cmbPattern->setDuplicatesEnabled(false);
00110 cmbPattern->insertStringList(lastSearchItems);
00111 cmbPattern->setEditText(TQString::null);
00112 cmbPattern->setInsertionPolicy(TQComboBox::NoInsertion);
00113 lPattern->setBuddy(cmbPattern);
00114 cmbPattern->setFocus();
00115 cmbPattern->setMinimumSize(cmbPattern->sizeHint());
00116 loPattern->addWidget( cmbPattern );
00117
00118 cbCasesensitive = new TQCheckBox(i18n("Case sensitive"), this);
00119 cbCasesensitive->setMinimumWidth(cbCasesensitive->sizeHint().width());
00120 cbCasesensitive->setChecked(config->readBoolEntry("CaseSensitive", true));
00121 loPattern->addWidget(cbCasesensitive);
00122
00123 cbRegex = new TQCheckBox( i18n("Regular expression"), this );
00124 cbRegex->setMinimumWidth( cbRegex->sizeHint().width() );
00125 cbRegex->setChecked( config->readBoolEntry( "Regex", true ) );
00126 loPattern->addWidget( cbRegex );
00127 loPattern->setStretchFactor( cmbPattern, 100 );
00128
00129 TQLabel *lTemplate = new TQLabel(i18n("Template:"), this);
00130 lTemplate->setFixedSize(lTemplate->sizeHint());
00131 loInput->addWidget(lTemplate, 1, 0, Qt::AlignRight | Qt::AlignVCenter);
00132
00133 TQBoxLayout *loTemplate = new TQHBoxLayout(4);
00134 loInput->addLayout(loTemplate, 1, 1);
00135
00136 leTemplate = new KLineEdit(this);
00137 lTemplate->setBuddy(leTemplate);
00138 leTemplate->setText(strTemplate[0]);
00139 leTemplate->setMinimumSize(leTemplate->sizeHint());
00140 loTemplate->addWidget(leTemplate);
00141
00142 KComboBox *cmbTemplate = new KComboBox(false, this);
00143 cmbTemplate->insertStrList(template_desc);
00144 cmbTemplate->adjustSize();
00145 cmbTemplate->setFixedSize(cmbTemplate->size());
00146 loTemplate->addWidget(cmbTemplate);
00147
00148 TQLabel *lFiles = new TQLabel(i18n("Files:"), this);
00149 lFiles->setFixedSize(lFiles->sizeHint());
00150 loInput->addWidget(lFiles, 2, 0, Qt::AlignRight | Qt::AlignVCenter);
00151
00152 TQBoxLayout *loFiles = new TQHBoxLayout( 2 );
00153 loInput->addLayout( loFiles, 2, 1 );
00154
00155 cmbFiles = new KComboBox(true, this);
00156 lFiles->setBuddy(TQT_TQWIDGET(cmbFiles->focusProxy()));
00157 cmbFiles->setMinimumSize(cmbFiles->sizeHint());
00158 cmbFiles->setInsertionPolicy(TQComboBox::NoInsertion);
00159 cmbFiles->setDuplicatesEnabled(false);
00160 cmbFiles->insertStringList(lastSearchFiles);
00161 loFiles->addWidget(cmbFiles);
00162
00163 cbHideErrors = new TQCheckBox( i18n("Hide errors"), this );
00164 cbHideErrors->setMinimumWidth( cbHideErrors->sizeHint().width() );
00165 cbHideErrors->setChecked( config->readBoolEntry( "HideErrors", false ) );
00166 loFiles->addWidget(cbHideErrors);
00167 loFiles->setStretchFactor(cmbFiles, 100);
00168
00169 TQLabel *lDir = new TQLabel(i18n("Folder:"), this);
00170 lDir->setFixedSize(lDir->sizeHint());
00171 loInput->addWidget(lDir, 3, 0, Qt::AlignRight | Qt::AlignVCenter);
00172
00173 TQBoxLayout *loDir = new TQHBoxLayout(3);
00174 loInput->addLayout(loDir, 3, 1);
00175
00176 KComboBox* cmbUrl = new KComboBox(true, this);
00177 cmbUrl->setMinimumWidth(80);
00178 cmbUrl->setDuplicatesEnabled(false);
00179 cmbUrl->setInsertionPolicy(TQComboBox::NoInsertion);
00180 cmbDir = new KURLRequester( cmbUrl, this, "dir combo" );
00181 cmbDir->completionObject()->setMode(KURLCompletion::DirCompletion);
00182 cmbDir->comboBox()->insertStringList(lastSearchPaths);
00183 cmbDir->setMode( KFile::Directory|KFile::LocalOnly );
00184 loDir->addWidget(cmbDir, 1);
00185 lDir->setBuddy(cmbDir);
00186
00187 cbRecursive = new TQCheckBox(i18n("Recursive"), this);
00188 cbRecursive->setMinimumWidth(cbRecursive->sizeHint().width());
00189 cbRecursive->setChecked(config->readBoolEntry("Recursive", true));
00190 loDir->addWidget(cbRecursive);
00191
00192 KButtonBox *actionbox = new KButtonBox(this, Qt::Vertical);
00193 layout->addWidget(actionbox, 0, 2);
00194 actionbox->addStretch();
00195 btnSearch = static_cast<KPushButton*>(actionbox->addButton(KGuiItem(i18n("Find"),"edit-find")));
00196 btnSearch->setDefault(true);
00197 btnClear = static_cast<KPushButton*>(actionbox->addButton( KStdGuiItem::clear() ));
00198 actionbox->addStretch();
00199 actionbox->layout();
00200
00201 lbResult = new TQListBox(this);
00202 TQFontMetrics rb_fm(lbResult->fontMetrics());
00203 layout->addMultiCellWidget(lbResult, 2, 2, 0, 2);
00204
00205 layout->activate();
00206
00207 TDEAcceleratorManager::manage( this );
00208
00209 TQWhatsThis::add(lPattern,
00210 i18n("<p>Enter the expression you want to search for here."
00211 "<p>If 'regular expression' is unchecked, all characters that are not "
00212 "letters in your expression will be escaped with a backslash character."
00213 "<p>Possible meta characters are:<br>"
00214 "<b>.</b> - Matches any character<br>"
00215 "<b>^</b> - Matches the beginning of a line<br>"
00216 "<b>$</b> - Matches the end of a line<br>"
00217 "<b>\\<</b> - Matches the beginning of a word<br>"
00218 "<b>\\></b> - Matches the end of a word"
00219 "<p>The following repetition operators exist:<br>"
00220 "<b>?</b> - The preceding item is matched at most once<br>"
00221 "<b>*</b> - The preceding item is matched zero or more times<br>"
00222 "<b>+</b> - The preceding item is matched one or more times<br>"
00223 "<b>{<i>n</i>}</b> - The preceding item is matched exactly <i>n</i> times<br>"
00224 "<b>{<i>n</i>,}</b> - The preceding item is matched <i>n</i> or more times<br>"
00225 "<b>{,<i>n</i>}</b> - The preceding item is matched at most <i>n</i> times<br>"
00226 "<b>{<i>n</i>,<i>m</i>}</b> - The preceding item is matched at least <i>n</i>, "
00227 "but at most <i>m</i> times."
00228 "<p>Furthermore, backreferences to bracketed subexpressions are available "
00229 "via the notation <code>\\#</code>."
00230 "<p>See the grep(1) documentation for the full documentation."
00231 ));
00232 TQWhatsThis::add(lFiles,
00233 i18n("Enter the file name pattern of the files to search here.\n"
00234 "You may give several patterns separated by commas."));
00235 TQWhatsThis::add(lTemplate,
00236 i18n("You can choose a template for the pattern from the combo box\n"
00237 "and edit it here. The string %s in the template is replaced\n"
00238 "by the pattern input field, resulting in the regular expression\n"
00239 "to search for."));
00240 TQWhatsThis::add(lDir,
00241 i18n("Enter the folder which contains the files in which you want to search."));
00242 TQWhatsThis::add(cbRecursive,
00243 i18n("Check this box to search in all subfolders."));
00244 TQWhatsThis::add(cbCasesensitive,
00245 i18n("If this option is enabled (the default), the search will be case sensitive."));
00246 TQWhatsThis::add( cbRegex, i18n(
00247 "<p>If this is enabled, your pattern will be passed unmodified to "
00248 "<em>grep(1)</em>. Otherwise, all characters that are not letters will be "
00249 "escaped using a backslash character to prevent grep from interpreting "
00250 "them as part of the expression.") );
00251 TQWhatsThis::add(lbResult,
00252 i18n("The results of the grep run are listed here. Select a\n"
00253 "filename/line number combination and press Enter or doubleclick\n"
00254 "on the item to show the respective line in the editor."));
00255 TQWhatsThis::add( cbHideErrors, i18n(
00256 "<p>If this is checked, the dialog window showing the search errors "
00257 "will not be displayed at the end of the search.") );
00258
00259
00260 cmbPattern->installEventFilter( this );
00261 leTemplate->installEventFilter( this );
00262 cmbFiles->installEventFilter( this );
00263 cmbDir->comboBox()->installEventFilter( this );
00264
00265 connect( cmbTemplate, TQT_SIGNAL(activated(int)),
00266 TQT_SLOT(templateActivated(int)) );
00267 connect( lbResult, TQT_SIGNAL(selected(const TQString&)),
00268 TQT_SLOT(itemSelected(const TQString&)) );
00269 connect( btnSearch, TQT_SIGNAL(clicked()),
00270 TQT_SLOT(slotSearch()) );
00271 connect( btnClear, TQT_SIGNAL(clicked()),
00272 TQT_SLOT(slotClear()) );
00273 connect( cmbPattern->lineEdit(), TQT_SIGNAL(textChanged ( const TQString & )),
00274 TQT_SLOT( patternTextChanged( const TQString & )));
00275
00276 patternTextChanged( cmbPattern->lineEdit()->text());
00277 }
00278
00279
00280 GrepTool::~GrepTool()
00281 {
00282 delete childproc;
00283 }
00284
00285 void GrepTool::patternTextChanged( const TQString & _text)
00286 {
00287 btnSearch->setEnabled( !_text.isEmpty() );
00288 }
00289
00290 void GrepTool::templateActivated(int index)
00291 {
00292 leTemplate->setText(strTemplate[index]);
00293 }
00294
00295 void GrepTool::itemSelected(const TQString& item)
00296 {
00297 int pos;
00298 TQString filename, linenumber;
00299
00300 TQString str = item;
00301 if ( (pos = str.find(':')) != -1)
00302 {
00303 filename = str.left(pos);
00304 str = str.mid(pos+1);
00305 if ( (pos = str.find(':')) != -1)
00306 {
00307 filename = m_workingDir + TQDir::separator() + filename;
00308 linenumber = str.left(pos);
00309 emit itemSelected(filename,linenumber.toInt()-1);
00310 }
00311 }
00312 }
00313
00314 void GrepTool::processOutput()
00315 {
00316 int pos;
00317 while ( (pos = buf.find('\n')) != -1)
00318 {
00319 TQString item = buf.mid(2,pos-2);
00320 if (!item.isEmpty())
00321 lbResult->insertItem(item);
00322 buf = buf.mid(pos+1);
00323 }
00324 kapp->processEvents();
00325 }
00326
00327 void GrepTool::slotSearch()
00328 {
00329 if ( cmbPattern->currentText().isEmpty() )
00330 {
00331 cmbPattern->setFocus();
00332 return;
00333 }
00334
00335 if ( cmbDir->url().isEmpty() || ! TQDir(cmbDir->url()).exists() )
00336 {
00337 cmbDir->setFocus();
00338 KMessageBox::information( this, i18n(
00339 "You must enter an existing local folder in the 'Folder' entry."),
00340 i18n("Invalid Folder"), "Kate grep tool: invalid folder" );
00341 return;
00342 }
00343
00344 if ( ! leTemplate->text().contains("%s") )
00345 {
00346 leTemplate->setFocus();
00347 return;
00348 }
00349
00350 if ( childproc && childproc->isRunning() )
00351 {
00352 childproc->kill();
00353 return;
00354 }
00355
00356 slotClear ();
00357
00358 m_workingDir = cmbDir->url();
00359
00360 TQString s = cmbPattern->currentText();
00361 if ( ! cbRegex->isChecked() )
00362 s.replace( TQRegExp( "([^\\w'()<>])" ), "\\\\1" );
00363 TQString pattern = leTemplate->text();
00364 pattern.replace( "%s", s );
00365
00366 childproc = new TDEProcess();
00367 childproc->setWorkingDirectory( m_workingDir );
00368 *childproc << "find" << ".";
00369 if (!cbRecursive->isChecked())
00370 *childproc << "-maxdepth" << "1";
00371 if (!cmbFiles->currentText().isEmpty() )
00372 {
00373 TQStringList files = TQStringList::split ( ",", cmbFiles->currentText(), FALSE );
00374 *childproc << "(";
00375 bool first = true;
00376 for ( TQStringList::Iterator it = files.begin(); it != files.end(); ++it )
00377 {
00378 if (!first)
00379 *childproc << "-o";
00380 *childproc << "-name" << (*it);
00381 first = false;
00382 }
00383 *childproc << ")";
00384 }
00385 *childproc << "-exec" << "grep";
00386 if (!cbCasesensitive->isChecked())
00387 *childproc << "-i";
00388 *childproc << "-n" << "-e" << pattern << "{}";
00389 *childproc << "/dev/null";
00390 *childproc << ";";
00391
00392 connect( childproc, TQT_SIGNAL(processExited(TDEProcess *)),
00393 TQT_SLOT(childExited()) );
00394 connect( childproc, TQT_SIGNAL(receivedStdout(TDEProcess *, char *, int)),
00395 TQT_SLOT(receivedOutput(TDEProcess *, char *, int)) );
00396 connect( childproc, TQT_SIGNAL(receivedStderr(TDEProcess *, char *, int)),
00397 TQT_SLOT(receivedErrOutput(TDEProcess *, char *, int)) );
00398
00399
00400 lbResult->setCursor( TQCursor(Qt::WaitCursor) );
00401 btnClear->setEnabled( false );
00402 btnSearch->setGuiItem( KGuiItem(i18n("Cancel"), "button_cancel"));
00403 childproc->start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
00404 }
00405
00406 void GrepTool::slotSearchFor(const TQString &pattern)
00407 {
00408 slotClear();
00409 cmbPattern->setEditText(pattern);
00410 slotSearch();
00411 }
00412
00413 void GrepTool::finish()
00414 {
00415 btnSearch->setEnabled( !cmbPattern->lineEdit()->text().isEmpty() );
00416
00417 buf += '\n';
00418 processOutput();
00419 delete childproc;
00420 childproc = 0;
00421
00422 config->setGroup("GrepTool");
00423
00424 TQString cmbText = cmbPattern->currentText();
00425 bool itemsRemoved = lastSearchItems.remove(cmbText) > 0;
00426 lastSearchItems.prepend(cmbText);
00427 if (itemsRemoved)
00428 {
00429 cmbPattern->removeItem(cmbPattern->currentItem());
00430 }
00431 cmbPattern->insertItem(cmbText, 0);
00432 cmbPattern->setCurrentItem(0);
00433 if (lastSearchItems.count() > 10) {
00434 lastSearchItems.pop_back();
00435 cmbPattern->removeItem(cmbPattern->count() - 1);
00436 }
00437 config->writeEntry("LastSearchItems", lastSearchItems);
00438
00439
00440 cmbText = cmbDir->url();
00441 itemsRemoved = lastSearchPaths.remove(cmbText) > 0;
00442 lastSearchPaths.prepend(cmbText);
00443 if (itemsRemoved)
00444 {
00445 cmbDir->comboBox()->removeItem(cmbDir->comboBox()->currentItem());
00446 }
00447 cmbDir->comboBox()->insertItem(cmbText, 0);
00448 cmbDir->comboBox()->setCurrentItem(0);
00449 if (lastSearchPaths.count() > 10)
00450 {
00451 lastSearchPaths.pop_back();
00452 cmbDir->comboBox()->removeItem(cmbDir->comboBox()->count() - 1);
00453 }
00454 config->writeEntry("LastSearchPaths", lastSearchPaths);
00455
00456
00457 cmbText = cmbFiles->currentText();
00458 itemsRemoved = lastSearchFiles.remove(cmbText) > 0;
00459 lastSearchFiles.prepend(cmbText);
00460 if (itemsRemoved)
00461 {
00462 cmbFiles->removeItem(cmbFiles->currentItem());
00463 }
00464 cmbFiles->insertItem(cmbText, 0);
00465 cmbFiles->setCurrentItem(0);
00466 if (lastSearchFiles.count() > 10) {
00467 lastSearchFiles.pop_back();
00468 cmbFiles->removeItem(cmbFiles->count() - 1);
00469 }
00470 config->writeEntry("LastSearchFiles", lastSearchFiles);
00471
00472 config->writeEntry("Recursive", cbRecursive->isChecked());
00473 config->writeEntry("CaseSensitive", cbCasesensitive->isChecked());
00474 config->writeEntry("Regex", cbRegex->isChecked());
00475 config->writeEntry("HideErrors", cbHideErrors->isChecked());
00476 }
00477
00478 void GrepTool::slotCancel()
00479 {
00480 finish();
00481 }
00482
00483 void GrepTool::childExited()
00484 {
00485
00486 lbResult->unsetCursor();
00487 btnClear->setEnabled( true );
00488 btnSearch->setGuiItem( KGuiItem(i18n("Find"), "edit-find") );
00489
00490 if ( !errbuf.isEmpty())
00491 {
00492 if (!cbHideErrors->isChecked())
00493 {
00494 KMessageBox::information( parentWidget(), i18n("<strong>Error:</strong><p>") + errbuf, i18n("Grep Tool Error") );
00495 }
00496 errbuf.truncate(0);
00497 }
00498 else
00499 finish();
00500 }
00501
00502 void GrepTool::receivedOutput(TDEProcess *, char *buffer, int buflen)
00503 {
00504 buf += TQCString(buffer, buflen+1);
00505 processOutput();
00506 }
00507
00508 void GrepTool::receivedErrOutput(TDEProcess *, char *buffer, int buflen)
00509 {
00510 errbuf += TQCString( buffer, buflen + 1 );
00511 }
00512
00513 void GrepTool::slotClear()
00514 {
00515 finish();
00516 lbResult->clear();
00517 }
00518
00519 void GrepTool::updateDirName(const TQString &dir)
00520 {
00521 if (m_lastUpdatedDir != dir)
00522 {
00523 setDirName (dir);
00524 m_lastUpdatedDir = dir;
00525 }
00526 }
00527
00528 void GrepTool::setDirName(const TQString &dir){
00529 cmbDir->setURL(dir);
00530 }
00531
00532 bool GrepTool::eventFilter( TQObject *o, TQEvent *e )
00533 {
00534 if ( e->type() == TQEvent::KeyPress && (
00535 ((TQKeyEvent*)e)->key() == Qt::Key_Return ||
00536 ((TQKeyEvent*)e)->key() == Qt::Key_Enter ) )
00537 {
00538 slotSearch();
00539 return true;
00540 }
00541
00542 return TQWidget::eventFilter( o, e );
00543 }
00544
00545 void GrepTool::focusInEvent ( TQFocusEvent * ev )
00546 {
00547 TQWidget::focusInEvent(ev);
00548 if (m_fixFocus) {
00549 m_fixFocus = false;
00550 cmbPattern->setFocus();
00551 }
00552 }
00553
00554 void GrepTool::showEvent( TQShowEvent * ev )
00555 {
00556 TQWidget::showEvent(ev);
00557 m_fixFocus = true;
00558 }
00559
00560 #include "kategrepdialog.moc"