aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancois Ferrand <thetypz@gmail.com>2012-11-30 16:15:07 +0100
committerEike Ziller <eike.ziller@digia.com>2012-12-14 10:22:41 +0100
commit058d2e8cb54d1f5e5c409182ae72fbbd1c96c3cc (patch)
treec5119a151f0c0ee0eb21b17f0ff07cc9dd1f5e01
parenta8a33b9a3b2bab7660a53919bfbfa011e31755d3 (diff)
Support preserving case when replacing.
When making a case insensitive search, try to keep the string capitalization when doing the replace: - All upper-case matches are replaced with the upper-case new text. - All lower-case matches are replaced with the lower-case new text. - Capitalized matches are replace with the capitalized new text. - Other matches are replaced with the new text as provided. Note: this does not work with regexp replace, only plain text. Change-Id: I87cbc28eb64688bdf3c8c6ec173fcb22f91abcd0 Reviewed-by: Cristian Tibirna <tibirna@kde.org> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@digia.com> Reviewed-by: Eike Ziller <eike.ziller@digia.com>
-rw-r--r--doc/src/editors/creator-editors.qdoc22
-rw-r--r--src/libs/utils/filesearch.cpp66
-rw-r--r--src/libs/utils/filesearch.h1
-rw-r--r--src/plugins/cpptools/cppfindreferences.cpp9
-rw-r--r--src/plugins/cpptools/cppfindreferences.h2
-rw-r--r--src/plugins/find/basetextfind.cpp22
-rw-r--r--src/plugins/find/find.qrc1
-rw-r--r--src/plugins/find/findplugin.cpp7
-rw-r--r--src/plugins/find/findplugin.h1
-rw-r--r--src/plugins/find/findtoolbar.cpp35
-rw-r--r--src/plugins/find/findtoolbar.h2
-rw-r--r--src/plugins/find/ifindfilter.cpp9
-rw-r--r--src/plugins/find/images/preservecase.pngbin0 -> 196 bytes
-rw-r--r--src/plugins/find/searchresultwidget.cpp14
-rw-r--r--src/plugins/find/searchresultwidget.h4
-rw-r--r--src/plugins/find/searchresultwindow.cpp6
-rw-r--r--src/plugins/find/searchresultwindow.h2
-rw-r--r--src/plugins/find/textfindconstants.h4
-rw-r--r--src/plugins/qmljseditor/qmljsfindreferences.cpp8
-rw-r--r--src/plugins/qmljseditor/qmljsfindreferences.h2
-rw-r--r--src/plugins/texteditor/basefilefind.cpp21
-rw-r--r--src/plugins/texteditor/basefilefind.h6
-rw-r--r--tests/auto/filesearch/tst_filesearch.cpp44
23 files changed, 256 insertions, 32 deletions
diff --git a/doc/src/editors/creator-editors.qdoc b/doc/src/editors/creator-editors.qdoc
index cf217ae9b6..34a340e5b6 100644
--- a/doc/src/editors/creator-editors.qdoc
+++ b/doc/src/editors/creator-editors.qdoc
@@ -1172,6 +1172,28 @@
\endlist
+ The \gui{Preserve Case when Replacing} option can be selected to preserve
+ the case of the original text when replacing. This option is not compatible
+ with the \gui {Regular Expressions} search option, and will thus be
+ disabled when regular expressions are used. When the option is used, the
+ case of the occurrence will be conserved, according to the following rules:
+
+ \list
+
+ \o All upper-case occurrences are replaced with the upper-case new text.
+
+ \o All lower-case occurrences are replaced with the lower-case new text.
+
+ \o Capitalized occurrences are replaced with the capitalized new text.
+
+ \o Other occurrences are replaced with the new text as entered.
+
+ \o If an occurrence and the new text have the same prefix or suffix,
+ then the case of the prefix and/or suffix are preserved, and the
+ other rules are applied on the rest of the occurrence only.
+
+ \endlist
+
\section1 Advanced Search
To search through projects, files on a file system or the currently open
diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp
index 8af9484cf7..dc5692666f 100644
--- a/src/libs/utils/filesearch.cpp
+++ b/src/libs/utils/filesearch.cpp
@@ -348,6 +348,72 @@ QString Utils::expandRegExpReplacement(const QString &replaceText, const QString
return result;
}
+namespace Utils {
+namespace Internal {
+QString matchCaseReplacement(const QString &originalText, const QString &replaceText)
+{
+ //Now proceed with actual case matching
+ bool firstIsUpperCase = originalText.at(0).isUpper();
+ bool firstIsLowerCase = originalText.at(0).isLower();
+ bool restIsLowerCase = true; // to be verified
+ bool restIsUpperCase = true; // to be verified
+
+ for (int i = 1; i < originalText.length(); ++i) {
+ if (originalText.at(i).isUpper())
+ restIsLowerCase = false;
+ else if (originalText.at(i).isLower())
+ restIsUpperCase = false;
+
+ if (!restIsLowerCase && !restIsUpperCase)
+ return replaceText; // mixed
+ }
+
+ if (restIsLowerCase) {
+ QString res = replaceText.toLower();
+ if (firstIsUpperCase)
+ res.replace(0, 1, res.at(0).toUpper());
+ return res;
+ }
+
+ if (restIsUpperCase) {
+ QString res = replaceText.toUpper();
+ if (firstIsLowerCase)
+ res.replace(0, 1, res.at(0).toLower());
+ return res;
+ }
+
+ return replaceText; // mixed
+}
+}
+}
+
+QString Utils::matchCaseReplacement(const QString &originalText, const QString &replaceText)
+{
+ if (originalText.isEmpty())
+ return replaceText;
+
+ //Find common prefix & suffix: these will be unaffected
+ const int replaceTextLen = replaceText.length();
+ const int originalTextLen = originalText.length();
+
+ int prefixLen = 0;
+ for (; prefixLen <= replaceTextLen && prefixLen <= originalTextLen; prefixLen++)
+ if (replaceText.at(prefixLen).toLower() != originalText.at(prefixLen).toLower())
+ break;
+
+ int suffixLen = 0;
+ for (; suffixLen < replaceTextLen - prefixLen && suffixLen < originalTextLen - prefixLen; suffixLen++)
+ if (replaceText.at(replaceTextLen - 1 - suffixLen).toLower() != originalText.at(originalTextLen- 1 - suffixLen).toLower())
+ break;
+
+ //keep prefix and suffix, and do actual replacement on the 'middle' of the string
+ return originalText.left(prefixLen)
+ + Internal::matchCaseReplacement(originalText.mid(prefixLen, originalTextLen - prefixLen - suffixLen),
+ replaceText.mid(prefixLen, replaceTextLen - prefixLen - suffixLen))
+ + originalText.right(suffixLen);
+
+}
+
// #pragma mark -- FileIterator
FileIterator::FileIterator()
diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h
index d390c4d7c7..4a54e1860a 100644
--- a/src/libs/utils/filesearch.h
+++ b/src/libs/utils/filesearch.h
@@ -118,6 +118,7 @@ QTCREATOR_UTILS_EXPORT QFuture<FileSearchResultList> findInFilesRegExp(const QSt
QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>());
QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts);
+QTCREATOR_UTILS_EXPORT QString matchCaseReplacement(const QString &originalText, const QString &replaceText);
} // namespace Utils
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index 173ed20222..c782f1a5ed 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -255,8 +255,8 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol,
: Find::SearchResultWindow::SearchOnly,
QLatin1String("CppEditor"));
search->setTextToReplace(replacement);
- connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
- SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>)));
+ connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)),
+ SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)));
connect(search, SIGNAL(paused(bool)), this, SLOT(setPaused(bool)));
search->setSearchAgainSupported(true);
connect(search, SIGNAL(searchAgainRequested()), this, SLOT(searchAgain()));
@@ -303,9 +303,10 @@ void CppFindReferences::findAll_helper(Find::SearchResult *search)
}
void CppFindReferences::onReplaceButtonClicked(const QString &text,
- const QList<Find::SearchResultItem> &items)
+ const QList<Find::SearchResultItem> &items,
+ bool preserveCase)
{
- const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items);
+ const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items, preserveCase);
if (!fileNames.isEmpty()) {
_modelManager->updateSourceFiles(fileNames);
Find::SearchResultWindow::instance()->hide();
diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h
index 4f5f9e19ab..d3c979106e 100644
--- a/src/plugins/cpptools/cppfindreferences.h
+++ b/src/plugins/cpptools/cppfindreferences.h
@@ -89,7 +89,7 @@ private Q_SLOTS:
void cancel();
void setPaused(bool paused);
void openEditor(const Find::SearchResultItem &item);
- void onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items);
+ void onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items, bool preserveCase);
void searchAgain();
private:
diff --git a/src/plugins/find/basetextfind.cpp b/src/plugins/find/basetextfind.cpp
index 6f25776c4e..4f7ff89f35 100644
--- a/src/plugins/find/basetextfind.cpp
+++ b/src/plugins/find/basetextfind.cpp
@@ -124,7 +124,8 @@ bool BaseTextFind::supportsReplace() const
Find::FindFlags BaseTextFind::supportedFindFlags() const
{
return Find::FindBackward | Find::FindCaseSensitively
- | Find::FindRegularExpression | Find::FindWholeWords;
+ | Find::FindRegularExpression | Find::FindWholeWords
+ | Find::FindPreserveCase;
}
void BaseTextFind::resetIncrementalSearch()
@@ -216,12 +217,19 @@ QTextCursor BaseTextFind::replaceInternal(const QString &before, const QString &
{
QTextCursor cursor = textCursor();
bool usesRegExp = (findFlags & Find::FindRegularExpression);
+ bool preserveCase = (findFlags & Find::FindPreserveCase);
QRegExp regexp(before,
(findFlags & Find::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive,
usesRegExp ? QRegExp::RegExp : QRegExp::FixedString);
if (regexp.exactMatch(cursor.selectedText())) {
- QString realAfter = usesRegExp ? Utils::expandRegExpReplacement(after, regexp.capturedTexts()) : after;
+ QString realAfter;
+ if (usesRegExp)
+ realAfter = Utils::expandRegExpReplacement(after, regexp.capturedTexts());
+ else if (preserveCase)
+ realAfter = Utils::matchCaseReplacement(cursor.selectedText(), after);
+ else
+ realAfter = after;
int start = cursor.selectionStart();
cursor.insertText(realAfter);
if ((findFlags&Find::FindBackward) != 0)
@@ -252,6 +260,7 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after,
editCursor.beginEditBlock();
int count = 0;
bool usesRegExp = (findFlags & Find::FindRegularExpression);
+ bool preserveCase = (findFlags & Find::FindPreserveCase);
QRegExp regexp(before);
regexp.setPatternSyntax(usesRegExp ? QRegExp::RegExp : QRegExp::FixedString);
regexp.setCaseSensitivity((findFlags & Find::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
@@ -263,7 +272,14 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after,
editCursor.setPosition(found.selectionStart());
editCursor.setPosition(found.selectionEnd(), QTextCursor::KeepAnchor);
regexp.exactMatch(found.selectedText());
- QString realAfter = usesRegExp ? Utils::expandRegExpReplacement(after, regexp.capturedTexts()) : after;
+
+ QString realAfter;
+ if (usesRegExp)
+ realAfter = Utils::expandRegExpReplacement(after, regexp.capturedTexts());
+ else if (preserveCase)
+ realAfter = Utils::matchCaseReplacement(found.selectedText(), after);
+ else
+ realAfter = after;
editCursor.insertText(realAfter);
found = findOne(regexp, editCursor, Find::textDocumentFlagsForFindFlags(findFlags));
}
diff --git a/src/plugins/find/find.qrc b/src/plugins/find/find.qrc
index 52d7a810bf..0c4e128101 100644
--- a/src/plugins/find/find.qrc
+++ b/src/plugins/find/find.qrc
@@ -5,5 +5,6 @@
<file>images/regexp.png</file>
<file>images/expand.png</file>
<file>images/wrapindicator.png</file>
+ <file>images/preservecase.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/find/findplugin.cpp b/src/plugins/find/findplugin.cpp
index f24e7d36f3..63e1c0a6bf 100644
--- a/src/plugins/find/findplugin.cpp
+++ b/src/plugins/find/findplugin.cpp
@@ -270,6 +270,11 @@ void FindPlugin::setRegularExpression(bool regExp)
setFindFlag(Find::FindRegularExpression, regExp);
}
+void FindPlugin::setPreserveCase(bool preserveCase)
+{
+ setFindFlag(Find::FindPreserveCase, preserveCase);
+}
+
void FindPlugin::setFindFlag(Find::FindFlag flag, bool enabled)
{
bool hasFlag = hasFindFlag(flag);
@@ -296,6 +301,7 @@ void FindPlugin::writeSettings()
settings->setValue(QLatin1String("CaseSensitively"), hasFindFlag(Find::FindCaseSensitively));
settings->setValue(QLatin1String("WholeWords"), hasFindFlag(Find::FindWholeWords));
settings->setValue(QLatin1String("RegularExpression"), hasFindFlag(Find::FindRegularExpression));
+ settings->setValue(QLatin1String("PreserveCase"), hasFindFlag(Find::FindPreserveCase));
settings->setValue(QLatin1String("FindStrings"), d->m_findCompletions);
settings->setValue(QLatin1String("ReplaceStrings"), d->m_replaceCompletions);
settings->endGroup();
@@ -312,6 +318,7 @@ void FindPlugin::readSettings()
setCaseSensitive(settings->value(QLatin1String("CaseSensitively"), false).toBool());
setWholeWord(settings->value(QLatin1String("WholeWords"), false).toBool());
setRegularExpression(settings->value(QLatin1String("RegularExpression"), false).toBool());
+ setPreserveCase(settings->value(QLatin1String("PreserveCase"), false).toBool());
blockSignals(block);
d->m_findCompletions = settings->value(QLatin1String("FindStrings")).toStringList();
d->m_replaceCompletions = settings->value(QLatin1String("ReplaceStrings")).toStringList();
diff --git a/src/plugins/find/findplugin.h b/src/plugins/find/findplugin.h
index dc80fd83f1..b4b84a3e9f 100644
--- a/src/plugins/find/findplugin.h
+++ b/src/plugins/find/findplugin.h
@@ -83,6 +83,7 @@ public slots:
void setWholeWord(bool wholeOnly);
void setBackward(bool backward);
void setRegularExpression(bool regExp);
+ void setPreserveCase(bool preserveCase);
signals:
void findFlagsChanged();
diff --git a/src/plugins/find/findtoolbar.cpp b/src/plugins/find/findtoolbar.cpp
index 47a72db22f..543e92a732 100644
--- a/src/plugins/find/findtoolbar.cpp
+++ b/src/plugins/find/findtoolbar.cpp
@@ -250,6 +250,15 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
connect(m_regularExpressionAction, SIGNAL(triggered(bool)), this, SLOT(setRegularExpressions(bool)));
lineEditMenu->addAction(m_regularExpressionAction);
+ m_preserveCaseAction = new QAction(tr("Preserve Case when Replacing"), this);
+ m_preserveCaseAction->setIcon(QPixmap(QLatin1String(":/find/images/preservecase.png")));
+ m_preserveCaseAction->setCheckable(true);
+ m_preserveCaseAction->setChecked(false);
+ cmd = Core::ActionManager::registerAction(m_preserveCaseAction, Constants::PRESERVE_CASE, globalcontext);
+ mfind->addAction(cmd, Constants::G_FIND_FLAGS);
+ connect(m_preserveCaseAction, SIGNAL(triggered(bool)), this, SLOT(setPreserveCase(bool)));
+ lineEditMenu->addAction(m_preserveCaseAction);
+
connect(m_currentDocumentFind, SIGNAL(candidateChanged()), this, SLOT(adaptToCandidate()));
connect(m_currentDocumentFind, SIGNAL(changed()), this, SLOT(updateToolBar()));
updateToolBar();
@@ -357,6 +366,7 @@ void FindToolBar::updateToolBar()
m_caseSensitiveAction->setEnabled(enabled);
m_wholeWordAction->setEnabled(enabled);
m_regularExpressionAction->setEnabled(enabled);
+ m_preserveCaseAction->setEnabled(replaceEnabled && !hasFindFlag(Find::FindRegularExpression));
if (QApplication::clipboard()->supportsFindBuffer())
m_enterFindStringAction->setEnabled(enabled);
bool replaceFocus = m_ui.replaceEdit->hasFocus();
@@ -549,7 +559,8 @@ void FindToolBar::updateIcons()
bool casesensitive = effectiveFlags & Find::FindCaseSensitively;
bool wholewords = effectiveFlags & Find::FindWholeWords;
bool regexp = effectiveFlags & Find::FindRegularExpression;
- if (!casesensitive && !wholewords && !regexp) {
+ bool preserveCase = effectiveFlags & Find::FindPreserveCase;
+ if (!casesensitive && !wholewords && !regexp && !preserveCase) {
QPixmap pixmap(17, 17);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
@@ -565,10 +576,15 @@ void FindToolBar::updateIcons()
Find::FindFlags FindToolBar::effectiveFindFlags()
{
Find::FindFlags supportedFlags;
- if (m_currentDocumentFind->isEnabled())
+ bool supportsReplace = true;
+ if (m_currentDocumentFind->isEnabled()) {
supportedFlags = m_currentDocumentFind->supportedFindFlags();
- else
+ supportsReplace = m_currentDocumentFind->supportsReplace();
+ } else {
supportedFlags = (Find::FindFlags)0xFFFFFF;
+ }
+ if (!supportsReplace || m_findFlags & Find::FindRegularExpression)
+ supportedFlags &= ~Find::FindPreserveCase;
return supportedFlags & m_findFlags;
}
@@ -577,18 +593,23 @@ void FindToolBar::updateFlagMenus()
bool wholeOnly = ((m_findFlags & Find::FindWholeWords));
bool sensitive = ((m_findFlags & Find::FindCaseSensitively));
bool regexp = ((m_findFlags & Find::FindRegularExpression));
+ bool preserveCase = ((m_findFlags & Find::FindPreserveCase));
if (m_wholeWordAction->isChecked() != wholeOnly)
m_wholeWordAction->setChecked(wholeOnly);
if (m_caseSensitiveAction->isChecked() != sensitive)
m_caseSensitiveAction->setChecked(sensitive);
if (m_regularExpressionAction->isChecked() != regexp)
m_regularExpressionAction->setChecked(regexp);
+ if (m_preserveCaseAction->isChecked() != preserveCase)
+ m_preserveCaseAction->setChecked(preserveCase);
Find::FindFlags supportedFlags;
if (m_currentDocumentFind->isEnabled())
supportedFlags = m_currentDocumentFind->supportedFindFlags();
m_wholeWordAction->setEnabled(supportedFlags & Find::FindWholeWords);
m_caseSensitiveAction->setEnabled(supportedFlags & Find::FindCaseSensitively);
m_regularExpressionAction->setEnabled(supportedFlags & Find::FindRegularExpression);
+ bool replaceEnabled = m_currentDocumentFind->isEnabled() && m_currentDocumentFind->supportsReplace();
+ m_preserveCaseAction->setEnabled((supportedFlags & Find::FindPreserveCase) && !regexp && replaceEnabled);
}
bool FindToolBar::setFocusToCurrentFindSupport()
@@ -682,6 +703,7 @@ void FindToolBar::writeSettings()
settings->setValue(QLatin1String("CaseSensitively"), QVariant((m_findFlags & Find::FindCaseSensitively) != 0));
settings->setValue(QLatin1String("WholeWords"), QVariant((m_findFlags & Find::FindWholeWords) != 0));
settings->setValue(QLatin1String("RegularExpression"), QVariant((m_findFlags & Find::FindRegularExpression) != 0));
+ settings->setValue(QLatin1String("PreserveCase"), QVariant((m_findFlags & Find::FindPreserveCase) != 0));
settings->endGroup();
settings->endGroup();
}
@@ -700,6 +722,8 @@ void FindToolBar::readSettings()
flags |= Find::FindWholeWords;
if (settings->value(QLatin1String("RegularExpression"), false).toBool())
flags |= Find::FindRegularExpression;
+ if (settings->value(QLatin1String("PreserveCase"), false).toBool())
+ flags |= Find::FindPreserveCase;
settings->endGroup();
settings->endGroup();
m_findFlags = flags;
@@ -744,6 +768,11 @@ void FindToolBar::setRegularExpressions(bool regexp)
setFindFlag(Find::FindRegularExpression, regexp);
}
+void FindToolBar::setPreserveCase(bool preserveCase)
+{
+ setFindFlag(Find::FindPreserveCase, preserveCase);
+}
+
void FindToolBar::setBackward(bool backward)
{
setFindFlag(Find::FindBackward, backward);
diff --git a/src/plugins/find/findtoolbar.h b/src/plugins/find/findtoolbar.h
index a53e721b39..015e15fd36 100644
--- a/src/plugins/find/findtoolbar.h
+++ b/src/plugins/find/findtoolbar.h
@@ -91,6 +91,7 @@ private slots:
void setCaseSensitive(bool sensitive);
void setWholeWord(bool wholeOnly);
void setRegularExpressions(bool regexp);
+ void setPreserveCase(bool preserveCase);
void adaptToCandidate();
@@ -132,6 +133,7 @@ private:
QAction *m_caseSensitiveAction;
QAction *m_wholeWordAction;
QAction *m_regularExpressionAction;
+ QAction *m_preserveCaseAction;
Find::FindFlags m_findFlags;
QTimer m_findIncrementalTimer;
diff --git a/src/plugins/find/ifindfilter.cpp b/src/plugins/find/ifindfilter.cpp
index 9f5a778800..feda930078 100644
--- a/src/plugins/find/ifindfilter.cpp
+++ b/src/plugins/find/ifindfilter.cpp
@@ -225,13 +225,16 @@ QPixmap Find::IFindFilter::pixmapForFindFlags(Find::FindFlags flags)
static const QPixmap casesensitiveIcon = QPixmap(QLatin1String(":/find/images/casesensitively.png"));
static const QPixmap regexpIcon = QPixmap(QLatin1String(":/find/images/regexp.png"));
static const QPixmap wholewordsIcon = QPixmap(QLatin1String(":/find/images/wholewords.png"));
+ static const QPixmap preservecaseIcon = QPixmap(QLatin1String(":/find/images/preservecase.png"));
bool casesensitive = flags & Find::FindCaseSensitively;
bool wholewords = flags & Find::FindWholeWords;
bool regexp = flags & Find::FindRegularExpression;
+ bool preservecase = flags & Find::FindPreserveCase;
int width = 0;
if (casesensitive) width += 6;
if (wholewords) width += 6;
if (regexp) width += 6;
+ if (preservecase) width += 6;
if (width > 0) --width;
QPixmap pixmap(width, 17);
pixmap.fill(Qt::transparent);
@@ -248,6 +251,10 @@ QPixmap Find::IFindFilter::pixmapForFindFlags(Find::FindFlags flags)
}
if (regexp) {
painter.drawPixmap(x - 6, 0, regexpIcon);
+ x += 6;
+ }
+ if (preservecase) {
+ painter.drawPixmap(x - 6, 0, preservecaseIcon);
}
return pixmap;
}
@@ -261,6 +268,8 @@ QString Find::IFindFilter::descriptionForFindFlags(Find::FindFlags flags)
flagStrings.append(tr("Whole words"));
if (flags & Find::FindRegularExpression)
flagStrings.append(tr("Regular expressions"));
+ if (flags & Find::FindPreserveCase)
+ flagStrings.append(tr("Preserve case"));
QString description = tr("Flags: %1");
if (flagStrings.isEmpty())
description = description.arg(tr("None"));
diff --git a/src/plugins/find/images/preservecase.png b/src/plugins/find/images/preservecase.png
new file mode 100644
index 0000000000..4869aabd71
--- /dev/null
+++ b/src/plugins/find/images/preservecase.png
Binary files differ
diff --git a/src/plugins/find/searchresultwidget.cpp b/src/plugins/find/searchresultwidget.cpp
index e61d36c614..71b1900f83 100644
--- a/src/plugins/find/searchresultwidget.cpp
+++ b/src/plugins/find/searchresultwidget.cpp
@@ -35,6 +35,7 @@
#include "searchresultcolor.h"
#include "ifindsupport.h"
+#include "findplugin.h"
#include "treeviewfind.h"
#include <aggregation/aggregate.h>
@@ -163,6 +164,14 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
m_replaceButton->setText(tr("Replace"));
m_replaceButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_replaceButton->setEnabled(false);
+ m_preserveCaseCheck = new QCheckBox(topWidget);
+ m_preserveCaseCheck->setText(tr("Preserve case"));
+ m_preserveCaseCheck->setEnabled(false);
+
+ if (FindPlugin * plugin = FindPlugin::instance()) {
+ m_preserveCaseCheck->setChecked(plugin->hasFindFlag(Find::FindPreserveCase));
+ connect(m_preserveCaseCheck, SIGNAL(clicked(bool)), plugin, SLOT(setPreserveCase(bool)));
+ }
m_matchesFoundLabel = new QLabel(topWidget);
updateMatchesFoundLabel();
@@ -173,6 +182,7 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
topLayout->addWidget(m_replaceLabel);
topLayout->addWidget(m_replaceTextEdit);
topLayout->addWidget(m_replaceButton);
+ topLayout->addWidget(m_preserveCaseCheck);
topLayout->addStretch(2);
topLayout->addWidget(m_matchesFoundLabel);
topWidget->setMinimumHeight(m_cancelButton->sizeHint().height()
@@ -285,6 +295,7 @@ void SearchResultWidget::setShowReplaceUI(bool visible)
m_replaceLabel->setVisible(visible);
m_replaceTextEdit->setVisible(visible);
m_replaceButton->setVisible(visible);
+ m_preserveCaseCheck->setVisible(visible);
m_isShowingReplaceUI = visible;
}
@@ -397,6 +408,7 @@ void SearchResultWidget::finishSearch(bool canceled)
m_sizeWarningOverridden = false;
m_replaceTextEdit->setEnabled(m_count > 0);
m_replaceButton->setEnabled(m_count > 0);
+ m_preserveCaseCheck->setEnabled(m_count > 0);
m_cancelButton->setVisible(false);
m_messageWidget->setVisible(canceled);
m_searchAgainButton->setVisible(m_searchAgainSupported);
@@ -441,7 +453,7 @@ void SearchResultWidget::handleReplaceButton()
// by pressing return in replace line edit
if (m_replaceButton->isEnabled()) {
m_infoBar.clear();
- emit replaceButtonClicked(m_replaceTextEdit->text(), checkedItems());
+ emit replaceButtonClicked(m_replaceTextEdit->text(), checkedItems(), m_preserveCaseCheck->isChecked());
}
}
diff --git a/src/plugins/find/searchresultwidget.h b/src/plugins/find/searchresultwidget.h
index 62c4321c93..7bdce4629c 100644
--- a/src/plugins/find/searchresultwidget.h
+++ b/src/plugins/find/searchresultwidget.h
@@ -39,6 +39,7 @@
#include <QLineEdit>
#include <QToolButton>
#include <QWidget>
+#include <QCheckBox>
namespace Find {
namespace Internal {
@@ -94,7 +95,7 @@ public slots:
signals:
void activated(const Find::SearchResultItem &item);
- void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems);
+ void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems, bool preserveCase);
void searchAgainRequested();
void cancelled();
void paused(bool paused);
@@ -132,6 +133,7 @@ private:
QLineEdit *m_replaceTextEdit;
QToolButton *m_replaceButton;
QToolButton *m_searchAgainButton;
+ QCheckBox *m_preserveCaseCheck;
bool m_searchAgainSupported;
QWidget *m_descriptionContainer;
QLabel *m_label;
diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp
index f8e89d1929..f587698af4 100644
--- a/src/plugins/find/searchresultwindow.cpp
+++ b/src/plugins/find/searchresultwindow.cpp
@@ -218,7 +218,7 @@ using namespace Find::Internal;
*/
/*!
- \fn void SearchResult::replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems)
+ \fn void SearchResult::replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems, bool preserveCase)
\brief Sent when the user initiated a replace, e.g. by pressing the replace
all button.
@@ -614,8 +614,8 @@ SearchResult::SearchResult(SearchResultWidget *widget)
{
connect(widget, SIGNAL(activated(Find::SearchResultItem)),
this, SIGNAL(activated(Find::SearchResultItem)));
- connect(widget, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
- this, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)));
+ connect(widget, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)),
+ this, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)));
connect(widget, SIGNAL(cancelled()),
this, SIGNAL(cancelled()));
connect(widget, SIGNAL(paused(bool)),
diff --git a/src/plugins/find/searchresultwindow.h b/src/plugins/find/searchresultwindow.h
index dc737d1391..6966c340df 100644
--- a/src/plugins/find/searchresultwindow.h
+++ b/src/plugins/find/searchresultwindow.h
@@ -110,7 +110,7 @@ public slots:
signals:
void activated(const Find::SearchResultItem &item);
- void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems);
+ void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems, bool preserveCase);
void cancelled();
void paused(bool paused);
void visibilityChanged(bool visible);
diff --git a/src/plugins/find/textfindconstants.h b/src/plugins/find/textfindconstants.h
index 1c884a1da8..533e790383 100644
--- a/src/plugins/find/textfindconstants.h
+++ b/src/plugins/find/textfindconstants.h
@@ -59,6 +59,7 @@ const char REPLACE_ALL[] = "Find.ReplaceAll";
const char CASE_SENSITIVE[] = "Find.CaseSensitive";
const char WHOLE_WORDS[] = "Find.WholeWords";
const char REGULAR_EXPRESSIONS[] = "Find.RegularExpressions";
+const char PRESERVE_CASE[] = "Find.PreserveCase";
const char TASK_SEARCH[] = "Find.Task.Search";
} // namespace Constants
@@ -67,7 +68,8 @@ enum FindFlag {
FindBackward = 0x01,
FindCaseSensitively = 0x02,
FindWholeWords = 0x04,
- FindRegularExpression = 0x08
+ FindRegularExpression = 0x08,
+ FindPreserveCase = 0x10
};
Q_DECLARE_FLAGS(FindFlags, FindFlag)
diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp
index 48bd7b6c18..d31b1af533 100644
--- a/src/plugins/qmljseditor/qmljsfindreferences.cpp
+++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp
@@ -933,8 +933,8 @@ void FindReferences::displayResults(int first, int last)
m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(
label, QString(), symbolName, Find::SearchResultWindow::SearchAndReplace);
m_currentSearch->setTextToReplace(replacement);
- connect(m_currentSearch, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
- SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>)));
+ connect(m_currentSearch, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)),
+ SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)));
}
connect(m_currentSearch, SIGNAL(activated(Find::SearchResultItem)),
this, SLOT(openEditor(Find::SearchResultItem)));
@@ -996,9 +996,9 @@ void FindReferences::openEditor(const Find::SearchResultItem &item)
}
}
-void FindReferences::onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items)
+void FindReferences::onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items, bool preserveCase)
{
- const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items);
+ const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items, preserveCase);
// files that are opened in an editor are changed, but not saved
QStringList changedOnDisk;
diff --git a/src/plugins/qmljseditor/qmljsfindreferences.h b/src/plugins/qmljseditor/qmljsfindreferences.h
index 625a75bbd5..d6f6f50289 100644
--- a/src/plugins/qmljseditor/qmljsfindreferences.h
+++ b/src/plugins/qmljseditor/qmljsfindreferences.h
@@ -86,7 +86,7 @@ private Q_SLOTS:
void cancel();
void setPaused(bool paused);
void openEditor(const Find::SearchResultItem &item);
- void onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items);
+ void onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items, bool preserveCase);
private:
QPointer<Find::SearchResult> m_currentSearch;
diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp
index ee87ea1757..bc64ea484d 100644
--- a/src/plugins/texteditor/basefilefind.cpp
+++ b/src/plugins/texteditor/basefilefind.cpp
@@ -131,8 +131,8 @@ void BaseFileFind::runNewSearch(const QString &txt, Find::FindFlags findFlags,
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(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)),
+ this, SLOT(doReplace(QString,QList<Find::SearchResultItem>,bool)));
}
connect(search, SIGNAL(visibilityChanged(bool)), this, SLOT(hideHighlightAll(bool)));
connect(search, SIGNAL(cancelled()), this, SLOT(cancel()));
@@ -183,9 +183,10 @@ void BaseFileFind::replaceAll(const QString &txt, Find::FindFlags findFlags)
}
void BaseFileFind::doReplace(const QString &text,
- const QList<Find::SearchResultItem> &items)
+ const QList<Find::SearchResultItem> &items,
+ bool preserveCase)
{
- QStringList files = replaceAll(text, items);
+ QStringList files = replaceAll(text, items, preserveCase);
if (!files.isEmpty()) {
Core::DocumentManager::notifyFilesChangedInternally(files);
Find::SearchResultWindow::instance()->hide();
@@ -331,7 +332,8 @@ void BaseFileFind::searchAgain()
}
QStringList BaseFileFind::replaceAll(const QString &text,
- const QList<Find::SearchResultItem> &items)
+ const QList<Find::SearchResultItem> &items,
+ bool preserveCase)
{
if (items.isEmpty())
return QStringList();
@@ -358,10 +360,15 @@ QStringList BaseFileFind::replaceAll(const QString &text,
processed.insert(p);
QString replacement;
- if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty())
+ if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty()) {
replacement = Utils::expandRegExpReplacement(text, item.userData.toStringList());
- else
+ } else if (preserveCase) {
+ const QString originalText = (item.textMarkLength == 0) ? item.text
+ : item.text.mid(item.textMarkPos, item.textMarkLength);
+ replacement = Utils::matchCaseReplacement(originalText, text);
+ } else {
replacement = text;
+ }
const int start = file->position(item.lineNumber, item.textMarkPos + 1);
const int end = file->position(item.lineNumber,
diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h
index e7451f5bd8..c4d78d72f9 100644
--- a/src/plugins/texteditor/basefilefind.h
+++ b/src/plugins/texteditor/basefilefind.h
@@ -71,7 +71,8 @@ public:
/* returns the list of unique files that were passed in items */
static QStringList replaceAll(const QString &txt,
- const QList<Find::SearchResultItem> &items);
+ const QList<Find::SearchResultItem> &items,
+ bool preserveCase = false);
protected:
virtual Utils::FileIterator *files(const QStringList &nameFilters,
@@ -95,7 +96,8 @@ private slots:
void setPaused(bool paused);
void openEditor(const Find::SearchResultItem &item);
void doReplace(const QString &txt,
- const QList<Find::SearchResultItem> &items);
+ const QList<Find::SearchResultItem> &items,
+ bool preserveCase);
void hideHighlightAll(bool visible);
void searchAgain();
diff --git a/tests/auto/filesearch/tst_filesearch.cpp b/tests/auto/filesearch/tst_filesearch.cpp
index c610d6c5a9..a2d1d47882 100644
--- a/tests/auto/filesearch/tst_filesearch.cpp
+++ b/tests/auto/filesearch/tst_filesearch.cpp
@@ -51,6 +51,7 @@ private slots:
void multipleResults();
void caseSensitive();
void caseInSensitive();
+ void matchCaseReplacement();
};
namespace {
@@ -99,6 +100,49 @@ void tst_FileSearch::caseInSensitive()
test_helper(expectedResults, QLatin1String("CaseSensitive"), QTextDocument::FindFlags(0));
}
+void tst_FileSearch::matchCaseReplacement()
+{
+ QCOMPARE(Utils::matchCaseReplacement("", "foobar"), QString("foobar")); //empty string
+
+ QCOMPARE(Utils::matchCaseReplacement("testpad", "foobar"), QString("foobar")); //lower case
+ QCOMPARE(Utils::matchCaseReplacement("TESTPAD", "foobar"), QString("FOOBAR")); //upper case
+ QCOMPARE(Utils::matchCaseReplacement("Testpad", "foobar"), QString("Foobar")); //capitalized
+ QCOMPARE(Utils::matchCaseReplacement("tESTPAD", "foobar"), QString("fOOBAR")); //un-capitalized
+ QCOMPARE(Utils::matchCaseReplacement("tEsTpAd", "foobar"), QString("foobar")); //mixed case, use replacement as specified
+ QCOMPARE(Utils::matchCaseReplacement("TeStPaD", "foobar"), QString("foobar")); //mixed case, use replacement as specified
+
+ QCOMPARE(Utils::matchCaseReplacement("testpad", "fooBar"), QString("foobar")); //lower case
+ QCOMPARE(Utils::matchCaseReplacement("TESTPAD", "fooBar"), QString("FOOBAR")); //upper case
+ QCOMPARE(Utils::matchCaseReplacement("Testpad", "fooBar"), QString("Foobar")); //capitalized
+ QCOMPARE(Utils::matchCaseReplacement("tESTPAD", "fooBar"), QString("fOOBAR")); //un-capitalized
+ QCOMPARE(Utils::matchCaseReplacement("tEsTpAd", "fooBar"), QString("fooBar")); //mixed case, use replacement as specified
+ QCOMPARE(Utils::matchCaseReplacement("TeStPaD", "fooBar"), QString("fooBar")); //mixed case, use replacement as specified
+
+ //with common prefix
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXtestpad", "prefixfoobar"), QString("pReFiXfoobar")); //lower case
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXTESTPAD", "prefixfoobar"), QString("pReFiXFOOBAR")); //upper case
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXTestpad", "prefixfoobar"), QString("pReFiXFoobar")); //capitalized
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXtESTPAD", "prefixfoobar"), QString("pReFiXfOOBAR")); //un-capitalized
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXtEsTpAd", "prefixfoobar"), QString("pReFiXfoobar")); //mixed case, use replacement as specified
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXTeStPaD", "prefixfoobar"), QString("pReFiXfoobar")); //mixed case, use replacement as specified
+
+ //with common suffix
+ QCOMPARE(Utils::matchCaseReplacement("testpadSuFfIx", "foobarsuffix"), QString("foobarSuFfIx")); //lower case
+ QCOMPARE(Utils::matchCaseReplacement("TESTPADSuFfIx", "foobarsuffix"), QString("FOOBARSuFfIx")); //upper case
+ QCOMPARE(Utils::matchCaseReplacement("TestpadSuFfIx", "foobarsuffix"), QString("FoobarSuFfIx")); //capitalized
+ QCOMPARE(Utils::matchCaseReplacement("tESTPADSuFfIx", "foobarsuffix"), QString("fOOBARSuFfIx")); //un-capitalized
+ QCOMPARE(Utils::matchCaseReplacement("tEsTpAdSuFfIx", "foobarsuffix"), QString("foobarSuFfIx")); //mixed case, use replacement as specified
+ QCOMPARE(Utils::matchCaseReplacement("TeStPaDSuFfIx", "foobarsuffix"), QString("foobarSuFfIx")); //mixed case, use replacement as specified
+
+ //with common prefix and suffix
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXtestpadSuFfIx", "prefixfoobarsuffix"), QString("pReFiXfoobarSuFfIx")); //lower case
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXTESTPADSuFfIx", "prefixfoobarsuffix"), QString("pReFiXFOOBARSuFfIx")); //upper case
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXTestpadSuFfIx", "prefixfoobarsuffix"), QString("pReFiXFoobarSuFfIx")); //capitalized
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXtESTPADSuFfIx", "prefixfoobarsuffix"), QString("pReFiXfOOBARSuFfIx")); //un-capitalized
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXtEsTpAdSuFfIx", "prefixfoobarsuffix"), QString("pReFiXfoobarSuFfIx")); //mixed case, use replacement as specified
+ QCOMPARE(Utils::matchCaseReplacement("pReFiXTeStPaDSuFfIx", "prefixfoobarsuffix"), QString("pReFiXfoobarSuFfIx")); //mixed case, use replacement as specified
+}
+
QTEST_MAIN(tst_FileSearch)
#include "tst_filesearch.moc"