forked from qt-creator/qt-creator
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>
This commit is contained in:
committed by
Eike Ziller
parent
a8a33b9a3b
commit
058d2e8cb5
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"));
|
||||
|
||||
BIN
src/plugins/find/images/preservecase.png
Normal file
BIN
src/plugins/find/images/preservecase.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 196 B |
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user