2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "basefilefind.h"
|
2015-02-26 13:22:35 +01:00
|
|
|
#include "textdocument.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-08-09 11:08:01 +02:00
|
|
|
#include <aggregation/aggregate.h>
|
2009-01-21 18:30:45 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2009-01-13 14:16:36 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2010-03-18 10:59:06 +01:00
|
|
|
#include <coreplugin/progressmanager/futureprogress.h>
|
2012-10-15 11:53:22 +02:00
|
|
|
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
2012-02-14 16:43:51 +01:00
|
|
|
#include <coreplugin/documentmanager.h>
|
2015-02-26 13:22:35 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2014-01-13 16:17:34 +01:00
|
|
|
#include <coreplugin/find/ifindsupport.h>
|
2014-09-26 09:14:03 +02:00
|
|
|
#include <texteditor/texteditor.h>
|
2011-10-17 10:37:22 +02:00
|
|
|
#include <texteditor/refactoringchanges.h>
|
2016-12-09 13:33:12 +01:00
|
|
|
#include <utils/algorithm.h>
|
2015-03-10 11:35:09 +01:00
|
|
|
#include <utils/fadingindicator.h>
|
2013-03-26 12:32:52 +01:00
|
|
|
#include <utils/filesearch.h>
|
2015-03-10 11:35:09 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/stylehelper.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QSettings>
|
|
|
|
|
#include <QHash>
|
|
|
|
|
#include <QPair>
|
2013-03-26 12:32:52 +01:00
|
|
|
#include <QStringListModel>
|
|
|
|
|
#include <QFutureWatcher>
|
|
|
|
|
#include <QPointer>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QComboBox>
|
2013-03-26 12:32:52 +01:00
|
|
|
#include <QLabel>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
using namespace Core;
|
|
|
|
|
|
2013-03-26 12:32:52 +01:00
|
|
|
namespace TextEditor {
|
|
|
|
|
namespace Internal {
|
2014-01-13 16:17:34 +01:00
|
|
|
|
2016-03-16 22:37:24 +01:00
|
|
|
namespace {
|
|
|
|
|
class InternalEngine : public TextEditor::SearchEngine
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
InternalEngine() : m_widget(new QWidget) {}
|
|
|
|
|
~InternalEngine() override { delete m_widget;}
|
|
|
|
|
QString title() const override { return tr("Internal"); }
|
|
|
|
|
QString toolTip() const override { return QString(); }
|
|
|
|
|
QWidget *widget() const override { return m_widget; }
|
|
|
|
|
QVariant parameters() const override { return QVariant(); }
|
2016-11-24 01:15:57 +01:00
|
|
|
void readSettings(QSettings * /*settings*/) override {}
|
|
|
|
|
void writeSettings(QSettings * /*settings*/) const override {}
|
2016-03-16 22:37:24 +01:00
|
|
|
QFuture<Utils::FileSearchResultList> executeSearch(
|
|
|
|
|
const TextEditor::FileFindParameters ¶meters,
|
|
|
|
|
BaseFileFind *baseFileFind) override
|
|
|
|
|
{
|
|
|
|
|
auto func = parameters.flags & FindRegularExpression
|
|
|
|
|
? Utils::findInFilesRegExp
|
|
|
|
|
: Utils::findInFiles;
|
|
|
|
|
|
|
|
|
|
return func(parameters.text,
|
2016-12-09 13:33:12 +01:00
|
|
|
baseFileFind->files(parameters.nameFilters, parameters.exclusionFilters,
|
|
|
|
|
parameters.additionalParameters),
|
2016-03-16 22:37:24 +01:00
|
|
|
textDocumentFlagsForFindFlags(parameters.flags),
|
|
|
|
|
TextDocument::openedTextDocumentContents());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
Core::IEditor *openEditor(const Core::SearchResultItem &/*item*/,
|
|
|
|
|
const TextEditor::FileFindParameters &/*parameters*/) override
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QWidget *m_widget;
|
|
|
|
|
};
|
2016-11-21 10:58:19 +01:00
|
|
|
} // namespace
|
2016-03-16 22:37:24 +01:00
|
|
|
|
2016-11-21 10:58:19 +01:00
|
|
|
class SearchEnginePrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool isEnabled = true;
|
|
|
|
|
};
|
2016-03-16 22:37:24 +01:00
|
|
|
|
2015-11-30 23:14:41 +02:00
|
|
|
class CountingLabel : public QLabel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CountingLabel();
|
|
|
|
|
void updateCount(int count);
|
|
|
|
|
};
|
|
|
|
|
|
2014-01-13 16:17:34 +01:00
|
|
|
class BaseFileFindPrivate
|
|
|
|
|
{
|
2013-03-26 12:32:52 +01:00
|
|
|
public:
|
2016-03-16 22:37:24 +01:00
|
|
|
~BaseFileFindPrivate() { delete m_internalSearchEngine; }
|
2015-02-03 23:46:35 +02:00
|
|
|
QPointer<IFindSupport> m_currentFindSupport;
|
2013-03-26 12:32:52 +01:00
|
|
|
|
2016-01-28 23:37:10 +02:00
|
|
|
QLabel *m_resultLabel = 0;
|
2016-12-09 13:33:12 +01:00
|
|
|
// models in native path format
|
2013-03-26 12:32:52 +01:00
|
|
|
QStringListModel m_filterStrings;
|
2016-12-09 13:33:12 +01:00
|
|
|
QStringListModel m_exclusionStrings;
|
|
|
|
|
// current filter in portable path format
|
2013-03-26 12:32:52 +01:00
|
|
|
QString m_filterSetting;
|
2016-12-09 13:33:12 +01:00
|
|
|
QString m_exclusionSetting;
|
2013-03-26 12:32:52 +01:00
|
|
|
QPointer<QComboBox> m_filterCombo;
|
2016-12-09 13:33:12 +01:00
|
|
|
QPointer<QComboBox> m_exclusionCombo;
|
2016-03-16 22:37:24 +01:00
|
|
|
QVector<SearchEngine *> m_searchEngines;
|
|
|
|
|
SearchEngine *m_internalSearchEngine;
|
2016-11-21 10:58:19 +01:00
|
|
|
int m_currentSearchEngineIndex = -1;
|
2013-03-26 12:32:52 +01:00
|
|
|
};
|
2014-01-13 16:17:34 +01:00
|
|
|
|
2013-03-26 12:32:52 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
|
2016-11-29 12:03:46 +01:00
|
|
|
static void syncComboWithSettings(QComboBox *combo, const QString &setting)
|
|
|
|
|
{
|
|
|
|
|
if (!combo)
|
|
|
|
|
return;
|
2016-12-09 13:33:12 +01:00
|
|
|
const QString &nativeSettings = QDir::toNativeSeparators(setting);
|
|
|
|
|
int index = combo->findText(nativeSettings);
|
2016-11-29 12:03:46 +01:00
|
|
|
if (index < 0)
|
2016-12-09 13:33:12 +01:00
|
|
|
combo->setEditText(nativeSettings);
|
2016-11-29 12:03:46 +01:00
|
|
|
else
|
|
|
|
|
combo->setCurrentIndex(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void updateComboEntries(QComboBox *combo, bool onTop)
|
|
|
|
|
{
|
|
|
|
|
int index = combo->findText(combo->currentText());
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
if (onTop)
|
|
|
|
|
combo->insertItem(0, combo->currentText());
|
|
|
|
|
else
|
|
|
|
|
combo->addItem(combo->currentText());
|
|
|
|
|
combo->setCurrentIndex(combo->findText(combo->currentText()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-13 16:17:34 +01:00
|
|
|
using namespace Internal;
|
2013-03-26 12:32:52 +01:00
|
|
|
|
2016-11-21 10:58:19 +01:00
|
|
|
SearchEngine::SearchEngine()
|
|
|
|
|
: d(new SearchEnginePrivate)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SearchEngine::~SearchEngine()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SearchEngine::isEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return d->isEnabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SearchEngine::setEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
if (enabled == d->isEnabled)
|
|
|
|
|
return;
|
|
|
|
|
d->isEnabled = enabled;
|
|
|
|
|
emit enabledChanged(d->isEnabled);
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-26 12:32:52 +01:00
|
|
|
BaseFileFind::BaseFileFind() : d(new BaseFileFindPrivate)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-03-16 22:37:24 +01:00
|
|
|
d->m_internalSearchEngine = new InternalEngine;
|
|
|
|
|
addSearchEngine(d->m_internalSearchEngine);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-18 14:23:06 +02:00
|
|
|
BaseFileFind::~BaseFileFind()
|
|
|
|
|
{
|
2013-03-26 12:32:52 +01:00
|
|
|
delete d;
|
2011-08-18 14:23:06 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool BaseFileFind::isEnabled() const
|
|
|
|
|
{
|
2011-12-12 15:16:49 +01:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-09 13:33:12 +01:00
|
|
|
static QStringList splitFilterUiText(const QString &text)
|
|
|
|
|
{
|
|
|
|
|
const QStringList parts = text.split(',');
|
|
|
|
|
const QStringList trimmedPortableParts = Utils::transform(parts, [](const QString &s) {
|
|
|
|
|
return QDir::fromNativeSeparators(s.trimmed());
|
|
|
|
|
});
|
|
|
|
|
return Utils::filtered(trimmedPortableParts, [](const QString &s) { return !s.isEmpty(); });
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList BaseFileFind::fileNameFilters() const
|
|
|
|
|
{
|
2016-12-09 13:33:12 +01:00
|
|
|
if (d->m_filterCombo)
|
|
|
|
|
return splitFilterUiText(d->m_filterCombo->currentText());
|
|
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList BaseFileFind::fileExclusionFilters() const
|
|
|
|
|
{
|
|
|
|
|
if (d->m_exclusionCombo)
|
|
|
|
|
return splitFilterUiText(d->m_exclusionCombo->currentText());
|
|
|
|
|
return QStringList();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-16 22:37:24 +01:00
|
|
|
SearchEngine *BaseFileFind::currentSearchEngine() const
|
2016-01-28 23:37:10 +02:00
|
|
|
{
|
2016-03-16 22:37:24 +01:00
|
|
|
if (d->m_searchEngines.isEmpty() || d->m_currentSearchEngineIndex == -1)
|
|
|
|
|
return nullptr;
|
|
|
|
|
return d->m_searchEngines[d->m_currentSearchEngineIndex];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVector<SearchEngine *> BaseFileFind::searchEngines() const
|
|
|
|
|
{
|
|
|
|
|
return d->m_searchEngines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BaseFileFind::setCurrentSearchEngine(int index)
|
|
|
|
|
{
|
2016-11-21 10:58:19 +01:00
|
|
|
if (d->m_currentSearchEngineIndex == index)
|
|
|
|
|
return;
|
2016-03-16 22:37:24 +01:00
|
|
|
d->m_currentSearchEngineIndex = index;
|
2016-11-21 10:58:19 +01:00
|
|
|
emit currentSearchEngineChanged();
|
2016-01-28 23:37:10 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-29 16:17:34 +01:00
|
|
|
static void displayResult(QFutureWatcher<FileSearchResultList> *watcher,
|
|
|
|
|
SearchResult *search, int index)
|
|
|
|
|
{
|
|
|
|
|
FileSearchResultList results = watcher->resultAt(index);
|
|
|
|
|
QList<SearchResultItem> items;
|
|
|
|
|
foreach (const FileSearchResult &result, results) {
|
|
|
|
|
SearchResultItem item;
|
|
|
|
|
item.path = QStringList() << QDir::toNativeSeparators(result.fileName);
|
|
|
|
|
item.mainRange.begin.line = result.lineNumber;
|
|
|
|
|
item.mainRange.begin.column = result.matchStart;
|
|
|
|
|
item.mainRange.end = item.mainRange.begin;
|
|
|
|
|
item.mainRange.end.column += result.matchLength;
|
|
|
|
|
item.text = result.matchingLine;
|
|
|
|
|
item.useTextEditorFont = true;
|
|
|
|
|
item.userData = result.regexpCapturedTexts;
|
|
|
|
|
items << item;
|
|
|
|
|
}
|
|
|
|
|
search->addResults(items, SearchResult::AddOrdered);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
void BaseFileFind::runNewSearch(const QString &txt, FindFlags findFlags,
|
2011-08-09 11:08:01 +02:00
|
|
|
SearchResultWindow::SearchMode searchMode)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-03-26 12:32:52 +01:00
|
|
|
d->m_currentFindSupport = 0;
|
|
|
|
|
if (d->m_filterCombo)
|
|
|
|
|
updateComboEntries(d->m_filterCombo, true);
|
2016-12-09 13:33:12 +01:00
|
|
|
if (d->m_exclusionCombo)
|
|
|
|
|
updateComboEntries(d->m_exclusionCombo, true);
|
2016-02-07 23:35:41 +02:00
|
|
|
QString tooltip = toolTip();
|
2016-03-16 22:37:24 +01:00
|
|
|
|
|
|
|
|
SearchResult *search = SearchResultWindow::instance()->startNewSearch(
|
|
|
|
|
label(),
|
|
|
|
|
tooltip.arg(IFindFilter::descriptionForFindFlags(findFlags)),
|
|
|
|
|
txt, searchMode, SearchResultWindow::PreserveCaseEnabled,
|
|
|
|
|
QString::fromLatin1("TextEditor"));
|
2011-12-12 15:16:49 +01:00
|
|
|
search->setTextToReplace(txt);
|
2011-12-13 10:50:57 +01:00
|
|
|
search->setSearchAgainSupported(true);
|
|
|
|
|
FileFindParameters parameters;
|
|
|
|
|
parameters.text = txt;
|
|
|
|
|
parameters.flags = findFlags;
|
|
|
|
|
parameters.nameFilters = fileNameFilters();
|
2016-12-09 13:33:12 +01:00
|
|
|
parameters.exclusionFilters = fileExclusionFilters();
|
2011-12-13 10:50:57 +01:00
|
|
|
parameters.additionalParameters = additionalParameters();
|
2016-03-16 22:37:24 +01:00
|
|
|
parameters.searchEngineParameters = currentSearchEngine()->parameters();
|
|
|
|
|
parameters.searchEngineIndex = d->m_currentSearchEngineIndex;
|
2011-12-13 10:50:57 +01:00
|
|
|
search->setUserData(qVariantFromValue(parameters));
|
2015-12-13 01:18:33 +02:00
|
|
|
connect(search, &SearchResult::activated, this, &BaseFileFind::openEditor);
|
|
|
|
|
if (searchMode == SearchResultWindow::SearchAndReplace)
|
|
|
|
|
connect(search, &SearchResult::replaceButtonClicked, this, &BaseFileFind::doReplace);
|
|
|
|
|
connect(search, &SearchResult::visibilityChanged, this, &BaseFileFind::hideHighlightAll);
|
|
|
|
|
connect(search, &SearchResult::searchAgainRequested, this, &BaseFileFind::searchAgain);
|
|
|
|
|
connect(this, &BaseFileFind::enabledChanged, search, &SearchResult::requestEnabledCheck);
|
|
|
|
|
connect(search, &SearchResult::requestEnabledCheck, this, &BaseFileFind::recheckEnabled);
|
2013-02-12 18:37:14 +01:00
|
|
|
|
2011-12-13 10:50:57 +01:00
|
|
|
runSearch(search);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
void BaseFileFind::runSearch(SearchResult *search)
|
2011-12-13 10:50:57 +01:00
|
|
|
{
|
|
|
|
|
FileFindParameters parameters = search->userData().value<FileFindParameters>();
|
2011-12-12 15:16:49 +01:00
|
|
|
CountingLabel *label = new CountingLabel;
|
2015-12-13 01:18:33 +02:00
|
|
|
connect(search, &SearchResult::countChanged, label, &CountingLabel::updateCount);
|
2013-04-08 15:02:30 +02:00
|
|
|
CountingLabel *statusLabel = new CountingLabel;
|
2015-12-13 01:18:33 +02:00
|
|
|
connect(search, &SearchResult::countChanged, statusLabel, &CountingLabel::updateCount);
|
2015-02-03 23:46:35 +02:00
|
|
|
SearchResultWindow::instance()->popup(IOutputPane::Flags(IOutputPane::ModeSwitch|IOutputPane::WithFocus));
|
2011-12-13 10:50:57 +01:00
|
|
|
QFutureWatcher<FileSearchResultList> *watcher = new QFutureWatcher<FileSearchResultList>();
|
|
|
|
|
watcher->setPendingResultsLimit(1);
|
2016-11-29 16:17:34 +01:00
|
|
|
// search is deleted if it is removed from search panel
|
|
|
|
|
connect(search, &QObject::destroyed, watcher, &QFutureWatcherBase::cancel);
|
|
|
|
|
connect(search, &SearchResult::cancelled, watcher, &QFutureWatcherBase::cancel);
|
|
|
|
|
connect(search, &SearchResult::paused, watcher, [watcher](bool paused) {
|
|
|
|
|
if (!paused || watcher->isRunning()) // guard against pausing when the search is finished
|
|
|
|
|
watcher->setPaused(paused);
|
|
|
|
|
});
|
|
|
|
|
connect(watcher, &QFutureWatcherBase::resultReadyAt, search, [watcher, search](int index) {
|
|
|
|
|
displayResult(watcher, search, index);
|
|
|
|
|
});
|
|
|
|
|
// auto-delete:
|
|
|
|
|
connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater);
|
|
|
|
|
connect(watcher, &QFutureWatcherBase::finished, search, [watcher, search]() {
|
|
|
|
|
search->finishSearch(watcher->isCanceled());
|
|
|
|
|
});
|
2015-11-30 23:14:41 +02:00
|
|
|
watcher->setFuture(executeSearch(parameters));
|
2013-09-03 15:18:37 +02:00
|
|
|
FutureProgress *progress =
|
2014-04-17 15:14:14 +02:00
|
|
|
ProgressManager::addTask(watcher->future(), tr("Searching"), Constants::TASK_SEARCH);
|
2013-09-03 15:18:37 +02:00
|
|
|
progress->setWidget(label);
|
2013-04-08 15:02:30 +02:00
|
|
|
progress->setStatusBarWidget(statusLabel);
|
2015-12-13 01:18:33 +02:00
|
|
|
connect(progress, &FutureProgress::clicked, search, &SearchResult::popup);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
void BaseFileFind::findAll(const QString &txt, FindFlags findFlags)
|
2011-08-09 11:08:01 +02:00
|
|
|
{
|
|
|
|
|
runNewSearch(txt, findFlags, SearchResultWindow::SearchOnly);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
void BaseFileFind::replaceAll(const QString &txt, FindFlags findFlags)
|
2009-12-21 11:08:20 +01:00
|
|
|
{
|
2011-08-09 11:08:01 +02:00
|
|
|
runNewSearch(txt, findFlags, SearchResultWindow::SearchAndReplace);
|
2009-12-21 11:08:20 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-16 22:37:24 +01:00
|
|
|
void BaseFileFind::addSearchEngine(SearchEngine *searchEngine)
|
2016-01-28 23:37:10 +02:00
|
|
|
{
|
2016-03-16 22:37:24 +01:00
|
|
|
d->m_searchEngines.push_back(searchEngine);
|
2016-11-28 15:41:56 +01:00
|
|
|
if (d->m_searchEngines.size() == 1) // empty before, make sure we have a current engine
|
|
|
|
|
setCurrentSearchEngine(0);
|
2016-01-28 23:37:10 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-21 11:08:20 +01:00
|
|
|
void BaseFileFind::doReplace(const QString &text,
|
2015-02-03 23:46:35 +02:00
|
|
|
const QList<SearchResultItem> &items,
|
2012-11-30 16:15:07 +01:00
|
|
|
bool preserveCase)
|
2009-12-21 11:08:20 +01:00
|
|
|
{
|
2012-11-30 16:15:07 +01:00
|
|
|
QStringList files = replaceAll(text, items, preserveCase);
|
2009-12-21 11:08:20 +01:00
|
|
|
if (!files.isEmpty()) {
|
2015-03-10 11:35:09 +01:00
|
|
|
Utils::FadingIndicator::showText(ICore::mainWindow(),
|
2015-07-27 14:49:17 +02:00
|
|
|
tr("%n occurrences replaced.", 0, items.size()),
|
2015-03-10 11:35:09 +01:00
|
|
|
Utils::FadingIndicator::SmallText);
|
2013-08-30 09:22:42 +02:00
|
|
|
DocumentManager::notifyFilesChangedInternally(files);
|
2015-02-03 23:46:35 +02:00
|
|
|
SearchResultWindow::instance()->hide();
|
2009-12-21 11:08:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 13:33:12 +01:00
|
|
|
static QComboBox *createCombo(QAbstractItemModel *model)
|
|
|
|
|
{
|
|
|
|
|
auto combo = new QComboBox;
|
|
|
|
|
combo->setEditable(true);
|
|
|
|
|
combo->setModel(model);
|
|
|
|
|
combo->setMaxCount(10);
|
|
|
|
|
combo->setMinimumContentsLength(10);
|
|
|
|
|
combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
|
|
|
|
combo->setInsertPolicy(QComboBox::InsertAtBottom);
|
|
|
|
|
combo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
|
|
|
return combo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QLabel *createLabel(const QString &text)
|
|
|
|
|
{
|
|
|
|
|
auto filePatternLabel = new QLabel(text);
|
|
|
|
|
filePatternLabel->setMinimumWidth(80);
|
|
|
|
|
filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
|
|
|
|
filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
|
|
return filePatternLabel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<QPair<QWidget *, QWidget *>> BaseFileFind::createPatternWidgets()
|
|
|
|
|
{
|
|
|
|
|
static const QString filterToolTip = tr("List of comma separated wildcard filters. "
|
|
|
|
|
"Files with file name or full file path matching any filter are included.");
|
|
|
|
|
QLabel *filterLabel = createLabel(tr("Fi&le pattern:"));
|
|
|
|
|
d->m_filterCombo = createCombo(&d->m_filterStrings);
|
2013-03-26 12:32:52 +01:00
|
|
|
d->m_filterCombo->setToolTip(filterToolTip);
|
2016-12-09 13:33:12 +01:00
|
|
|
filterLabel->setBuddy(d->m_filterCombo);
|
2013-03-26 12:32:52 +01:00
|
|
|
syncComboWithSettings(d->m_filterCombo, d->m_filterSetting);
|
2016-12-09 13:33:12 +01:00
|
|
|
QLabel *exclusionLabel = createLabel(tr("Exclusion pattern:"));
|
|
|
|
|
d->m_exclusionCombo = createCombo(&d->m_exclusionStrings);
|
|
|
|
|
d->m_exclusionCombo->setToolTip(filterToolTip);
|
|
|
|
|
exclusionLabel->setBuddy(d->m_exclusionCombo);
|
|
|
|
|
syncComboWithSettings(d->m_exclusionCombo, d->m_exclusionSetting);
|
|
|
|
|
return { qMakePair(filterLabel, d->m_filterCombo),
|
|
|
|
|
qMakePair(exclusionLabel, d->m_exclusionCombo) };
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BaseFileFind::writeCommonSettings(QSettings *settings)
|
|
|
|
|
{
|
2016-12-09 13:33:12 +01:00
|
|
|
std::function<QStringList(const QStringList &)> fromNativeSeparators = [](const QStringList &files) {
|
|
|
|
|
return Utils::transform(files, &QDir::fromNativeSeparators);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
settings->setValue("filters", fromNativeSeparators(d->m_filterStrings.stringList()));
|
2013-03-26 12:32:52 +01:00
|
|
|
if (d->m_filterCombo)
|
2016-12-09 13:33:12 +01:00
|
|
|
settings->setValue("currentFilter",
|
|
|
|
|
QDir::fromNativeSeparators(d->m_filterCombo->currentText()));
|
|
|
|
|
settings->setValue("exclusionFilters", fromNativeSeparators(d->m_exclusionStrings.stringList()));
|
|
|
|
|
if (d->m_exclusionCombo)
|
|
|
|
|
settings->setValue("currentExclusionFilter",
|
|
|
|
|
QDir::fromNativeSeparators(d->m_exclusionCombo->currentText()));
|
2016-03-16 22:37:24 +01:00
|
|
|
|
|
|
|
|
foreach (SearchEngine *searchEngine, d->m_searchEngines)
|
|
|
|
|
searchEngine->writeSettings(settings);
|
|
|
|
|
settings->setValue("currentSearchEngineIndex", d->m_currentSearchEngineIndex);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-09 13:33:12 +01:00
|
|
|
void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter,
|
|
|
|
|
const QString &defaultExclusionFilter)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-12-09 13:33:12 +01:00
|
|
|
std::function<QStringList(const QStringList &)> toNativeSeparators = [](const QStringList &files) {
|
|
|
|
|
return Utils::transform(files, &QDir::toNativeSeparators);
|
|
|
|
|
};
|
|
|
|
|
|
2016-03-16 22:37:24 +01:00
|
|
|
QStringList filters = settings->value("filters").toStringList();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (filters.isEmpty())
|
|
|
|
|
filters << defaultFilter;
|
2016-12-09 13:33:12 +01:00
|
|
|
const QVariant currentFilter = settings->value("currentFilter");
|
|
|
|
|
d->m_filterSetting = currentFilter.isValid() ? currentFilter.toString()
|
|
|
|
|
: filters.first();
|
|
|
|
|
d->m_filterStrings.setStringList(toNativeSeparators(filters));
|
2013-03-26 12:32:52 +01:00
|
|
|
if (d->m_filterCombo)
|
|
|
|
|
syncComboWithSettings(d->m_filterCombo, d->m_filterSetting);
|
2016-03-16 22:37:24 +01:00
|
|
|
|
2016-12-09 13:33:12 +01:00
|
|
|
QStringList exclusionFilters = settings->value("exclusionFilters").toStringList();
|
|
|
|
|
if (exclusionFilters.isEmpty())
|
|
|
|
|
exclusionFilters << defaultExclusionFilter;
|
|
|
|
|
const QVariant currentExclusionFilter = settings->value("currentExclusionFilter");
|
|
|
|
|
d->m_exclusionSetting = currentExclusionFilter.isValid() ? currentExclusionFilter.toString()
|
|
|
|
|
: exclusionFilters.first();
|
|
|
|
|
d->m_exclusionStrings.setStringList(toNativeSeparators(exclusionFilters));
|
|
|
|
|
if (d->m_exclusionCombo)
|
|
|
|
|
syncComboWithSettings(d->m_exclusionCombo, d->m_exclusionSetting);
|
|
|
|
|
|
2016-03-16 22:37:24 +01:00
|
|
|
foreach (SearchEngine* searchEngine, d->m_searchEngines)
|
|
|
|
|
searchEngine->readSettings(settings);
|
|
|
|
|
const int currentSearchEngineIndex = settings->value("currentSearchEngineIndex", 0).toInt();
|
|
|
|
|
syncSearchEngineCombo(currentSearchEngineIndex);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
void BaseFileFind::openEditor(const SearchResultItem &item)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2011-08-09 11:08:01 +02:00
|
|
|
SearchResult *result = qobject_cast<SearchResult *>(sender());
|
2016-02-07 23:35:41 +02:00
|
|
|
FileFindParameters parameters = result->userData().value<FileFindParameters>();
|
2016-03-16 22:37:24 +01:00
|
|
|
IEditor *openedEditor =
|
|
|
|
|
d->m_searchEngines[parameters.searchEngineIndex]->openEditor(item, parameters);
|
2016-02-07 23:35:41 +02:00
|
|
|
if (!openedEditor) {
|
|
|
|
|
if (item.path.size() > 0) {
|
|
|
|
|
openedEditor = EditorManager::openEditorAt(QDir::fromNativeSeparators(item.path.first()),
|
2016-11-17 17:33:22 +01:00
|
|
|
item.mainRange.begin.line,
|
|
|
|
|
item.mainRange.begin.column, Id(),
|
2016-02-07 23:35:41 +02:00
|
|
|
EditorManager::DoNotSwitchToDesignMode);
|
|
|
|
|
} else {
|
|
|
|
|
openedEditor = EditorManager::openEditor(QDir::fromNativeSeparators(item.text));
|
|
|
|
|
}
|
2011-08-09 11:08:01 +02:00
|
|
|
}
|
2013-03-26 12:32:52 +01:00
|
|
|
if (d->m_currentFindSupport)
|
2014-07-02 13:43:31 +02:00
|
|
|
d->m_currentFindSupport->clearHighlights();
|
2013-03-26 12:32:52 +01:00
|
|
|
d->m_currentFindSupport = 0;
|
2011-08-09 11:08:01 +02:00
|
|
|
if (!openedEditor)
|
|
|
|
|
return;
|
|
|
|
|
// highlight results
|
|
|
|
|
if (IFindSupport *findSupport = Aggregation::query<IFindSupport>(openedEditor->widget())) {
|
2016-02-07 23:35:41 +02:00
|
|
|
d->m_currentFindSupport = findSupport;
|
|
|
|
|
d->m_currentFindSupport->highlightAll(parameters.text, parameters.flags);
|
2010-07-19 14:46:53 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-12-21 11:08:20 +01:00
|
|
|
|
2011-08-09 11:08:01 +02:00
|
|
|
void BaseFileFind::hideHighlightAll(bool visible)
|
|
|
|
|
{
|
2013-03-26 12:32:52 +01:00
|
|
|
if (!visible && d->m_currentFindSupport)
|
2014-07-02 13:43:31 +02:00
|
|
|
d->m_currentFindSupport->clearHighlights();
|
2011-08-09 11:08:01 +02:00
|
|
|
}
|
|
|
|
|
|
2011-12-13 10:50:57 +01:00
|
|
|
void BaseFileFind::searchAgain()
|
|
|
|
|
{
|
|
|
|
|
SearchResult *search = qobject_cast<SearchResult *>(sender());
|
2012-02-07 15:44:12 +01:00
|
|
|
search->restart();
|
2011-12-13 10:50:57 +01:00
|
|
|
runSearch(search);
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-12 18:37:14 +01:00
|
|
|
void BaseFileFind::recheckEnabled()
|
|
|
|
|
{
|
|
|
|
|
SearchResult *search = qobject_cast<SearchResult *>(sender());
|
|
|
|
|
if (!search)
|
|
|
|
|
return;
|
|
|
|
|
search->setSearchAgainEnabled(isEnabled());
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-21 11:08:20 +01:00
|
|
|
QStringList BaseFileFind::replaceAll(const QString &text,
|
2015-02-03 23:46:35 +02:00
|
|
|
const QList<SearchResultItem> &items,
|
2012-11-30 16:15:07 +01:00
|
|
|
bool preserveCase)
|
2009-12-21 11:08:20 +01:00
|
|
|
{
|
2010-12-01 13:25:08 +01:00
|
|
|
if (items.isEmpty())
|
2009-12-21 11:08:20 +01:00
|
|
|
return QStringList();
|
|
|
|
|
|
2011-10-17 10:37:22 +02:00
|
|
|
RefactoringChanges refactoring;
|
2009-12-21 11:08:20 +01:00
|
|
|
|
2015-02-03 23:46:35 +02:00
|
|
|
QHash<QString, QList<SearchResultItem> > changes;
|
|
|
|
|
foreach (const SearchResultItem &item, items)
|
2010-10-19 12:15:36 +02:00
|
|
|
changes[QDir::fromNativeSeparators(item.path.first())].append(item);
|
2009-12-21 11:08:20 +01:00
|
|
|
|
2012-10-15 11:53:22 +02:00
|
|
|
// Checking for files without write permissions
|
2015-02-03 23:46:35 +02:00
|
|
|
QHashIterator<QString, QList<SearchResultItem> > it(changes);
|
2012-10-15 11:53:22 +02:00
|
|
|
QSet<QString> roFiles;
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
const QFileInfo fileInfo(it.key());
|
|
|
|
|
if (!fileInfo.isWritable())
|
|
|
|
|
roFiles.insert(it.key());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Query the user for permissions
|
|
|
|
|
if (!roFiles.isEmpty()) {
|
2014-09-20 21:52:56 +02:00
|
|
|
ReadOnlyFilesDialog roDialog(roFiles.toList(), ICore::mainWindow());
|
2012-10-15 11:53:22 +02:00
|
|
|
roDialog.setShowFailWarning(true, tr("Aborting replace."));
|
2014-09-20 21:52:56 +02:00
|
|
|
if (roDialog.exec() == ReadOnlyFilesDialog::RO_Cancel)
|
2012-10-15 11:53:22 +02:00
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it.toFront();
|
2009-12-21 11:08:20 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
const QString fileName = it.key();
|
2015-02-03 23:46:35 +02:00
|
|
|
const QList<SearchResultItem> changeItems = it.value();
|
2009-12-21 11:08:20 +01:00
|
|
|
|
2011-10-17 10:37:22 +02:00
|
|
|
ChangeSet changeSet;
|
|
|
|
|
RefactoringFilePtr file = refactoring.file(fileName);
|
|
|
|
|
QSet<QPair<int, int> > processed;
|
2015-02-03 23:46:35 +02:00
|
|
|
foreach (const SearchResultItem &item, changeItems) {
|
2016-11-17 17:33:22 +01:00
|
|
|
const QPair<int, int> &p = qMakePair(item.mainRange.begin.line,
|
|
|
|
|
item.mainRange.begin.column);
|
2011-10-17 10:37:22 +02:00
|
|
|
if (processed.contains(p))
|
|
|
|
|
continue;
|
|
|
|
|
processed.insert(p);
|
|
|
|
|
|
|
|
|
|
QString replacement;
|
2012-11-30 16:15:07 +01:00
|
|
|
if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty()) {
|
2011-10-17 10:37:22 +02:00
|
|
|
replacement = Utils::expandRegExpReplacement(text, item.userData.toStringList());
|
2012-11-30 16:15:07 +01:00
|
|
|
} else if (preserveCase) {
|
2016-11-17 17:33:22 +01:00
|
|
|
const QString originalText = (item.mainRange.length() == 0) ? item.text
|
|
|
|
|
: item.mainRange.mid(text);
|
2012-11-30 16:15:07 +01:00
|
|
|
replacement = Utils::matchCaseReplacement(originalText, text);
|
|
|
|
|
} else {
|
2011-10-17 10:37:22 +02:00
|
|
|
replacement = text;
|
2012-11-30 16:15:07 +01:00
|
|
|
}
|
2011-10-17 10:37:22 +02:00
|
|
|
|
2016-11-17 17:33:22 +01:00
|
|
|
const int start = file->position(item.mainRange.begin.line,
|
|
|
|
|
item.mainRange.begin.column + 1);
|
|
|
|
|
const int end = file->position(item.mainRange.end.line,
|
|
|
|
|
item.mainRange.end.column + 1);
|
2011-10-17 10:37:22 +02:00
|
|
|
changeSet.replace(start, end, replacement);
|
2009-12-21 11:08:20 +01:00
|
|
|
}
|
2011-10-17 10:37:22 +02:00
|
|
|
file->setChangeSet(changeSet);
|
|
|
|
|
file->apply();
|
2009-12-21 11:08:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return changes.keys();
|
|
|
|
|
}
|
2011-12-12 15:16:49 +01:00
|
|
|
|
2013-02-12 18:37:14 +01:00
|
|
|
QVariant BaseFileFind::getAdditionalParameters(SearchResult *search)
|
|
|
|
|
{
|
|
|
|
|
return search->userData().value<FileFindParameters>().additionalParameters;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 23:14:41 +02:00
|
|
|
QFuture<FileSearchResultList> BaseFileFind::executeSearch(const FileFindParameters ¶meters)
|
|
|
|
|
{
|
2016-11-29 12:03:46 +01:00
|
|
|
return d->m_searchEngines[parameters.searchEngineIndex]->executeSearch(parameters, this);
|
2015-11-30 23:14:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2011-12-12 15:16:49 +01:00
|
|
|
CountingLabel::CountingLabel()
|
|
|
|
|
{
|
|
|
|
|
setAlignment(Qt::AlignCenter);
|
|
|
|
|
// ### TODO this setup should be done by style
|
|
|
|
|
QFont f = font();
|
|
|
|
|
f.setBold(true);
|
|
|
|
|
f.setPointSizeF(StyleHelper::sidebarFontSize());
|
|
|
|
|
setFont(f);
|
|
|
|
|
setPalette(StyleHelper::sidebarFontPalette(palette()));
|
2016-07-21 17:14:52 +02:00
|
|
|
setProperty("_q_custom_style_disabled", QVariant(true));
|
2011-12-12 15:16:49 +01:00
|
|
|
updateCount(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CountingLabel::updateCount(int count)
|
|
|
|
|
{
|
2016-11-04 08:55:09 +01:00
|
|
|
setText(BaseFileFind::tr("%n found", nullptr, count));
|
2011-12-12 15:16:49 +01:00
|
|
|
}
|
2014-01-13 16:17:34 +01:00
|
|
|
|
2015-11-30 23:14:41 +02:00
|
|
|
} // namespace Internal
|
2014-01-13 16:17:34 +01:00
|
|
|
} // namespace TextEditor
|