21 #include "kategrepdialog.h"
22 #include "katemainwindow.h"
27 #include <tqcheckbox.h>
29 #include <tqlistbox.h>
31 #include <tqwhatsthis.h>
34 #include <tdeapplication.h>
35 #include <tdeaccelmanager.h>
36 #include <kbuttonbox.h>
37 #include <tdefiledialog.h>
38 #include <tdeprocess.h>
39 #include <tdeapplication.h>
40 #include <tdelocale.h>
41 #include <kiconloader.h>
42 #include <tdemessagebox.h>
43 #include <kpushbutton.h>
44 #include <kurlrequester.h>
45 #include <kurlcompletion.h>
46 #include <kcombobox.h>
47 #include <klineedit.h>
49 const char *template_desc[] = {
58 const char *strTemplate[] = {
60 "\\<%s\\>[\t ]*=[^=]",
61 "\\->[\\t ]*\\<%s\\>[\\t ]*(",
62 "[a-z0-9_$]\\+[\\t ]*::[\\t ]*\\<%s\\>[\\t ]*(",
63 "\\<%s\\>[\\t ]*\\->[\\t ]*[a-z0-9_$]\\+[\\t ]*(",
68 GrepTool::GrepTool(TQWidget *parent,
const char *name)
69 : TQWidget(parent, name), m_fixFocus(true), childproc(0)
71 setCaption(i18n(
"Find in Files"));
72 config = TDEGlobal::config();
73 config->setGroup(
"GrepTool");
74 lastSearchItems = config->readListEntry(
"LastSearchItems");
75 lastSearchPaths = config->readListEntry(
"LastSearchPaths");
76 lastSearchFiles = config->readListEntry(
"LastSearchFiles");
78 if( lastSearchFiles.isEmpty() )
82 lastSearchFiles <<
"*.h,*.hxx,*.cpp,*.cc,*.C,*.cxx,*.idl,*.c"
83 <<
"*.cpp,*.cc,*.C,*.cxx,*.c"
88 TQGridLayout *layout =
new TQGridLayout(
this, 6, 3, 4, 4);
89 layout->setColStretch(0, 10);
90 layout->addColSpacing(1, 10);
91 layout->setColStretch(1, 0);
92 layout->setColStretch(2, 1);
93 layout->setRowStretch(1, 0);
94 layout->setRowStretch(2, 10);
95 layout->setRowStretch(4, 0);
97 TQGridLayout *loInput =
new TQGridLayout(4, 2, 4);
98 layout->addLayout(loInput, 0, 0);
99 loInput->setColStretch(0, 0);
100 loInput->setColStretch(1, 20);
102 TQLabel *lPattern =
new TQLabel(i18n(
"Pattern:"),
this);
103 lPattern->setFixedSize(lPattern->sizeHint());
104 loInput->addWidget(lPattern, 0, 0, TQt::AlignRight | TQt::AlignVCenter);
106 TQBoxLayout *loPattern =
new TQHBoxLayout( 4 );
107 loInput->addLayout( loPattern, 0, 1 );
108 cmbPattern =
new KComboBox(
true,
this);
109 cmbPattern->setDuplicatesEnabled(
false);
110 cmbPattern->insertStringList(lastSearchItems);
111 cmbPattern->setEditText(TQString::null);
112 cmbPattern->setInsertionPolicy(TQComboBox::NoInsertion);
113 lPattern->setBuddy(cmbPattern);
114 cmbPattern->setFocus();
115 cmbPattern->setMinimumSize(cmbPattern->sizeHint());
116 loPattern->addWidget( cmbPattern );
118 cbCasesensitive =
new TQCheckBox(i18n(
"Case sensitive"),
this);
119 cbCasesensitive->setMinimumWidth(cbCasesensitive->sizeHint().width());
120 cbCasesensitive->setChecked(config->readBoolEntry(
"CaseSensitive",
true));
121 loPattern->addWidget(cbCasesensitive);
123 cbRegex =
new TQCheckBox( i18n(
"Regular expression"),
this );
124 cbRegex->setMinimumWidth( cbRegex->sizeHint().width() );
125 cbRegex->setChecked( config->readBoolEntry(
"Regex",
true ) );
126 loPattern->addWidget( cbRegex );
127 loPattern->setStretchFactor( cmbPattern, 100 );
129 TQLabel *lTemplate =
new TQLabel(i18n(
"Template:"),
this);
130 lTemplate->setFixedSize(lTemplate->sizeHint());
131 loInput->addWidget(lTemplate, 1, 0, TQt::AlignRight | TQt::AlignVCenter);
133 TQBoxLayout *loTemplate =
new TQHBoxLayout(4);
134 loInput->addLayout(loTemplate, 1, 1);
136 leTemplate =
new KLineEdit(
this);
137 lTemplate->setBuddy(leTemplate);
138 leTemplate->setText(strTemplate[0]);
139 leTemplate->setMinimumSize(leTemplate->sizeHint());
140 loTemplate->addWidget(leTemplate);
142 KComboBox *cmbTemplate =
new KComboBox(
false,
this);
143 cmbTemplate->insertStrList(template_desc);
144 cmbTemplate->adjustSize();
145 cmbTemplate->setFixedSize(cmbTemplate->size());
146 loTemplate->addWidget(cmbTemplate);
148 TQLabel *lFiles =
new TQLabel(i18n(
"Files:"),
this);
149 lFiles->setFixedSize(lFiles->sizeHint());
150 loInput->addWidget(lFiles, 2, 0, TQt::AlignRight | TQt::AlignVCenter);
152 TQBoxLayout *loFiles =
new TQHBoxLayout( 2 );
153 loInput->addLayout( loFiles, 2, 1 );
155 cmbFiles =
new KComboBox(
true,
this);
156 lFiles->setBuddy(cmbFiles->focusProxy());
157 cmbFiles->setMinimumSize(cmbFiles->sizeHint());
158 cmbFiles->setInsertionPolicy(TQComboBox::NoInsertion);
159 cmbFiles->setDuplicatesEnabled(
false);
160 cmbFiles->insertStringList(lastSearchFiles);
161 loFiles->addWidget(cmbFiles);
163 cbHideErrors =
new TQCheckBox( i18n(
"Hide errors"),
this );
164 cbHideErrors->setMinimumWidth( cbHideErrors->sizeHint().width() );
165 cbHideErrors->setChecked( config->readBoolEntry(
"HideErrors",
false ) );
166 loFiles->addWidget(cbHideErrors);
167 loFiles->setStretchFactor(cmbFiles, 100);
169 TQLabel *lDir =
new TQLabel(i18n(
"Folder:"),
this);
170 lDir->setFixedSize(lDir->sizeHint());
171 loInput->addWidget(lDir, 3, 0, TQt::AlignRight | TQt::AlignVCenter);
173 TQBoxLayout *loDir =
new TQHBoxLayout(3);
174 loInput->addLayout(loDir, 3, 1);
176 KComboBox* cmbUrl =
new KComboBox(
true,
this);
177 cmbUrl->setMinimumWidth(80);
178 cmbUrl->setDuplicatesEnabled(
false);
179 cmbUrl->setInsertionPolicy(TQComboBox::NoInsertion);
180 cmbDir =
new KURLRequester( cmbUrl,
this,
"dir combo" );
181 cmbDir->completionObject()->setMode(KURLCompletion::DirCompletion);
182 cmbDir->comboBox()->insertStringList(lastSearchPaths);
183 cmbDir->setMode( KFile::Directory|KFile::LocalOnly );
184 loDir->addWidget(cmbDir, 1);
185 lDir->setBuddy(cmbDir);
187 cbRecursive =
new TQCheckBox(i18n(
"Recursive"),
this);
188 cbRecursive->setMinimumWidth(cbRecursive->sizeHint().width());
189 cbRecursive->setChecked(config->readBoolEntry(
"Recursive",
true));
190 loDir->addWidget(cbRecursive);
192 KButtonBox *actionbox =
new KButtonBox(
this, TQt::Vertical);
193 layout->addWidget(actionbox, 0, 2);
194 actionbox->addStretch();
195 btnSearch =
static_cast<KPushButton*
>(actionbox->addButton(KGuiItem(i18n(
"Find"),
"edit-find")));
196 btnSearch->setDefault(
true);
197 btnClear =
static_cast<KPushButton*
>(actionbox->addButton( KStdGuiItem::clear() ));
198 actionbox->addStretch();
201 lbResult =
new TQListBox(
this);
202 TQFontMetrics rb_fm(lbResult->fontMetrics());
203 layout->addMultiCellWidget(lbResult, 2, 2, 0, 2);
207 TDEAcceleratorManager::manage(
this );
209 TQWhatsThis::add(lPattern,
210 i18n(
"<p>Enter the expression you want to search for here."
211 "<p>If 'regular expression' is unchecked, all characters that are not "
212 "letters in your expression will be escaped with a backslash character."
213 "<p>Possible meta characters are:<br>"
214 "<b>.</b> - Matches any character<br>"
215 "<b>^</b> - Matches the beginning of a line<br>"
216 "<b>$</b> - Matches the end of a line<br>"
217 "<b>\\<</b> - Matches the beginning of a word<br>"
218 "<b>\\></b> - Matches the end of a word"
219 "<p>The following repetition operators exist:<br>"
220 "<b>?</b> - The preceding item is matched at most once<br>"
221 "<b>*</b> - The preceding item is matched zero or more times<br>"
222 "<b>+</b> - The preceding item is matched one or more times<br>"
223 "<b>{<i>n</i>}</b> - The preceding item is matched exactly <i>n</i> times<br>"
224 "<b>{<i>n</i>,}</b> - The preceding item is matched <i>n</i> or more times<br>"
225 "<b>{,<i>n</i>}</b> - The preceding item is matched at most <i>n</i> times<br>"
226 "<b>{<i>n</i>,<i>m</i>}</b> - The preceding item is matched at least <i>n</i>, "
227 "but at most <i>m</i> times."
228 "<p>Furthermore, backreferences to bracketed subexpressions are available "
229 "via the notation <code>\\#</code>."
230 "<p>See the grep(1) documentation for the full documentation."
232 TQWhatsThis::add(lFiles,
233 i18n(
"Enter the file name pattern of the files to search here.\n"
234 "You may give several patterns separated by commas."));
235 TQWhatsThis::add(lTemplate,
236 i18n(
"You can choose a template for the pattern from the combo box\n"
237 "and edit it here. The string %s in the template is replaced\n"
238 "by the pattern input field, resulting in the regular expression\n"
240 TQWhatsThis::add(lDir,
241 i18n(
"Enter the folder which contains the files in which you want to search."));
242 TQWhatsThis::add(cbRecursive,
243 i18n(
"Check this box to search in all subfolders."));
244 TQWhatsThis::add(cbCasesensitive,
245 i18n(
"If this option is enabled (the default), the search will be case sensitive."));
246 TQWhatsThis::add( cbRegex, i18n(
247 "<p>If this is enabled, your pattern will be passed unmodified to "
248 "<em>grep(1)</em>. Otherwise, all characters that are not letters will be "
249 "escaped using a backslash character to prevent grep from interpreting "
250 "them as part of the expression.") );
251 TQWhatsThis::add(lbResult,
252 i18n(
"The results of the grep run are listed here. Select a\n"
253 "filename/line number combination and press Enter or doubleclick\n"
254 "on the item to show the respective line in the editor."));
255 TQWhatsThis::add( cbHideErrors, i18n(
256 "<p>If this is checked, the dialog window showing the search errors "
257 "will not be displayed at the end of the search.") );
260 cmbPattern->installEventFilter(
this );
261 leTemplate->installEventFilter(
this );
262 cmbFiles->installEventFilter(
this );
263 cmbDir->comboBox()->installEventFilter(
this );
265 connect( cmbTemplate, TQ_SIGNAL(activated(
int)),
266 TQ_SLOT(templateActivated(
int)) );
267 connect( lbResult, TQ_SIGNAL(selected(
const TQString&)),
268 TQ_SLOT(itemSelected(
const TQString&)) );
269 connect( btnSearch, TQ_SIGNAL(clicked()),
270 TQ_SLOT(slotSearch()) );
271 connect( btnClear, TQ_SIGNAL(clicked()),
272 TQ_SLOT(slotClear()) );
273 connect( cmbPattern->lineEdit(), TQ_SIGNAL(textChanged (
const TQString & )),
274 TQ_SLOT( patternTextChanged(
const TQString & )));
276 patternTextChanged( cmbPattern->lineEdit()->text());
280 GrepTool::~GrepTool()
285 void GrepTool::patternTextChanged(
const TQString & _text)
287 btnSearch->setEnabled( !_text.isEmpty() );
290 void GrepTool::templateActivated(
int index)
292 leTemplate->setText(strTemplate[index]);
295 void GrepTool::itemSelected(
const TQString& item)
298 TQString filename, linenumber;
301 if ( (pos = str.find(
':')) != -1)
303 filename = str.left(pos);
304 str = str.mid(pos+1);
305 if ( (pos = str.find(
':')) != -1)
307 filename = m_workingDir + TQDir::separator() + filename;
308 linenumber = str.left(pos);
309 emit itemSelected(filename,linenumber.toInt()-1);
314 void GrepTool::processOutput()
317 while ( (pos = buf.find(
'\n')) != -1)
319 TQString item = buf.mid(2,pos-2);
321 lbResult->insertItem(item);
322 buf = buf.mid(pos+1);
324 kapp->processEvents();
327 void GrepTool::slotSearch()
329 if ( cmbPattern->currentText().isEmpty() )
331 cmbPattern->setFocus();
335 if ( cmbDir->url().isEmpty() || ! TQDir(cmbDir->url()).exists() )
338 KMessageBox::information(
this, i18n(
339 "You must enter an existing local folder in the 'Folder' entry."),
340 i18n(
"Invalid Folder"),
"Kate grep tool: invalid folder" );
344 if ( ! leTemplate->text().contains(
"%s") )
346 leTemplate->setFocus();
350 if ( childproc && childproc->isRunning() )
358 m_workingDir = cmbDir->url();
360 TQString s = cmbPattern->currentText();
361 if ( ! cbRegex->isChecked() )
362 s.replace( TQRegExp(
"([^\\w'()<>])" ),
"\\\\1" );
363 TQString pattern = leTemplate->text();
364 pattern.replace(
"%s", s );
366 childproc =
new TDEProcess();
367 childproc->setWorkingDirectory( m_workingDir );
368 *childproc <<
"find" <<
".";
369 if (!cbRecursive->isChecked())
370 *childproc <<
"-maxdepth" <<
"1";
371 if (!cmbFiles->currentText().isEmpty() )
373 TQStringList files = TQStringList::split (
",", cmbFiles->currentText(), FALSE );
376 for ( TQStringList::Iterator it = files.begin(); it != files.end(); ++it )
380 *childproc <<
"-name" << (*it);
385 *childproc <<
"-exec" <<
"grep";
386 if (!cbCasesensitive->isChecked())
388 *childproc <<
"-n" <<
"-e" << pattern <<
"{}";
389 *childproc <<
"/dev/null";
392 connect( childproc, TQ_SIGNAL(processExited(TDEProcess *)),
393 TQ_SLOT(childExited()) );
394 connect( childproc, TQ_SIGNAL(receivedStdout(TDEProcess *,
char *,
int)),
395 TQ_SLOT(receivedOutput(TDEProcess *,
char *,
int)) );
396 connect( childproc, TQ_SIGNAL(receivedStderr(TDEProcess *,
char *,
int)),
397 TQ_SLOT(receivedErrOutput(TDEProcess *,
char *,
int)) );
400 lbResult->setCursor( TQCursor(TQt::WaitCursor) );
401 btnClear->setEnabled(
false );
402 btnSearch->setGuiItem( KGuiItem(i18n(
"Cancel"),
"button_cancel"));
403 childproc->start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
406 void GrepTool::slotSearchFor(
const TQString &pattern)
409 cmbPattern->setEditText(pattern);
413 void GrepTool::finish()
415 btnSearch->setEnabled( !cmbPattern->lineEdit()->text().isEmpty() );
422 config->setGroup(
"GrepTool");
424 TQString cmbText = cmbPattern->currentText();
425 bool itemsRemoved = lastSearchItems.remove(cmbText) > 0;
426 lastSearchItems.prepend(cmbText);
429 cmbPattern->removeItem(cmbPattern->currentItem());
431 cmbPattern->insertItem(cmbText, 0);
432 cmbPattern->setCurrentItem(0);
433 if (lastSearchItems.count() > 10) {
434 lastSearchItems.pop_back();
435 cmbPattern->removeItem(cmbPattern->count() - 1);
437 config->writeEntry(
"LastSearchItems", lastSearchItems);
440 cmbText = cmbDir->url();
441 itemsRemoved = lastSearchPaths.remove(cmbText) > 0;
442 lastSearchPaths.prepend(cmbText);
445 cmbDir->comboBox()->removeItem(cmbDir->comboBox()->currentItem());
447 cmbDir->comboBox()->insertItem(cmbText, 0);
448 cmbDir->comboBox()->setCurrentItem(0);
449 if (lastSearchPaths.count() > 10)
451 lastSearchPaths.pop_back();
452 cmbDir->comboBox()->removeItem(cmbDir->comboBox()->count() - 1);
454 config->writeEntry(
"LastSearchPaths", lastSearchPaths);
457 cmbText = cmbFiles->currentText();
458 itemsRemoved = lastSearchFiles.remove(cmbText) > 0;
459 lastSearchFiles.prepend(cmbText);
462 cmbFiles->removeItem(cmbFiles->currentItem());
464 cmbFiles->insertItem(cmbText, 0);
465 cmbFiles->setCurrentItem(0);
466 if (lastSearchFiles.count() > 10) {
467 lastSearchFiles.pop_back();
468 cmbFiles->removeItem(cmbFiles->count() - 1);
470 config->writeEntry(
"LastSearchFiles", lastSearchFiles);
472 config->writeEntry(
"Recursive", cbRecursive->isChecked());
473 config->writeEntry(
"CaseSensitive", cbCasesensitive->isChecked());
474 config->writeEntry(
"Regex", cbRegex->isChecked());
475 config->writeEntry(
"HideErrors", cbHideErrors->isChecked());
478 void GrepTool::slotCancel()
483 void GrepTool::childExited()
486 lbResult->unsetCursor();
487 btnClear->setEnabled(
true );
488 btnSearch->setGuiItem( KGuiItem(i18n(
"Find"),
"edit-find") );
490 if ( !errbuf.isEmpty())
492 if (!cbHideErrors->isChecked())
494 KMessageBox::information( parentWidget(), i18n(
"<strong>Error:</strong><p>") + errbuf, i18n(
"Grep Tool Error") );
502 void GrepTool::receivedOutput(TDEProcess *,
char *buffer,
int buflen)
504 buf += TQCString(buffer, buflen+1);
508 void GrepTool::receivedErrOutput(TDEProcess *,
char *buffer,
int buflen)
510 errbuf += TQCString( buffer, buflen + 1 );
513 void GrepTool::slotClear()
519 void GrepTool::updateDirName(
const TQString &dir)
521 if (m_lastUpdatedDir != dir)
524 m_lastUpdatedDir = dir;
528 void GrepTool::setDirName(
const TQString &dir){
532 bool GrepTool::eventFilter( TQObject *o, TQEvent *e )
534 if ( e->type() == TQEvent::KeyPress && (
535 ((TQKeyEvent*)e)->key() == TQt::Key_Return ||
536 ((TQKeyEvent*)e)->key() == TQt::Key_Enter ) )
542 return TQWidget::eventFilter( o, e );
545 void GrepTool::focusInEvent ( TQFocusEvent * ev )
547 TQWidget::focusInEvent(ev);
550 cmbPattern->setFocus();
554 void GrepTool::showEvent( TQShowEvent * ev )
556 TQWidget::showEvent(ev);
560 #include "kategrepdialog.moc"