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>
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, Qt::AlignRight | Qt::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, Qt::AlignRight | Qt::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, Qt::AlignRight | Qt::AlignVCenter);
152 cmbFiles =
new KComboBox(
true,
this);
153 lFiles->setBuddy(TQT_TQWIDGET(cmbFiles->focusProxy()));
154 cmbFiles->setMinimumSize(cmbFiles->sizeHint());
155 cmbFiles->setInsertionPolicy(TQComboBox::NoInsertion);
156 cmbFiles->setDuplicatesEnabled(
false);
157 cmbFiles->insertStringList(lastSearchFiles);
158 loInput->addWidget(cmbFiles, 2, 1);
160 TQLabel *lDir =
new TQLabel(i18n(
"Folder:"),
this);
161 lDir->setFixedSize(lDir->sizeHint());
162 loInput->addWidget(lDir, 3, 0, Qt::AlignRight | Qt::AlignVCenter);
164 TQBoxLayout *loDir =
new TQHBoxLayout(3);
165 loInput->addLayout(loDir, 3, 1);
167 KComboBox* cmbUrl =
new KComboBox(
true,
this);
168 cmbUrl->setMinimumWidth(80);
169 cmbUrl->setDuplicatesEnabled(
false);
170 cmbUrl->setInsertionPolicy(TQComboBox::NoInsertion);
171 cmbDir =
new KURLRequester( cmbUrl,
this,
"dir combo" );
172 cmbDir->completionObject()->setMode(KURLCompletion::DirCompletion);
173 cmbDir->comboBox()->insertStringList(lastSearchPaths);
174 cmbDir->setMode( KFile::Directory|KFile::LocalOnly );
175 loDir->addWidget(cmbDir, 1);
176 lDir->setBuddy(cmbDir);
178 cbRecursive =
new TQCheckBox(i18n(
"Recursive"),
this);
179 cbRecursive->setMinimumWidth(cbRecursive->sizeHint().width());
180 cbRecursive->setChecked(config->readBoolEntry(
"Recursive",
true));
181 loDir->addWidget(cbRecursive);
183 KButtonBox *actionbox =
new KButtonBox(
this, Qt::Vertical);
184 layout->addWidget(actionbox, 0, 2);
185 actionbox->addStretch();
186 btnSearch =
static_cast<KPushButton*
>(actionbox->addButton(KGuiItem(i18n(
"Find"),
"edit-find")));
187 btnSearch->setDefault(
true);
188 btnClear =
static_cast<KPushButton*
>(actionbox->addButton( KStdGuiItem::clear() ));
189 actionbox->addStretch();
192 lbResult =
new TQListBox(
this);
193 TQFontMetrics rb_fm(lbResult->fontMetrics());
194 layout->addMultiCellWidget(lbResult, 2, 2, 0, 2);
198 TDEAcceleratorManager::manage(
this );
200 TQWhatsThis::add(lPattern,
201 i18n(
"<p>Enter the expression you want to search for here."
202 "<p>If 'regular expression' is unchecked, any non-space letters in your "
203 "expression will be escaped with a backslash character."
204 "<p>Possible meta characters are:<br>"
205 "<b>.</b> - Matches any character<br>"
206 "<b>^</b> - Matches the beginning of a line<br>"
207 "<b>$</b> - Matches the end of a line<br>"
208 "<b>\\<</b> - Matches the beginning of a word<br>"
209 "<b>\\></b> - Matches the end of a word"
210 "<p>The following repetition operators exist:<br>"
211 "<b>?</b> - The preceding item is matched at most once<br>"
212 "<b>*</b> - The preceding item is matched zero or more times<br>"
213 "<b>+</b> - The preceding item is matched one or more times<br>"
214 "<b>{<i>n</i>}</b> - The preceding item is matched exactly <i>n</i> times<br>"
215 "<b>{<i>n</i>,}</b> - The preceding item is matched <i>n</i> or more times<br>"
216 "<b>{,<i>n</i>}</b> - The preceding item is matched at most <i>n</i> times<br>"
217 "<b>{<i>n</i>,<i>m</i>}</b> - The preceding item is matched at least <i>n</i>, "
218 "but at most <i>m</i> times."
219 "<p>Furthermore, backreferences to bracketed subexpressions are available "
220 "via the notation <code>\\#</code>."
221 "<p>See the grep(1) documentation for the full documentation."
223 TQWhatsThis::add(lFiles,
224 i18n(
"Enter the file name pattern of the files to search here.\n"
225 "You may give several patterns separated by commas."));
226 TQWhatsThis::add(lTemplate,
227 i18n(
"You can choose a template for the pattern from the combo box\n"
228 "and edit it here. The string %s in the template is replaced\n"
229 "by the pattern input field, resulting in the regular expression\n"
231 TQWhatsThis::add(lDir,
232 i18n(
"Enter the folder which contains the files in which you want to search."));
233 TQWhatsThis::add(cbRecursive,
234 i18n(
"Check this box to search in all subfolders."));
235 TQWhatsThis::add(cbCasesensitive,
236 i18n(
"If this option is enabled (the default), the search will be case sensitive."));
237 TQWhatsThis::add( cbRegex, i18n(
238 "<p>If this is enabled, your pattern will be passed unmodified to "
239 "<em>grep(1)</em>. Otherwise, all characters that are not letters will be "
240 "escaped using a backslash character to prevent grep from interpreting "
241 "them as part of the expression.") );
242 TQWhatsThis::add(lbResult,
243 i18n(
"The results of the grep run are listed here. Select a\n"
244 "filename/line number combination and press Enter or doubleclick\n"
245 "on the item to show the respective line in the editor."));
248 cmbPattern->installEventFilter(
this );
249 leTemplate->installEventFilter(
this );
250 cmbFiles->installEventFilter(
this );
251 cmbDir->comboBox()->installEventFilter(
this );
253 connect( cmbTemplate, TQT_SIGNAL(activated(
int)),
254 TQT_SLOT(templateActivated(
int)) );
255 connect( lbResult, TQT_SIGNAL(selected(
const TQString&)),
256 TQT_SLOT(itemSelected(
const TQString&)) );
257 connect( btnSearch, TQT_SIGNAL(clicked()),
258 TQT_SLOT(slotSearch()) );
259 connect( btnClear, TQT_SIGNAL(clicked()),
260 TQT_SLOT(slotClear()) );
261 connect( cmbPattern->lineEdit(), TQT_SIGNAL(textChanged (
const TQString & )),
262 TQT_SLOT( patternTextChanged(
const TQString & )));
264 patternTextChanged( cmbPattern->lineEdit()->text());
268 GrepTool::~GrepTool()
273 void GrepTool::patternTextChanged(
const TQString & _text)
275 btnSearch->setEnabled( !_text.isEmpty() );
278 void GrepTool::templateActivated(
int index)
280 leTemplate->setText(strTemplate[index]);
283 void GrepTool::itemSelected(
const TQString& item)
286 TQString filename, linenumber;
289 if ( (pos = str.find(
':')) != -1)
291 filename = str.left(pos);
292 str = str.mid(pos+1);
293 if ( (pos = str.find(
':')) != -1)
295 filename = m_workingDir + TQDir::separator() + filename;
296 linenumber = str.left(pos);
297 emit itemSelected(filename,linenumber.toInt()-1);
302 void GrepTool::processOutput()
305 while ( (pos = buf.find(
'\n')) != -1)
307 TQString item = buf.mid(2,pos-2);
309 lbResult->insertItem(item);
310 buf = buf.mid(pos+1);
312 kapp->processEvents();
315 void GrepTool::slotSearch()
317 if ( cmbPattern->currentText().isEmpty() )
319 cmbPattern->setFocus();
323 if ( cmbDir->url().isEmpty() || ! TQDir(cmbDir->url()).exists() )
326 KMessageBox::information(
this, i18n(
327 "You must enter an existing local folder in the 'Folder' entry."),
328 i18n(
"Invalid Folder"),
"Kate grep tool: invalid folder" );
332 if ( ! leTemplate->text().contains(
"%s") )
334 leTemplate->setFocus();
338 if ( childproc && childproc->isRunning() )
346 m_workingDir = cmbDir->url();
348 TQString s = cmbPattern->currentText();
349 if ( ! cbRegex->isChecked() )
350 s.replace( TQRegExp(
"([^\\w'()<>])" ),
"\\\\1" );
351 TQString pattern = leTemplate->text();
352 pattern.replace(
"%s", s );
354 childproc =
new TDEProcess();
355 childproc->setWorkingDirectory( m_workingDir );
356 *childproc <<
"find" <<
".";
357 if (!cbRecursive->isChecked())
358 *childproc <<
"-maxdepth" <<
"1";
359 if (!cmbFiles->currentText().isEmpty() )
361 TQStringList files = TQStringList::split (
",", cmbFiles->currentText(), FALSE );
364 for ( TQStringList::Iterator it = files.begin(); it != files.end(); ++it )
368 *childproc <<
"-name" << (*it);
373 *childproc <<
"-exec" <<
"grep";
374 if (!cbCasesensitive->isChecked())
376 *childproc <<
"-n" <<
"-e" << pattern <<
"{}";
377 *childproc <<
"/dev/null";
380 connect( childproc, TQT_SIGNAL(processExited(TDEProcess *)),
381 TQT_SLOT(childExited()) );
382 connect( childproc, TQT_SIGNAL(receivedStdout(TDEProcess *,
char *,
int)),
383 TQT_SLOT(receivedOutput(TDEProcess *,
char *,
int)) );
384 connect( childproc, TQT_SIGNAL(receivedStderr(TDEProcess *,
char *,
int)),
385 TQT_SLOT(receivedErrOutput(TDEProcess *,
char *,
int)) );
388 lbResult->setCursor( TQCursor(Qt::WaitCursor) );
389 btnClear->setEnabled(
false );
390 btnSearch->setGuiItem( KGuiItem(i18n(
"Cancel"),
"button_cancel"));
391 childproc->start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
394 void GrepTool::slotSearchFor(
const TQString &pattern)
397 cmbPattern->setEditText(pattern);
401 void GrepTool::finish()
403 btnSearch->setEnabled( !cmbPattern->lineEdit()->text().isEmpty() );
410 config->setGroup(
"GrepTool");
412 TQString cmbText = cmbPattern->currentText();
413 bool itemsRemoved = lastSearchItems.remove(cmbText) > 0;
414 lastSearchItems.prepend(cmbText);
417 cmbPattern->removeItem(cmbPattern->currentItem());
419 cmbPattern->insertItem(cmbText, 0);
420 cmbPattern->setCurrentItem(0);
421 if (lastSearchItems.count() > 10) {
422 lastSearchItems.pop_back();
423 cmbPattern->removeItem(cmbPattern->count() - 1);
425 config->writeEntry(
"LastSearchItems", lastSearchItems);
428 cmbText = cmbDir->url();
429 itemsRemoved = lastSearchPaths.remove(cmbText) > 0;
430 lastSearchPaths.prepend(cmbText);
433 cmbDir->comboBox()->removeItem(cmbDir->comboBox()->currentItem());
435 cmbDir->comboBox()->insertItem(cmbText, 0);
436 cmbDir->comboBox()->setCurrentItem(0);
437 if (lastSearchPaths.count() > 10)
439 lastSearchPaths.pop_back();
440 cmbDir->comboBox()->removeItem(cmbDir->comboBox()->count() - 1);
442 config->writeEntry(
"LastSearchPaths", lastSearchPaths);
445 cmbText = cmbFiles->currentText();
446 itemsRemoved = lastSearchFiles.remove(cmbText) > 0;
447 lastSearchFiles.prepend(cmbText);
450 cmbFiles->removeItem(cmbFiles->currentItem());
452 cmbFiles->insertItem(cmbText, 0);
453 cmbFiles->setCurrentItem(0);
454 if (lastSearchFiles.count() > 10) {
455 lastSearchFiles.pop_back();
456 cmbFiles->removeItem(cmbFiles->count() - 1);
458 config->writeEntry(
"LastSearchFiles", lastSearchFiles);
460 config->writeEntry(
"Recursive", cbRecursive->isChecked());
461 config->writeEntry(
"CaseSensitive", cbCasesensitive->isChecked());
462 config->writeEntry(
"Regex", cbRegex->isChecked());
465 void GrepTool::slotCancel()
470 void GrepTool::childExited()
473 lbResult->unsetCursor();
474 btnClear->setEnabled(
true );
475 btnSearch->setGuiItem( KGuiItem(i18n(
"Find"),
"edit-find") );
477 if ( ! errbuf.isEmpty() )
479 KMessageBox::information( parentWidget(), i18n(
"<strong>Error:</strong><p>") + errbuf, i18n(
"Grep Tool Error") );
486 void GrepTool::receivedOutput(TDEProcess *,
char *buffer,
int buflen)
488 buf += TQCString(buffer, buflen+1);
492 void GrepTool::receivedErrOutput(TDEProcess *,
char *buffer,
int buflen)
494 errbuf += TQCString( buffer, buflen + 1 );
497 void GrepTool::slotClear()
503 void GrepTool::updateDirName(
const TQString &dir)
505 if (m_lastUpdatedDir != dir)
508 m_lastUpdatedDir = dir;
512 void GrepTool::setDirName(
const TQString &dir){
516 bool GrepTool::eventFilter( TQObject *o, TQEvent *e )
518 if ( e->type() == TQEvent::KeyPress && (
519 ((TQKeyEvent*)e)->key() == Qt::Key_Return ||
520 ((TQKeyEvent*)e)->key() == Qt::Key_Enter ) )
526 return TQWidget::eventFilter( o, e );
529 void GrepTool::focusInEvent ( TQFocusEvent * ev )
531 TQWidget::focusInEvent(ev);
534 cmbPattern->setFocus();
538 void GrepTool::showEvent( TQShowEvent * ev )
540 TQWidget::showEvent(ev);
544 #include "kategrepdialog.moc"