Core: Streamline SearchResultWindow interface

That is, make SearchResultItem the one data type for adding search
results.
This will allow us to add additional properties to search results
without adding more and more parameters to a bunch of functions.

Change-Id: Ic2740477ae47449cee75caa2525727fe2b460f91
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Christian Kandeler
2021-02-11 16:22:48 +01:00
parent fa5fdef6e1
commit d3deefc3a4
17 changed files with 136 additions and 157 deletions

View File

@@ -3118,14 +3118,14 @@ void EditorManager::openEditorAtSearchResult(const SearchResultItem &item,
OpenEditorFlags flags,
bool *newEditor)
{
if (item.path.empty()) {
openEditor(QDir::fromNativeSeparators(item.text), editorId, flags, newEditor);
if (item.path().empty()) {
openEditor(QDir::fromNativeSeparators(item.lineText()), editorId, flags, newEditor);
return;
}
openEditorAt(QDir::fromNativeSeparators(item.path.first()),
item.mainRange.begin.line,
item.mainRange.begin.column,
openEditorAt(QDir::fromNativeSeparators(item.path().first()),
item.mainRange().begin.line,
item.mainRange().begin.column,
editorId,
flags,
newEditor);

View File

@@ -27,6 +27,7 @@
#include "searchresultcolor.h"
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <QIcon>
@@ -87,16 +88,50 @@ public:
} // namespace Search
class SearchResultItem
class CORE_EXPORT SearchResultItem
{
public:
QStringList path; // hierarchy to the parent item of this item
QString text; // text to show for the item itself
QIcon icon; // icon to show in front of the item (by be null icon to hide)
QVariant userData; // user data for identification of the item
Search::TextRange mainRange;
bool useTextEditorFont = false;
SearchResultColor::Style style = SearchResultColor::Style::Default;
QStringList path() const { return m_path; }
void setPath(const QStringList &path) { m_path = path; }
void setFilePath(const Utils::FilePath &filePath)
{
m_path = QStringList{filePath.toUserOutput()};
}
QString lineText() const { return m_lineText; }
void setLineText(const QString &text) { m_lineText = text; }
QIcon icon() const { return m_icon; }
void setIcon(const QIcon &icon) { m_icon = icon; }
QVariant userData() const { return m_userData; }
void setUserData(const QVariant &userData) { m_userData = userData; }
Search::TextRange mainRange() const { return m_mainRange; }
void setMainRange(const Search::TextRange &mainRange) { m_mainRange = mainRange; }
void setMainRange(int line, int column, int length)
{
m_mainRange = {};
m_mainRange.begin.line = line;
m_mainRange.begin.column = column;
m_mainRange.end.line = m_mainRange.begin.line;
m_mainRange.end.column = m_mainRange.begin.column + length;
}
bool useTextEditorFont() const { return m_useTextEditorFont; }
void setUseTextEditorFont(bool useTextEditorFont) { m_useTextEditorFont = useTextEditorFont; }
SearchResultColor::Style style() const { return m_style; }
void setStyle(SearchResultColor::Style style) { m_style = style; }
private:
QStringList m_path; // hierarchy to the parent item of this item
QString m_lineText; // text to show for the item itself
QIcon m_icon; // icon to show in front of the item (by be null icon to hide)
QVariant m_userData; // user data for identification of the item
Search::TextRange m_mainRange;
bool m_useTextEditorFont = false;
SearchResultColor::Style m_style = SearchResultColor::Style::Default;
};
} // namespace Core

View File

@@ -85,7 +85,7 @@ SearchResultTreeItem *SearchResultTreeItem::parent() const
static bool lessThanByText(SearchResultTreeItem *a, const QString &b)
{
return a->item.text < b;
return a->item.lineText() < b;
}
int SearchResultTreeItem::insertionIndex(const QString &text, SearchResultTreeItem **existingItem) const
@@ -93,7 +93,7 @@ int SearchResultTreeItem::insertionIndex(const QString &text, SearchResultTreeIt
QList<SearchResultTreeItem *>::const_iterator insertionPosition =
std::lower_bound(m_children.begin(), m_children.end(), text, lessThanByText);
if (existingItem) {
if (insertionPosition != m_children.end() && (*insertionPosition)->item.text == text)
if (insertionPosition != m_children.end() && (*insertionPosition)->item.lineText() == text)
(*existingItem) = (*insertionPosition);
else
*existingItem = nullptr;
@@ -103,7 +103,7 @@ int SearchResultTreeItem::insertionIndex(const QString &text, SearchResultTreeIt
int SearchResultTreeItem::insertionIndex(const SearchResultItem &item, SearchResultTreeItem **existingItem) const
{
return insertionIndex(item.text, existingItem);
return insertionIndex(item.lineText(), existingItem);
}
void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child)

View File

@@ -294,44 +294,44 @@ QVariant SearchResultTreeModel::data(const SearchResultTreeItem *row, int role)
result = row->checkState();
break;
case Qt::ToolTipRole:
result = row->item.text.trimmed();
result = row->item.lineText().trimmed();
break;
case Qt::FontRole:
if (row->item.useTextEditorFont)
if (row->item.useTextEditorFont())
result = m_textEditorFont;
else
result = QVariant();
break;
case Qt::ForegroundRole:
result = m_colors.value(row->item.style).textForeground;
result = m_colors.value(row->item.style()).textForeground;
break;
case Qt::BackgroundRole:
result = m_colors.value(row->item.style).textBackground;
result = m_colors.value(row->item.style()).textBackground;
break;
case ItemDataRoles::ResultLineRole:
case Qt::DisplayRole:
result = row->item.text;
result = row->item.lineText();
break;
case ItemDataRoles::ResultItemRole:
result = QVariant::fromValue(row->item);
break;
case ItemDataRoles::ResultBeginLineNumberRole:
result = row->item.mainRange.begin.line;
result = row->item.mainRange().begin.line;
break;
case ItemDataRoles::ResultIconRole:
result = row->item.icon;
result = row->item.icon();
break;
case ItemDataRoles::ResultHighlightBackgroundColor:
result = m_colors.value(row->item.style).highlightBackground;
result = m_colors.value(row->item.style()).highlightBackground;
break;
case ItemDataRoles::ResultHighlightForegroundColor:
result = m_colors.value(row->item.style).highlightForeground;
result = m_colors.value(row->item.style()).highlightForeground;
break;
case ItemDataRoles::ResultBeginColumnNumberRole:
result = row->item.mainRange.begin.column;
result = row->item.mainRange().begin.column;
break;
case ItemDataRoles::SearchTermLengthRole:
result = row->item.mainRange.length(row->item.text);
result = row->item.mainRange().length(row->item.lineText());
break;
case ItemDataRoles::IsGeneratedRole:
result = row->isGenerated();
@@ -368,8 +368,8 @@ QSet<SearchResultTreeItem *> SearchResultTreeModel::addPath(const QStringList &p
const int insertionIndex = currentItem->insertionIndex(part, &partItem);
if (!partItem) {
SearchResultItem item;
item.path = currentPath;
item.text = part;
item.setPath(currentPath);
item.setLineText(part);
partItem = new SearchResultTreeItem(item, currentItem);
if (m_showReplaceUI)
partItem->setCheckState(Qt::Checked);
@@ -423,14 +423,14 @@ void SearchResultTreeModel::addResultsToCurrentParent(const QList<SearchResultIt
static bool lessThanByPath(const SearchResultItem &a, const SearchResultItem &b)
{
if (a.path.size() < b.path.size())
if (a.path().size() < b.path().size())
return true;
if (a.path.size() > b.path.size())
if (a.path().size() > b.path().size())
return false;
for (int i = 0; i < a.path.size(); ++i) {
if (a.path.at(i) < b.path.at(i))
for (int i = 0; i < a.path().size(); ++i) {
if (a.path().at(i) < b.path().at(i))
return true;
if (a.path.at(i) > b.path.at(i))
if (a.path().at(i) > b.path().at(i))
return false;
}
return false;
@@ -447,15 +447,15 @@ QList<QModelIndex> SearchResultTreeModel::addResults(const QList<SearchResultIte
std::stable_sort(sortedItems.begin(), sortedItems.end(), lessThanByPath);
QList<SearchResultItem> itemSet;
foreach (const SearchResultItem &item, sortedItems) {
m_editorFontIsUsed |= item.useTextEditorFont;
if (!m_currentParent || (m_currentPath != item.path)) {
m_editorFontIsUsed |= item.useTextEditorFont();
if (!m_currentParent || (m_currentPath != item.path())) {
// first add all the items from before
if (!itemSet.isEmpty()) {
addResultsToCurrentParent(itemSet, mode);
itemSet.clear();
}
// switch parent
pathNodes += addPath(item.path);
pathNodes += addPath(item.path());
}
itemSet << item;
}
@@ -642,7 +642,7 @@ bool SearchResultFilterModel::filterAcceptsRow(int source_row,
return false;
if (!m_filter)
return true;
if (item->item.userData.isValid())
if (item->item.userData().isValid())
return m_filter->matches(item->item);
const int childCount = sourceModel()->rowCount(idx);
for (int i = 0; i < childCount; ++i) {

View File

@@ -247,22 +247,6 @@ void SearchResultWidget::setAdditionalReplaceWidget(QWidget *widget)
m_additionalReplaceWidget = widget;
}
void SearchResultWidget::addResult(const QString &fileName,
const QString &rowText,
Search::TextRange mainRange,
const QVariant &userData,
SearchResultColor::Style style)
{
SearchResultItem item;
item.path = QStringList({QDir::toNativeSeparators(fileName)});
item.mainRange = mainRange;
item.text = rowText;
item.useTextEditorFont = true;
item.userData = userData;
item.style = style;
addResults(QList<SearchResultItem>() << item, SearchResult::AddOrdered);
}
void SearchResultWidget::addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode)
{
bool firstItems = (m_count == 0);

View File

@@ -55,11 +55,6 @@ public:
QWidget *additionalReplaceWidget() const;
void setAdditionalReplaceWidget(QWidget *widget);
void addResult(const QString &fileName,
const QString &lineText,
Search::TextRange mainRange,
const QVariant &userData = QVariant(),
SearchResultColor::Style style = SearchResultColor::Style::Default);
void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
int count() const;

View File

@@ -803,48 +803,18 @@ void SearchResult::setAdditionalReplaceWidget(QWidget *widget)
/*!
Adds a single result line to the \uicontrol {Search Results} output pane.
\a fileName, \a lineNumber, and \a lineText are shown on the result line.
\a searchTermStart and \a searchTermLength specify the region that
should be visually marked (string position and length in \a lineText).
You can attach arbitrary \a userData to the search result, which can
be used, for example, when reacting to the signals of the search results
for your search.
\sa addResults()
*/
void SearchResult::addResult(const QString &fileName, int lineNumber, const QString &lineText,
int searchTermStart, int searchTermLength, const QVariant &userData,
SearchResultColor::Style style)
{
Search::TextRange mainRange;
mainRange.begin.line = lineNumber;
mainRange.begin.column = searchTermStart;
mainRange.end.line = mainRange.begin.line;
mainRange.end.column = mainRange.begin.column + searchTermLength;
m_widget->addResult(fileName, lineText, mainRange, userData, style);
}
/*!
Adds a single result line to the \uicontrol {Search Results} output pane.
\a mainRange specifies the region from the beginning of the search term
\a {item}.mainRange() specifies the region from the beginning of the search term
through its length that should be visually marked.
\a fileName and \a lineText are shown on the result line.
You can attach arbitrary \a userData to the search result, which can
\a {item}.path(), \a {item}.text() are shown on the result line.
You can attach arbitrary \a {item}.userData() to the search result, which can
be used, for example, when reacting to the signals of the search results
for your search.
\sa addResults()
*/
void SearchResult::addResult(const QString &fileName,
const QString &lineText,
Search::TextRange mainRange,
const QVariant &userData,
SearchResultColor::Style style)
void SearchResult::addResult(const SearchResultItem &item)
{
m_widget->addResult(fileName, lineText, mainRange, userData, style);
emit countChanged(m_widget->count());
m_widget->addResults({item}, AddSorted);
}
/*!

View File

@@ -76,18 +76,7 @@ public:
void setAdditionalReplaceWidget(QWidget *widget);
public slots:
void addResult(const QString &fileName,
int lineNumber,
const QString &lineText,
int searchTermStart,
int searchTermLength,
const QVariant &userData = QVariant(),
SearchResultColor::Style style = SearchResultColor::Style::Default);
void addResult(const QString &fileName,
const QString &lineText,
Search::TextRange mainRange,
const QVariant &userData = QVariant(),
SearchResultColor::Style style = SearchResultColor::Style::Default);
void addResult(const SearchResultItem &item);
void addResults(const QList<SearchResultItem> &items, AddMode mode);
void setFilter(SearchResultFilter *filter); // Takes ownership
void finishSearch(bool canceled);

View File

@@ -417,7 +417,11 @@ static void addSearchResults(CppTools::Usages usages, SearchResult &search, cons
if (!lineContent.isEmpty()) {
Search::TextRange range{Search::TextPosition(usage.line, usage.column - 1),
Search::TextPosition(usage.line, usage.column + text.length() - 1)};
search.addResult(usage.path, lineContent, range);
SearchResultItem item;
item.setFilePath(FilePath::fromString(usage.path));
item.setLineText(lineContent);
item.setMainRange(range);
search.addResult(item);
}
}
}

View File

@@ -308,10 +308,10 @@ public:
}
Core::SearchResultItem item;
item.path = scope.split(QLatin1String("::"), Qt::SkipEmptyParts);
item.text = text;
item.icon = info->icon();
item.userData = QVariant::fromValue(info);
item.setPath(scope.split(QLatin1String("::"), Qt::SkipEmptyParts));
item.setLineText(text);
item.setIcon(info->icon());
item.setUserData(QVariant::fromValue(info));
resultItems << item;
}

View File

@@ -202,7 +202,7 @@ class Filter : public Core::SearchResultFilter
bool matches(const SearchResultItem &item) const override
{
switch (static_cast<CPlusPlus::Usage::Type>(item.userData.toInt())) {
switch (static_cast<CPlusPlus::Usage::Type>(item.userData().toInt())) {
case CPlusPlus::Usage::Type::Read:
return m_showReads;
case CPlusPlus::Usage::Type::Write:
@@ -630,9 +630,13 @@ static void displayResults(SearchResult *search, QFutureWatcher<CPlusPlus::Usage
};
for (int index = first; index != last; ++index) {
const CPlusPlus::Usage result = watcher->future().resultAt(index);
search->addResult(result.path.toString(), result.line, result.lineText,
result.col, result.len, int(result.type),
colorStyleForUsageType(result.type));
SearchResultItem item;
item.setFilePath(result.path);
item.setMainRange(result.line, result.col, result.len);
item.setLineText(result.lineText);
item.setUserData(int(result.type));
item.setStyle(colorStyleForUsageType(result.type));
search->addResult(item);
if (parameters.prettySymbolName.isEmpty())
continue;
@@ -823,8 +827,11 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro &macro, const QStri
unsigned column;
const QString line = FindMacroUsesInFile::matchingLine(macro.bytesOffset(), source,
&column);
search->addResult(macro.fileName(), macro.line(), line, column,
macro.nameToQString().length());
SearchResultItem item;
item.setFilePath(Utils::FilePath::fromString(macro.fileName()));
item.setLineText(line);
item.setMainRange(macro.line(), column, macro.nameToQString().length());
search->addResult(item);
}
QFuture<CPlusPlus::Usage> result;

View File

@@ -64,7 +64,7 @@ public:
{
ResultDataList result;
for (const Core::SearchResultItem &entry : entries)
result << ResultData(entry.text, entry.path.join(QLatin1String("::")));
result << ResultData(entry.lineText(), entry.path().join(QLatin1String("::")));
return result;
}

View File

@@ -176,9 +176,9 @@ void SymbolsFindFilter::finish()
void SymbolsFindFilter::openEditor(const SearchResultItem &item)
{
if (!item.userData.canConvert<IndexItem::Ptr>())
if (!item.userData().canConvert<IndexItem::Ptr>())
return;
IndexItem::Ptr info = item.userData.value<IndexItem::Ptr>();
IndexItem::Ptr info = item.userData().value<IndexItem::Ptr>();
EditorManager::openEditorAt(info->fileName(), info->line(), info->column());
}

View File

@@ -312,13 +312,13 @@ IEditor *GitGrep::openEditor(const SearchResultItem &item,
const TextEditor::FileFindParameters &parameters)
{
GitGrepParameters params = parameters.searchEngineParameters.value<GitGrepParameters>();
if (params.ref.isEmpty() || item.path.isEmpty())
if (params.ref.isEmpty() || item.path().isEmpty())
return nullptr;
const QString path = QDir::fromNativeSeparators(item.path.first());
const QString path = QDir::fromNativeSeparators(item.path().first());
const QString topLevel = parameters.additionalParameters.toString();
IEditor *editor = m_client->openShowEditor(
topLevel, params.ref, path, GitClient::ShowEditor::OnlyIfDifferent);
editor->gotoLine(item.mainRange.begin.line, item.mainRange.begin.column);
editor->gotoLine(item.mainRange().begin.line, item.mainRange().begin.column);
return editor;
}

View File

@@ -170,17 +170,15 @@ QList<Core::SearchResultItem> generateSearchResultItems(
const QString &fileName = it.key();
Core::SearchResultItem item;
item.path = QStringList() << fileName;
item.useTextEditorFont = true;
item.setFilePath(Utils::FilePath::fromString(fileName));
item.setUseTextEditorFont(true);
QStringList lines = getFileContents(fileName);
for (const ItemData &data : it.value()) {
item.mainRange = data.range;
item.setMainRange(data.range);
if (data.range.begin.line > 0 && data.range.begin.line <= lines.size())
item.text = lines[data.range.begin.line - 1];
else
item.text.clear();
item.userData = data.userData;
item.setLineText(lines[data.range.begin.line - 1]);
item.setUserData(data.userData);
result << item;
}
}
@@ -411,8 +409,8 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem
{
QMap<DocumentUri, QList<TextEdit>> editsForDocuments;
for (const Core::SearchResultItem &item : checkedItems) {
auto uri = DocumentUri::fromFilePath(Utils::FilePath::fromString(item.path.value(0)));
TextEdit edit(item.userData.toJsonObject());
auto uri = DocumentUri::fromFilePath(Utils::FilePath::fromString(item.path().value(0)));
TextEdit edit(item.userData().toJsonObject());
if (edit.isValid(nullptr))
editsForDocuments[uri] << edit;
}

View File

@@ -1008,11 +1008,11 @@ void FindReferences::displayResults(int first, int last)
}
for (int index = first; index != last; ++index) {
Usage result = m_watcher.future().resultAt(index);
m_currentSearch->addResult(result.path,
result.line,
result.lineText,
result.col,
result.len);
SearchResultItem item;
item.setFilePath(Utils::FilePath::fromString(result.path));
item.setLineText(result.lineText);
item.setMainRange(result.line, result.col, result.len);
m_currentSearch->addResult(item);
}
}

View File

@@ -234,14 +234,11 @@ static void displayResult(QFutureWatcher<FileSearchResultList> *watcher,
QList<SearchResultItem> items;
for (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;
item.setFilePath(Utils::FilePath::fromString(result.fileName));
item.setMainRange(result.lineNumber, result.matchStart, result.matchLength);
item.setLineText(result.matchingLine);
item.setUseTextEditorFont(true);
item.setUserData(result.regexpCapturedTexts);
items << item;
}
search->addResults(items, SearchResult::AddOrdered);
@@ -493,7 +490,7 @@ QStringList BaseFileFind::replaceAll(const QString &text,
QHash<QString, QList<SearchResultItem> > changes;
for (const SearchResultItem &item : items)
changes[QDir::fromNativeSeparators(item.path.first())].append(item);
changes[QDir::fromNativeSeparators(item.path().first())].append(item);
// Checking for files without write permissions
QSet<FilePath> roFiles;
@@ -519,28 +516,28 @@ QStringList BaseFileFind::replaceAll(const QString &text,
RefactoringFilePtr file = refactoring.file(fileName);
QSet<QPair<int, int> > processed;
for (const SearchResultItem &item : changeItems) {
const QPair<int, int> &p = qMakePair(item.mainRange.begin.line,
item.mainRange.begin.column);
const QPair<int, int> &p = qMakePair(item.mainRange().begin.line,
item.mainRange().begin.column);
if (processed.contains(p))
continue;
processed.insert(p);
QString replacement;
if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty()) {
replacement = Utils::expandRegExpReplacement(text, item.userData.toStringList());
if (item.userData().canConvert<QStringList>() && !item.userData().toStringList().isEmpty()) {
replacement = Utils::expandRegExpReplacement(text, item.userData().toStringList());
} else if (preserveCase) {
const QString originalText = (item.mainRange.length(item.text) == 0)
? item.text
: item.mainRange.mid(item.text);
const QString originalText = (item.mainRange().length(item.lineText()) == 0)
? item.lineText()
: item.mainRange().mid(item.lineText());
replacement = Utils::matchCaseReplacement(originalText, text);
} else {
replacement = text;
}
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);
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);
changeSet.replace(start, end, replacement);
}
file->setChangeSet(changeSet);