Commit 2538f800 authored by Eike Ziller's avatar Eike Ziller
Browse files

Implement "Search Again" for file/text searches



Task-number: QTCREATORBUG-621
Change-Id: I6fb7df3d943353497b73b9813684ae973b708913
Reviewed-by: default avatarLeandro Melo <leandro.melo@nokia.com>
parent e1c388f1
......@@ -211,7 +211,8 @@ using namespace Find::Internal;
SearchResultWidget::SearchResultWidget(QWidget *parent) :
QWidget(parent),
m_count(0),
m_isShowingReplaceUI(false)
m_isShowingReplaceUI(false),
m_searchAgainSupported(false)
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
......@@ -259,21 +260,30 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
m_cancelButton->setText(tr("Cancel"));
m_cancelButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(cancel()));
m_searchAgainButton = new QToolButton(topWidget);
m_searchAgainButton->setToolTip(tr("Repeat the search with same parameters"));
m_searchAgainButton->setText(tr("Search again"));
m_searchAgainButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_searchAgainButton->setVisible(false);
connect(m_searchAgainButton, SIGNAL(clicked()), this, SLOT(searchAgain()));
m_replaceLabel = new QLabel(tr("Replace with:"), topWidget);
m_replaceTextEdit = new WideEnoughLineEdit(topWidget);
m_replaceTextEdit->setMinimumWidth(120);
m_replaceTextEdit->setEnabled(false);
m_replaceTextEdit->setTabOrder(m_replaceTextEdit, m_searchResultTreeView);
m_replaceButton = new QToolButton(topWidget);
m_replaceButton->setToolTip(tr("Replace all occurrences"));
m_replaceButton->setText(tr("Replace"));
m_replaceButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_replaceTextEdit->setTabOrder(m_replaceTextEdit, m_searchResultTreeView);
m_replaceButton->setEnabled(false);
m_matchesFoundLabel = new QLabel(topWidget);
updateMatchesFoundLabel();
topLayout->addWidget(m_descriptionContainer);
topLayout->addWidget(m_cancelButton);
topLayout->addWidget(m_searchAgainButton);
topLayout->addWidget(m_replaceLabel);
topLayout->addWidget(m_replaceTextEdit);
topLayout->addWidget(m_replaceButton);
......@@ -447,11 +457,29 @@ void SearchResultWidget::goToPrevious()
}
}
void SearchResultWidget::reset()
{
m_replaceTextEdit->setEnabled(false);
m_replaceButton->setEnabled(false);
m_searchResultTreeView->clear();
m_count = 0;
m_cancelButton->setVisible(true);
m_searchAgainButton->setVisible(false);
updateMatchesFoundLabel();
}
void SearchResultWidget::setSearchAgainSupported(bool supported)
{
m_searchAgainSupported = supported;
m_searchAgainButton->setVisible(supported && !m_cancelButton->isVisible());
}
void SearchResultWidget::finishSearch()
{
m_replaceTextEdit->setEnabled(m_count > 0);
m_replaceButton->setEnabled(m_count > 0);
m_cancelButton->setVisible(false);
m_searchAgainButton->setVisible(m_searchAgainSupported);
}
void SearchResultWidget::hideNoUndoWarning()
......@@ -481,6 +509,11 @@ void SearchResultWidget::cancel()
emit cancelled();
}
void SearchResultWidget::searchAgain()
{
emit searchAgainRequested();
}
bool SearchResultWidget::showWarningMessage() const
{
if (m_dontAskAgainGroup.isEmpty())
......
......@@ -83,12 +83,17 @@ public:
void goToNext();
void goToPrevious();
void reset();
void setSearchAgainSupported(bool supported);
public slots:
void finishSearch();
signals:
void activated(const Find::SearchResultItem &item);
void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems);
void searchAgainRequested();
void cancelled();
void visibilityChanged(bool visible);
......@@ -99,6 +104,7 @@ private slots:
void handleJumpToSearchResult(const SearchResultItem &item);
void handleReplaceButton();
void cancel();
void searchAgain();
private:
bool showWarningMessage() const;
......@@ -115,6 +121,8 @@ private:
QLabel *m_replaceLabel;
QLineEdit *m_replaceTextEdit;
QToolButton *m_replaceButton;
QToolButton *m_searchAgainButton;
bool m_searchAgainSupported;
QWidget *m_descriptionContainer;
QLabel *m_label;
QLabel *m_searchTerm;
......
......@@ -549,6 +549,8 @@ SearchResult::SearchResult(SearchResultWidget *widget)
this, SIGNAL(cancelled()));
connect(widget, SIGNAL(visibilityChanged(bool)),
this, SIGNAL(visibilityChanged(bool)));
connect(widget, SIGNAL(searchAgainRequested()),
this, SIGNAL(searchAgainRequested()));
}
/*!
......@@ -587,6 +589,11 @@ int SearchResult::count() const
return m_widget->count();
}
void SearchResult::setSearchAgainSupported(bool supported)
{
m_widget->setSearchAgainSupported(supported);
}
/*!
\fn void SearchResult::addResult(const QString &fileName, int lineNumber, const QString &rowText, int searchTermStart, int searchTermLength, const QVariant &userData)
\brief Adds a single result line to the search results.
......@@ -640,6 +647,14 @@ void SearchResult::setTextToReplace(const QString &textToReplace)
m_widget->setTextToReplace(textToReplace);
}
/*!
* \brief Removes all search results.
*/
void SearchResult::reset()
{
m_widget->reset();
}
} // namespace Find
#include "searchresultwindow.moc"
......@@ -99,6 +99,7 @@ public:
QVariant userData() const;
QString textToReplace() const;
int count() const;
void setSearchAgainSupported(bool supported);
public slots:
void addResult(const QString &fileName, int lineNumber, const QString &lineText,
......@@ -106,6 +107,7 @@ public slots:
void addResults(const QList<SearchResultItem> &items, AddMode mode);
void finishSearch();
void setTextToReplace(const QString &textToReplace);
void reset();
signals:
void activated(const Find::SearchResultItem &item);
......@@ -113,6 +115,7 @@ signals:
void cancelled();
void visibilityChanged(bool visible);
void countChanged(int count);
void searchAgainRequested();
private:
SearchResult(Internal::SearchResultWidget *widget);
......
......@@ -77,22 +77,24 @@ bool AllProjectsFind::isEnabled() const
&& m_plugin->session()->projects().count() > 0;
}
QList<Project *> AllProjectsFind::projects() const
Utils::FileIterator *AllProjectsFind::files(const QStringList &nameFilters,
const QVariant &additionalParameters) const
{
Q_ASSERT(m_plugin->session());
return m_plugin->session()->projects();
Q_UNUSED(additionalParameters)
QTC_ASSERT(m_plugin->session(), return new Utils::FileIterator());
return filesForProjects(nameFilters, m_plugin->session()->projects());
}
Utils::FileIterator *AllProjectsFind::files() const
Utils::FileIterator *AllProjectsFind::filesForProjects(const QStringList &nameFilters,
const QList<Project *> &projects) const
{
QList<QRegExp> filterRegs;
QStringList nameFilters = fileNameFilters();
foreach (const QString &filter, nameFilters) {
filterRegs << QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard);
}
QMap<QString, QTextCodec *> openEditorEncodings = TextEditor::ITextEditor::openedTextEditorsEncodings();
QMap<QString, QTextCodec *> encodings;
foreach (const Project *project, projects()) {
foreach (const Project *project, projects) {
QStringList projectFiles = project->files(Project::AllFiles);
QStringList filteredFiles;
if (!filterRegs.isEmpty()) {
......@@ -117,6 +119,11 @@ Utils::FileIterator *AllProjectsFind::files() const
return new Utils::FileIterator(encodings.keys(), encodings.values());
}
QVariant AllProjectsFind::additionalParameters() const
{
return QVariant();
}
QString AllProjectsFind::label() const
{
return tr("All Projects:");
......
......@@ -61,8 +61,12 @@ public:
void readSettings(QSettings *settings);
protected:
virtual QList<Project *> projects() const;
Utils::FileIterator *files() const;
Utils::FileIterator *files(const QStringList &nameFilters,
const QVariant &additionalParameters) const;
Utils::FileIterator *filesForProjects(const QStringList &nameFilters,
const QList<Project *> &projects) const;
QVariant additionalParameters() const;
QString label() const;
QString toolTip() const;
......
......@@ -34,7 +34,9 @@
#include "projectexplorer.h"
#include "project.h"
#include "session.h"
#include <coreplugin/ifile.h>
#include <utils/qtcassert.h>
#include <QtCore/QDebug>
......@@ -70,14 +72,31 @@ bool CurrentProjectFind::isEnabled() const
return m_plugin->currentProject() != 0 && BaseFileFind::isEnabled();
}
QList<Project *> CurrentProjectFind::projects() const
QVariant CurrentProjectFind::additionalParameters() const
{
return QList<Project *>() << m_plugin->currentProject();
if (m_plugin->currentProject() && m_plugin->currentProject()->file())
return qVariantFromValue(m_plugin->currentProject()->file()->fileName());
return QVariant();
}
Utils::FileIterator *CurrentProjectFind::files(const QStringList &nameFilters,
const QVariant &additionalParameters) const
{
QTC_ASSERT(m_plugin->session(), return new Utils::FileIterator());
QTC_ASSERT(additionalParameters.isValid(), return new Utils::FileIterator());
QList<Project *> allProjects = m_plugin->session()->projects();
QString projectFile = additionalParameters.toString();
foreach (Project *project, allProjects) {
if (project->file() && projectFile == project->file()->fileName())
return filesForProjects(nameFilters, QList<Project *>() << project);
}
return new Utils::FileIterator();
}
QString CurrentProjectFind::label() const
{
return tr("Project '%1':").arg(projects().first()->displayName());
QTC_ASSERT(m_plugin->currentProject(), return QString());
return tr("Project '%1':").arg(m_plugin->currentProject()->displayName());
}
void CurrentProjectFind::writeSettings(QSettings *settings)
......
......@@ -62,7 +62,9 @@ public:
void readSettings(QSettings *settings);
protected:
QList<Project *> projects() const;
Utils::FileIterator *files(const QStringList &nameFilters,
const QVariant &additionalParameters) const;
QVariant additionalParameters() const;
QString label() const;
private:
......
......@@ -112,40 +112,54 @@ void BaseFileFind::runNewSearch(const QString &txt, Find::FindFlags findFlags,
m_currentFindSupport = 0;
if (m_filterCombo)
updateComboEntries(m_filterCombo, true);
QFutureWatcher<FileSearchResultList> *watcher = new QFutureWatcher<FileSearchResultList>();
watcher->setPendingResultsLimit(1);
connect(watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
connect(watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
SearchResult *search = Find::SearchResultWindow::instance()->startNewSearch(label(),
toolTip().arg(Find::IFindFilter::descriptionForFindFlags(findFlags)),
txt, searchMode, QString::fromLatin1("TextEditor"));
m_watchers.insert(watcher, search);
search->setTextToReplace(txt);
QVariantList searchParameters;
searchParameters << qVariantFromValue(txt) << qVariantFromValue(findFlags);
search->setUserData(searchParameters);
search->setSearchAgainSupported(true);
FileFindParameters parameters;
parameters.text = txt;
parameters.flags = findFlags;
parameters.nameFilters = fileNameFilters();
parameters.additionalParameters = additionalParameters();
search->setUserData(qVariantFromValue(parameters));
connect(search, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem)));
if (searchMode == SearchResultWindow::SearchAndReplace) {
connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
this, SLOT(doReplace(QString,QList<Find::SearchResultItem>)));
}
connect(search, SIGNAL(visibilityChanged(bool)), this, SLOT(hideHighlightAll(bool)));
connect(search, SIGNAL(cancelled()), this, SLOT(cancel()));
connect(search, SIGNAL(searchAgainRequested()), this, SLOT(searchAgain()));
runSearch(search);
}
void BaseFileFind::runSearch(Find::SearchResult *search)
{
FileFindParameters parameters = search->userData().value<FileFindParameters>();
CountingLabel *label = new CountingLabel;
connect(search, SIGNAL(countChanged(int)), label, SLOT(updateCount(int)));
Find::SearchResultWindow::instance()->popup(true);
if (findFlags & Find::FindRegularExpression) {
watcher->setFuture(Utils::findInFilesRegExp(txt, files(),
textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
QFutureWatcher<FileSearchResultList> *watcher = new QFutureWatcher<FileSearchResultList>();
m_watchers.insert(watcher, search);
watcher->setPendingResultsLimit(1);
connect(watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
connect(watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
if (parameters.flags & Find::FindRegularExpression) {
watcher->setFuture(Utils::findInFilesRegExp(parameters.text,
files(parameters.nameFilters, parameters.additionalParameters),
textDocumentFlagsForFindFlags(parameters.flags),
ITextEditor::openedTextEditorsContents()));
} else {
watcher->setFuture(Utils::findInFiles(txt, files(),
textDocumentFlagsForFindFlags(findFlags), ITextEditor::openedTextEditorsContents()));
watcher->setFuture(Utils::findInFiles(parameters.text,
files(parameters.nameFilters, parameters.additionalParameters),
textDocumentFlagsForFindFlags(parameters.flags),
ITextEditor::openedTextEditorsContents()));
}
connect(search, SIGNAL(cancelled()), this, SLOT(cancel()));
Core::FutureProgress *progress =
Core::ICore::instance()->progressManager()->addTask(watcher->future(),
tr("Search"),
Constants::TASK_SEARCH);
progress->setWidget(label);
connect(progress, SIGNAL(clicked()), Find::SearchResultWindow::instance(), SLOT(popup()));
}
......@@ -302,10 +316,9 @@ void BaseFileFind::openEditor(const Find::SearchResultItem &item)
// highlight results
if (IFindSupport *findSupport = Aggregation::query<IFindSupport>(openedEditor->widget())) {
if (result) {
QVariantList userData = result->userData().value<QVariantList>();
QTC_ASSERT(userData.size() != 0, return);
FileFindParameters parameters = result->userData().value<FileFindParameters>();
m_currentFindSupport = findSupport;
m_currentFindSupport->highlightAll(userData.at(0).toString(), userData.at(1).value<FindFlags>());
m_currentFindSupport->highlightAll(parameters.text, parameters.flags);
}
}
}
......@@ -316,6 +329,13 @@ void BaseFileFind::hideHighlightAll(bool visible)
m_currentFindSupport->clearResults();
}
void BaseFileFind::searchAgain()
{
SearchResult *search = qobject_cast<SearchResult *>(sender());
search->reset();
runSearch(search);
}
QStringList BaseFileFind::replaceAll(const QString &text,
const QList<Find::SearchResultItem> &items)
{
......
......@@ -77,7 +77,9 @@ public:
const QList<Find::SearchResultItem> &items);
protected:
virtual Utils::FileIterator *files() const = 0;
virtual Utils::FileIterator *files(const QStringList &nameFilters,
const QVariant &additionalParameters) const = 0;
virtual QVariant additionalParameters() const = 0;
virtual QString label() const = 0; // see Find::SearchResultWindow::startNewSearch
virtual QString toolTip() const = 0; // see Find::SearchResultWindow::startNewSearch,
// add %1 placeholder where the find flags should be put
......@@ -97,10 +99,12 @@ private slots:
void doReplace(const QString &txt,
const QList<Find::SearchResultItem> &items);
void hideHighlightAll(bool visible);
void searchAgain();
private:
void runNewSearch(const QString &txt, Find::FindFlags findFlags,
Find::SearchResultWindow::SearchMode searchMode);
void runSearch(Find::SearchResult *search);
QFutureWatcher<Utils::FileSearchResultList> *watcherForSearch(Find::SearchResult *search);
QMap<QFutureWatcher<Utils::FileSearchResultList> *, QPointer<Find::SearchResult> > m_watchers;
......
......@@ -33,6 +33,9 @@
#ifndef BASEFILEFIND_P_H
#define BASEFILEFIND_P_H
#include <find/ifindfilter.h>
#include <QtCore/QVariant>
#include <QtGui/QLabel>
namespace TextEditor {
......@@ -48,7 +51,18 @@ public slots:
void updateCount(int count);
};
class FileFindParameters
{
public:
QString text;
Find::FindFlags flags;
QStringList nameFilters;
QVariant additionalParameters;
};
} // namespace Internal
} // namespace TextEditor
Q_DECLARE_METATYPE(TextEditor::Internal::FileFindParameters)
#endif // BASEFILEFIND_P_H
......@@ -66,10 +66,11 @@ QString FindInCurrentFile::displayName() const
return tr("Current File");
}
Utils::FileIterator *FindInCurrentFile::files() const
Utils::FileIterator *FindInCurrentFile::files(const QStringList &nameFilters,
const QVariant &additionalParameters) const
{
Q_ASSERT(isEnabled());
QString fileName = m_currentFile->fileName();
Q_UNUSED(nameFilters)
QString fileName = additionalParameters.toString();
QMap<QString, QTextCodec *> openEditorEncodings = ITextEditor::openedTextEditorsEncodings();
QTextCodec *codec = openEditorEncodings.value(fileName);
if (!codec)
......@@ -77,6 +78,11 @@ Utils::FileIterator *FindInCurrentFile::files() const
return new Utils::FileIterator(QStringList() << fileName, QList<QTextCodec *>() << codec);
}
QVariant FindInCurrentFile::additionalParameters() const
{
return qVariantFromValue(m_currentFile->fileName());
}
QString FindInCurrentFile::label() const
{
return tr("File '%1':").arg(QFileInfo(m_currentFile->fileName()).fileName());
......
......@@ -63,7 +63,9 @@ public:
void readSettings(QSettings *settings);
protected:
Utils::FileIterator *files() const;
Utils::FileIterator *files(const QStringList &nameFilters,
const QVariant &additionalParameters) const;
QVariant additionalParameters() const;
QString label() const;
QString toolTip() const;
......
......@@ -68,13 +68,19 @@ void FindInFiles::findAll(const QString &txt, Find::FindFlags findFlags)
BaseFileFind::findAll(txt, findFlags);
}
Utils::FileIterator *FindInFiles::files() const
Utils::FileIterator *FindInFiles::files(const QStringList &nameFilters,
const QVariant &additionalParameters) const
{
return new Utils::SubDirFileIterator(QStringList() << QDir::fromNativeSeparators(m_directory->currentText()),
fileNameFilters(),
return new Utils::SubDirFileIterator(QStringList() << additionalParameters.toString(),
nameFilters,
Core::EditorManager::instance()->defaultTextCodec());
}
QVariant FindInFiles::additionalParameters() const
{
return qVariantFromValue(QDir::fromNativeSeparators(m_directory->currentText()));
}
QString FindInFiles::label() const
{
const QStringList &nonEmptyComponents = QDir::cleanPath(
......
......@@ -62,7 +62,9 @@ public:
void setDirectory(const QString &directory);
protected:
Utils::FileIterator *files() const;
Utils::FileIterator *files(const QStringList &nameFilters,
const QVariant &additionalParameters) const;
QVariant additionalParameters() const;
QString label() const;
QString toolTip() const;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment