ui: Added second line to search autocompletion list showing namespace or filepath
* Show namespace or filepath in second line of search autocompletions * Add filepaths relative to .coatidb location * Rescore matches to acknowledge line split * Fixed SearchMatch type to be drawn always visible at right edge
This commit is contained in:
@@ -20,9 +20,10 @@
|
|||||||
|
|
||||||
<popup>
|
<popup>
|
||||||
<text>#3D3D3D</text>
|
<text>#3D3D3D</text>
|
||||||
<by_text>#A0A0A0</by_text>
|
<by_text>#808080</by_text>
|
||||||
<background>#CCCCCC</background>
|
<background>#CCCCCC</background>
|
||||||
<highlight>#FFFFFF</highlight>
|
<highlight>#FFFFFF</highlight>
|
||||||
|
<line>#B1B1B1</line>
|
||||||
</popup>
|
</popup>
|
||||||
|
|
||||||
<query>
|
<query>
|
||||||
|
|||||||
@@ -20,9 +20,10 @@
|
|||||||
|
|
||||||
<popup>
|
<popup>
|
||||||
<text>black</text>
|
<text>black</text>
|
||||||
<by_text>#A0A0A0</by_text>
|
<by_text>#626262</by_text>
|
||||||
<background>white</background>
|
<background>white</background>
|
||||||
<highlight>#B2B2B2</highlight>
|
<highlight>#D0D0D0</highlight>
|
||||||
|
<line>#E0E0E0</line>
|
||||||
</popup>
|
</popup>
|
||||||
|
|
||||||
<query>
|
<query>
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
<text>#F7F7F7</text>
|
<text>#F7F7F7</text>
|
||||||
<by_text>#A0A0A0</by_text>
|
<by_text>#A0A0A0</by_text>
|
||||||
<background>#272728</background>
|
<background>#272728</background>
|
||||||
<highlight>#555555</highlight>
|
<highlight>#333333</highlight>
|
||||||
|
<line>#444444</line>
|
||||||
</popup>
|
</popup>
|
||||||
|
|
||||||
<query>
|
<query>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 491 B |
@@ -159,7 +159,7 @@ void FeatureController::handleMessage(MessageSearch* message)
|
|||||||
MessageActivateTokens m(message, tokenIds);
|
MessageActivateTokens m(message, tokenIds);
|
||||||
for (const SearchMatch& match : matches)
|
for (const SearchMatch& match : matches)
|
||||||
{
|
{
|
||||||
m.unknownNames.push_back(match.text);
|
m.unknownNames.push_back(match.name);
|
||||||
}
|
}
|
||||||
if (!message->isReplayed())
|
if (!message->isReplayed())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -121,6 +121,32 @@ Id HierarchyCache::getLastVisibleParentNodeId(Id nodeId) const
|
|||||||
return nodeId;
|
return nodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t HierarchyCache::getIndexOfLastVisibleParentNode(Id nodeId) const
|
||||||
|
{
|
||||||
|
HierarchyNode* node = nullptr;
|
||||||
|
HierarchyNode* parent = getNode(nodeId);
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
|
bool visible = false;
|
||||||
|
|
||||||
|
while (parent)
|
||||||
|
{
|
||||||
|
node = parent;
|
||||||
|
parent = node->getParent();
|
||||||
|
|
||||||
|
if (node->isVisible())
|
||||||
|
{
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
else if (visible)
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
void HierarchyCache::addAllChildIdsForNodeId(Id nodeId, std::vector<Id>* nodeIds, std::vector<Id>* edgeIds) const
|
void HierarchyCache::addAllChildIdsForNodeId(Id nodeId, std::vector<Id>* nodeIds, std::vector<Id>* edgeIds) const
|
||||||
{
|
{
|
||||||
HierarchyNode* node = getNode(nodeId);
|
HierarchyNode* node = getNode(nodeId);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public:
|
|||||||
void createConnection(Id edgeId, Id fromId, Id toId, bool fromVisible);
|
void createConnection(Id edgeId, Id fromId, Id toId, bool fromVisible);
|
||||||
|
|
||||||
Id getLastVisibleParentNodeId(Id nodeId) const;
|
Id getLastVisibleParentNodeId(Id nodeId) const;
|
||||||
|
size_t getIndexOfLastVisibleParentNode(Id nodeId) const;
|
||||||
|
|
||||||
void addAllChildIdsForNodeId(Id nodeId, std::vector<Id>* nodeIds, std::vector<Id>* edgeIds) const;
|
void addAllChildIdsForNodeId(Id nodeId, std::vector<Id>* nodeIds, std::vector<Id>* edgeIds) const;
|
||||||
void addFirstChildIdsForNodeId(Id nodeId, std::vector<Id>* nodeIds) const;
|
void addFirstChildIdsForNodeId(Id nodeId, std::vector<Id>* nodeIds) const;
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
PersistentStorage::PersistentStorage(const FilePath& dbPath)
|
PersistentStorage::PersistentStorage(const FilePath& dbPath)
|
||||||
: m_sqliteStorage(dbPath)
|
: m_sqliteStorage(dbPath)
|
||||||
{
|
{
|
||||||
m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL)));
|
m_commandIndex.addNode(0, SearchMatch::getCommandName(SearchMatch::COMMAND_ALL));
|
||||||
m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR)));
|
m_commandIndex.addNode(0, SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR));
|
||||||
// m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_COLOR_SCHEME_TEST)));
|
// m_commandIndex.addNode(0, SearchMatch::getCommandName(SearchMatch::COMMAND_COLOR_SCHEME_TEST));
|
||||||
m_commandIndex.finishSetup();
|
m_commandIndex.finishSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +275,7 @@ void PersistentStorage::clear()
|
|||||||
void PersistentStorage::clearCaches()
|
void PersistentStorage::clearCaches()
|
||||||
{
|
{
|
||||||
m_elementIndex.clear();
|
m_elementIndex.clear();
|
||||||
|
m_fileIndex.clear();
|
||||||
m_fileNodeIds.clear();
|
m_fileNodeIds.clear();
|
||||||
m_fileNodePaths.clear();
|
m_fileNodePaths.clear();
|
||||||
m_hierarchyCache.clear();
|
m_hierarchyCache.clear();
|
||||||
@@ -344,8 +345,8 @@ void PersistentStorage::buildCaches()
|
|||||||
|
|
||||||
clearCaches();
|
clearCaches();
|
||||||
|
|
||||||
buildSearchIndex();
|
|
||||||
buildFilePathMaps();
|
buildFilePathMaps();
|
||||||
|
buildSearchIndex();
|
||||||
buildHierarchyCache();
|
buildHierarchyCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,55 +479,14 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionMatches(const std::
|
|||||||
{
|
{
|
||||||
TRACE();
|
TRACE();
|
||||||
|
|
||||||
std::vector<SearchResult> commandResults = m_commandIndex.search(query, 0);
|
// search in indices
|
||||||
|
size_t maxResultsCount = 100;
|
||||||
const size_t maxResultCount = 100;
|
|
||||||
std::vector<SearchResult> elementResults = m_elementIndex.search(query, maxResultCount);
|
|
||||||
|
|
||||||
std::vector<SearchResult> results;
|
std::vector<SearchResult> results;
|
||||||
utility::append(results, commandResults);
|
utility::append(results, m_commandIndex.search(query, 0));
|
||||||
utility::append(results, elementResults);
|
utility::append(results, m_elementIndex.search(query, maxResultsCount, 100));
|
||||||
|
utility::append(results, m_fileIndex.search(query, 20));
|
||||||
std::sort(results.begin(), results.end(),
|
|
||||||
[](const SearchResult& a, const SearchResult& b)
|
|
||||||
{
|
|
||||||
// should a be ranked higher than b?
|
|
||||||
if (a.score > b.score)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (a.score == b.score)
|
|
||||||
{
|
|
||||||
if (a.text.size() < b.text.size())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (a.text.size() == b.text.size())
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < a.text.size(); i++)
|
|
||||||
{
|
|
||||||
if (tolower(a.text[i]) != tolower(b.text[i]))
|
|
||||||
{
|
|
||||||
return tolower(a.text[i]) < tolower(b.text[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (a.text[i] < b.text[i])
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (a.text[i] > b.text[i])
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// fetch StorageNodes for node ids
|
||||||
std::map<Id, StorageNode> storageNodesMap;
|
std::map<Id, StorageNode> storageNodesMap;
|
||||||
{
|
{
|
||||||
std::vector<Id> elementIds;
|
std::vector<Id> elementIds;
|
||||||
@@ -547,7 +507,8 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionMatches(const std::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SearchMatch> matches;
|
// create SearchMatches
|
||||||
|
std::set<SearchMatch> matches;
|
||||||
for (const SearchResult& result : results)
|
for (const SearchResult& result : results)
|
||||||
{
|
{
|
||||||
SearchMatch match;
|
SearchMatch match;
|
||||||
@@ -572,14 +533,41 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionMatches(const std::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match.text = result.text;
|
match.name = result.text;
|
||||||
match.indices = result.indices;
|
match.indices = result.indices;
|
||||||
|
match.score = result.score;
|
||||||
|
|
||||||
if (firstNode)
|
if (firstNode)
|
||||||
{
|
{
|
||||||
match.nodeType = Node::intToType(firstNode->type);
|
match.nodeType = Node::intToType(firstNode->type);
|
||||||
match.typeName = Node::getTypeString(match.nodeType);
|
match.typeName = Node::getTypeString(match.nodeType);
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
|
if (match.nodeType == Node::NODE_FILE)
|
||||||
|
{
|
||||||
|
idx = 1;
|
||||||
|
|
||||||
|
FilePath path(match.name);
|
||||||
|
match.text = path.fileName();
|
||||||
|
match.subtext = path.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = m_hierarchyCache.getIndexOfLastVisibleParentNode(firstNode->id);
|
||||||
|
const NameHierarchy& name = match.nameHierarchies[0];
|
||||||
|
|
||||||
|
match.text = name.getRange(idx, name.size()).getQualifiedName();
|
||||||
|
match.subtext = name.getRange(0, idx).getQualifiedName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// rescore match
|
||||||
|
if (idx && match.indices.size())
|
||||||
|
{
|
||||||
|
SearchResult newResult = SearchIndex::rescoreText(match.name, match.text, match.indices, match.score);
|
||||||
|
match.score = newResult.score;
|
||||||
|
match.indices = newResult.indices;
|
||||||
|
}
|
||||||
|
|
||||||
if (intToDefinitionType(firstNode->definitionType) == DEFINITION_NONE
|
if (intToDefinitionType(firstNode->definitionType) == DEFINITION_NONE
|
||||||
&& match.nodeType != Node::NODE_UNDEFINED)
|
&& match.nodeType != Node::NODE_UNDEFINED)
|
||||||
{
|
{
|
||||||
@@ -593,10 +581,16 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionMatches(const std::
|
|||||||
match.typeName = "command";
|
match.typeName = "command";
|
||||||
}
|
}
|
||||||
|
|
||||||
matches.push_back(match);
|
matches.insert(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches;
|
std::vector<SearchMatch> matchesVector = utility::toVector(matches);
|
||||||
|
if (matchesVector.size() > maxResultsCount)
|
||||||
|
{
|
||||||
|
matchesVector.resize(maxResultsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchesVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SearchMatch> PersistentStorage::getSearchMatchesForTokenIds(const std::vector<Id>& elementIds) const
|
std::vector<SearchMatch> PersistentStorage::getSearchMatchesForTokenIds(const std::vector<Id>& elementIds) const
|
||||||
@@ -624,7 +618,7 @@ std::vector<SearchMatch> PersistentStorage::getSearchMatchesForTokenIds(const st
|
|||||||
}
|
}
|
||||||
|
|
||||||
NameHierarchy nameHierarchy = NameHierarchy::deserialize(m_sqliteStorage.getNodeById(elementId).serializedName);
|
NameHierarchy nameHierarchy = NameHierarchy::deserialize(m_sqliteStorage.getNodeById(elementId).serializedName);
|
||||||
match.text = nameHierarchy.getQualifiedName();
|
match.name = nameHierarchy.getQualifiedName();
|
||||||
match.nameHierarchies.push_back(nameHierarchy.getQualifiedName());
|
match.nameHierarchies.push_back(nameHierarchy.getQualifiedName());
|
||||||
match.searchType = SearchMatch::SEARCH_TOKEN;
|
match.searchType = SearchMatch::SEARCH_TOKEN;
|
||||||
|
|
||||||
@@ -1430,14 +1424,33 @@ void PersistentStorage::buildSearchIndex()
|
|||||||
{
|
{
|
||||||
TRACE();
|
TRACE();
|
||||||
|
|
||||||
|
FilePath dbPath = getDbFilePath();
|
||||||
|
|
||||||
for (StorageNode node : m_sqliteStorage.getAllNodes())
|
for (StorageNode node : m_sqliteStorage.getAllNodes())
|
||||||
{
|
{
|
||||||
if (intToDefinitionType(node.definitionType) != DEFINITION_IMPLICIT)
|
if (intToDefinitionType(node.definitionType) != DEFINITION_IMPLICIT)
|
||||||
{
|
{
|
||||||
m_elementIndex.addNode(node.id, NameHierarchy::deserialize(node.serializedName));
|
if (Node::intToType(node.type) == Node::NODE_FILE)
|
||||||
|
{
|
||||||
|
FilePath filePath = m_fileNodePaths[node.id];
|
||||||
|
|
||||||
|
if (filePath.exists())
|
||||||
|
{
|
||||||
|
filePath = filePath.relativeTo(dbPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fileIndex.addNode(node.id, filePath.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we don't use the signature here, so elements with the same signature share the same node.
|
||||||
|
m_elementIndex.addNode(node.id, NameHierarchy::deserialize(node.serializedName).getQualifiedName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_elementIndex.finishSetup();
|
m_elementIndex.finishSetup();
|
||||||
|
m_fileIndex.finishSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PersistentStorage::buildFilePathMaps()
|
void PersistentStorage::buildFilePathMaps()
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ private:
|
|||||||
|
|
||||||
SearchIndex m_commandIndex;
|
SearchIndex m_commandIndex;
|
||||||
SearchIndex m_elementIndex;
|
SearchIndex m_elementIndex;
|
||||||
|
SearchIndex m_fileIndex;
|
||||||
|
|
||||||
mutable FullTextSearchIndex m_fullTextSearchIndex;
|
mutable FullTextSearchIndex m_fullTextSearchIndex;
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,18 @@ std::shared_ptr<NameElement> NameHierarchy::operator[](size_t pos) const
|
|||||||
return m_elements[pos];
|
return m_elements[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NameHierarchy NameHierarchy::getRange(size_t first, size_t last) const
|
||||||
|
{
|
||||||
|
NameHierarchy hierarchy;
|
||||||
|
|
||||||
|
for (size_t i = first; i < last; i++)
|
||||||
|
{
|
||||||
|
hierarchy.push(m_elements[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
size_t NameHierarchy::size() const
|
size_t NameHierarchy::size() const
|
||||||
{
|
{
|
||||||
return m_elements.size();
|
return m_elements.size();
|
||||||
|
|||||||
@@ -23,8 +23,12 @@ public:
|
|||||||
|
|
||||||
void push(std::shared_ptr<NameElement> element);
|
void push(std::shared_ptr<NameElement> element);
|
||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
std::shared_ptr<NameElement> back() const;
|
std::shared_ptr<NameElement> back() const;
|
||||||
std::shared_ptr<NameElement> operator[](size_t pos) const;
|
std::shared_ptr<NameElement> operator[](size_t pos) const;
|
||||||
|
|
||||||
|
NameHierarchy getRange(size_t first, size_t last) const;
|
||||||
|
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
|
||||||
std::string getQualifiedName() const;
|
std::string getQualifiedName() const;
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ SearchIndex::~SearchIndex()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchIndex::addNode(Id id, const NameHierarchy& nameHierarchy)
|
void SearchIndex::addNode(Id id, const std::string& name)
|
||||||
{
|
{
|
||||||
Node* currentNode = m_root;
|
Node* currentNode = m_root;
|
||||||
|
|
||||||
// we don't use the signature here, so elements with the same signature share the same node in the search index.
|
std::string remaining = name;
|
||||||
std::string remaining = nameHierarchy.getQualifiedName();
|
|
||||||
|
|
||||||
while (remaining.size() > 0)
|
while (remaining.size() > 0)
|
||||||
{
|
{
|
||||||
bool matchingEdgeFound = false;
|
bool matchingEdgeFound = false;
|
||||||
@@ -106,7 +104,8 @@ void SearchIndex::clear()
|
|||||||
m_root = n.get();
|
m_root = n.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SearchResult> SearchIndex::search(const std::string& query, size_t maxResultCount) const
|
std::vector<SearchResult> SearchIndex::search(
|
||||||
|
const std::string& query, size_t maxResultCount, size_t maxBestScoredLength) const
|
||||||
{
|
{
|
||||||
// find paths containing query
|
// find paths containing query
|
||||||
Path startPath;
|
Path startPath;
|
||||||
@@ -123,7 +122,7 @@ std::vector<SearchResult> SearchIndex::search(const std::string& query, size_t m
|
|||||||
std::multiset<SearchResult> bestResults;
|
std::multiset<SearchResult> bestResults;
|
||||||
for (const SearchResult& result : searchResults)
|
for (const SearchResult& result : searchResults)
|
||||||
{
|
{
|
||||||
bestResults.insert(bestScoredResult(result, &scoresCache));
|
bestResults.insert(bestScoredResult(result, &scoresCache, maxBestScoredLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
// narrow down to max result count
|
// narrow down to max result count
|
||||||
@@ -212,7 +211,7 @@ std::multiset<SearchResult> SearchIndex::createScoredResults(const std::vector<P
|
|||||||
|
|
||||||
for (const Path& path : paths)
|
for (const Path& path : paths)
|
||||||
{
|
{
|
||||||
scoredPaths.insert(std::make_pair(score(path.text, path.indices), path));
|
scoredPaths.insert(std::make_pair(scoreText(path.text, path.indices), path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// score paths and subpaths
|
// score paths and subpaths
|
||||||
@@ -234,7 +233,7 @@ std::multiset<SearchResult> SearchIndex::createScoredResults(const std::vector<P
|
|||||||
result.text = path.text;
|
result.text = path.text;
|
||||||
result.elementIds = path.node->elementIds;
|
result.elementIds = path.node->elementIds;
|
||||||
result.indices = path.indices;
|
result.indices = path.indices;
|
||||||
result.score = score(path.text, path.indices);
|
result.score = scoreText(path.text, path.indices);
|
||||||
searchResults.insert(result);
|
searchResults.insert(result);
|
||||||
|
|
||||||
if (maxResultCount && searchResults.size() >= maxResultCount)
|
if (maxResultCount && searchResults.size() >= maxResultCount)
|
||||||
@@ -260,9 +259,10 @@ std::multiset<SearchResult> SearchIndex::createScoredResults(const std::vector<P
|
|||||||
return searchResults;
|
return searchResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResult SearchIndex::bestScoredResult(SearchResult result, std::map<std::string, SearchResult>* scoresCache) const
|
SearchResult SearchIndex::bestScoredResult(
|
||||||
|
SearchResult result, std::map<std::string, SearchResult>* scoresCache, size_t maxBestScoredLength)
|
||||||
{
|
{
|
||||||
if (result.text.size() > 100)
|
if (maxBestScoredLength && result.text.size() > maxBestScoredLength)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -296,7 +296,7 @@ SearchResult SearchIndex::bestScoredResult(SearchResult result, std::map<std::st
|
|||||||
|
|
||||||
void SearchIndex::bestScoredResultRecursive(
|
void SearchIndex::bestScoredResultRecursive(
|
||||||
const std::string& lowerText, const std::vector<size_t>& indices, const size_t indicesPos,
|
const std::string& lowerText, const std::vector<size_t>& indices, const size_t indicesPos,
|
||||||
std::map<std::string, SearchResult>* scoresCache, SearchResult* result) const
|
std::map<std::string, SearchResult>* scoresCache, SearchResult* result)
|
||||||
{
|
{
|
||||||
// left for debugging
|
// left for debugging
|
||||||
// std::cout << lowerText << std::endl;
|
// std::cout << lowerText << std::endl;
|
||||||
@@ -326,7 +326,7 @@ void SearchIndex::bestScoredResultRecursive(
|
|||||||
std::vector<size_t> newIndices = indices;
|
std::vector<size_t> newIndices = indices;
|
||||||
newIndices[indicesPos] = i;
|
newIndices[indicesPos] = i;
|
||||||
|
|
||||||
int newScore = score(result->text, newIndices);
|
int newScore = scoreText(result->text, newIndices);
|
||||||
if (newScore > result->score)
|
if (newScore > result->score)
|
||||||
{
|
{
|
||||||
result->score = newScore;
|
result->score = newScore;
|
||||||
@@ -362,12 +362,13 @@ void SearchIndex::bestScoredResultRecursive(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int SearchIndex::score(const std::string& text, const std::vector<size_t>& indices) const
|
int SearchIndex::scoreText(const std::string& text, const std::vector<size_t>& indices)
|
||||||
{
|
{
|
||||||
const int unmatchedLetterBonus = -1;
|
const int unmatchedLetterBonus = -1;
|
||||||
const int consecutiveLetterBonus = 5;
|
const int consecutiveLetterBonus = 5;
|
||||||
const int camelCaseBonus = 4;
|
const int camelCaseBonus = 4;
|
||||||
const int noLetterBonus = 3;
|
const int noLetterBonus = 3;
|
||||||
|
const int firstLetterBonus = 4;
|
||||||
const int delayedStartBonus = -1;
|
const int delayedStartBonus = -1;
|
||||||
const int minDelayedStartBonus = -20;
|
const int minDelayedStartBonus = -20;
|
||||||
|
|
||||||
@@ -375,6 +376,7 @@ int SearchIndex::score(const std::string& text, const std::vector<size_t>& indic
|
|||||||
int consecutiveLetterScore = 0;
|
int consecutiveLetterScore = 0;
|
||||||
int camelCaseScore = 0;
|
int camelCaseScore = 0;
|
||||||
int noLetterScore = 0;
|
int noLetterScore = 0;
|
||||||
|
int firstLetterScore = 0;
|
||||||
|
|
||||||
static std::set<char> noLetters;
|
static std::set<char> noLetters;
|
||||||
if (!noLetters.size())
|
if (!noLetters.size())
|
||||||
@@ -386,6 +388,8 @@ int SearchIndex::score(const std::string& text, const std::vector<size_t>& indic
|
|||||||
noLetters.insert(':');
|
noLetters.insert(':');
|
||||||
noLetters.insert('<');
|
noLetters.insert('<');
|
||||||
noLetters.insert('>');
|
noLetters.insert('>');
|
||||||
|
noLetters.insert('/');
|
||||||
|
noLetters.insert('\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < indices.size(); i++)
|
for (size_t i = 0; i < indices.size(); i++)
|
||||||
@@ -399,9 +403,13 @@ int SearchIndex::score(const std::string& text, const std::vector<size_t>& indic
|
|||||||
|
|
||||||
size_t index = indices[i];
|
size_t index = indices[i];
|
||||||
|
|
||||||
|
// first letter
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
firstLetterScore += firstLetterBonus;
|
||||||
|
}
|
||||||
// after no letter
|
// after no letter
|
||||||
bool prevIsNoLetter = (index == 0 || noLetters.find(text[index - 1]) != noLetters.end());
|
else if ((index != 0 && noLetters.find(text[index - 1]) != noLetters.end()))
|
||||||
if (prevIsNoLetter)
|
|
||||||
{
|
{
|
||||||
noLetterScore += noLetterBonus;
|
noLetterScore += noLetterBonus;
|
||||||
}
|
}
|
||||||
@@ -416,6 +424,8 @@ int SearchIndex::score(const std::string& text, const std::vector<size_t>& indic
|
|||||||
camelCaseScore += camelCaseBonus;
|
camelCaseScore += camelCaseBonus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int leadingStartScore = std::max(int(indices[0]) * delayedStartBonus, minDelayedStartBonus);
|
int leadingStartScore = std::max(int(indices[0]) * delayedStartBonus, minDelayedStartBonus);
|
||||||
@@ -425,7 +435,66 @@ int SearchIndex::score(const std::string& text, const std::vector<size_t>& indic
|
|||||||
consecutiveLetterScore +
|
consecutiveLetterScore +
|
||||||
camelCaseScore +
|
camelCaseScore +
|
||||||
noLetterScore +
|
noLetterScore +
|
||||||
|
firstLetterScore +
|
||||||
leadingStartScore;
|
leadingStartScore;
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SearchResult SearchIndex::rescoreText(
|
||||||
|
const std::string& fulltext,
|
||||||
|
const std::string& text,
|
||||||
|
const std::vector<size_t>& indices,
|
||||||
|
int score,
|
||||||
|
size_t maxBestScoredLength)
|
||||||
|
{
|
||||||
|
SearchResult result;
|
||||||
|
result.text = text;
|
||||||
|
result.score = score;
|
||||||
|
result.indices = indices;
|
||||||
|
|
||||||
|
std::vector<size_t> textIndices;
|
||||||
|
|
||||||
|
// match is already within text
|
||||||
|
int newIdx = indices[0] - (fulltext.size() - text.size());
|
||||||
|
if (newIdx >= 0)
|
||||||
|
{
|
||||||
|
for (size_t idx : indices)
|
||||||
|
{
|
||||||
|
textIndices.push_back(idx - (fulltext.size() - text.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// try if match is within text
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t idx = 0;
|
||||||
|
for (size_t i = 0; i < text.size() && idx < indices.size(); i++)
|
||||||
|
{
|
||||||
|
if (tolower(text[i]) == tolower(fulltext[indices[idx]]))
|
||||||
|
{
|
||||||
|
textIndices.push_back(i);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// match was not found
|
||||||
|
if (idx != indices.size())
|
||||||
|
{
|
||||||
|
result.score -= 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.score = scoreText(text, textIndices);
|
||||||
|
result.indices = textIndices;
|
||||||
|
|
||||||
|
std::map<std::string, SearchResult> scoresCache;
|
||||||
|
result = bestScoredResult(result, &scoresCache, maxBestScoredLength);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < result.indices.size(); i++)
|
||||||
|
{
|
||||||
|
result.indices[i] += fulltext.size() - text.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,20 +8,19 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "data/name/NameHierarchy.h"
|
|
||||||
#include "utility/types.h"
|
#include "utility/types.h"
|
||||||
|
|
||||||
struct SearchResult
|
struct SearchResult
|
||||||
{
|
{
|
||||||
std::string text;
|
|
||||||
std::set<Id> elementIds;
|
|
||||||
std::vector<size_t> indices;
|
|
||||||
int score;
|
|
||||||
|
|
||||||
bool operator<(const SearchResult& other) const
|
bool operator<(const SearchResult& other) const
|
||||||
{
|
{
|
||||||
return score > other.score;
|
return score > other.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string text;
|
||||||
|
std::set<Id> elementIds;
|
||||||
|
std::vector<size_t> indices;
|
||||||
|
int score;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchIndex
|
class SearchIndex
|
||||||
@@ -30,12 +29,12 @@ public:
|
|||||||
SearchIndex();
|
SearchIndex();
|
||||||
virtual ~SearchIndex();
|
virtual ~SearchIndex();
|
||||||
|
|
||||||
void addNode(Id id, const NameHierarchy& nameHierarchy);
|
void addNode(Id id, const std::string& name);
|
||||||
void finishSetup();
|
void finishSetup();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// maxResultCount == 0 means "no restriction".
|
// maxResultCount == 0 means "no restriction".
|
||||||
std::vector<SearchResult> search(const std::string& query, size_t maxResultCount) const;
|
std::vector<SearchResult> search(const std::string& query, size_t maxResultCount, size_t maxBestScoredLength = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Node;
|
struct Node;
|
||||||
@@ -65,12 +64,23 @@ private:
|
|||||||
void searchRecursive(const Path& path, const std::string& remainingQuery, std::vector<SearchIndex::Path>* results) const;
|
void searchRecursive(const Path& path, const std::string& remainingQuery, std::vector<SearchIndex::Path>* results) const;
|
||||||
|
|
||||||
std::multiset<SearchResult> createScoredResults(const std::vector<Path>& paths, size_t maxResultCount) const;
|
std::multiset<SearchResult> createScoredResults(const std::vector<Path>& paths, size_t maxResultCount) const;
|
||||||
SearchResult bestScoredResult(SearchResult result, std::map<std::string, SearchResult>* scoresCache) const;
|
|
||||||
void bestScoredResultRecursive(
|
|
||||||
const std::string& lowerText, const std::vector<size_t>& indices, const size_t indicesPos,
|
|
||||||
std::map<std::string, SearchResult>* scoresCache, SearchResult* result) const;
|
|
||||||
int score(const std::string& text, const std::vector<size_t>& indices) const;
|
|
||||||
|
|
||||||
|
static SearchResult bestScoredResult(
|
||||||
|
SearchResult result, std::map<std::string, SearchResult>* scoresCache, size_t maxBestScoredLength);
|
||||||
|
static void bestScoredResultRecursive(
|
||||||
|
const std::string& lowerText, const std::vector<size_t>& indices, const size_t indicesPos,
|
||||||
|
std::map<std::string, SearchResult>* scoresCache, SearchResult* result);
|
||||||
|
static int scoreText(const std::string& text, const std::vector<size_t>& indices);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static SearchResult rescoreText(
|
||||||
|
const std::string& fulltext,
|
||||||
|
const std::string& text,
|
||||||
|
const std::vector<size_t>& indices,
|
||||||
|
int score,
|
||||||
|
size_t maxBestScoredLength = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
std::vector<std::shared_ptr<Node>> m_nodes;
|
std::vector<std::shared_ptr<Node>> m_nodes;
|
||||||
std::vector<std::shared_ptr<Edge>> m_edges;
|
std::vector<std::shared_ptr<Edge>> m_edges;
|
||||||
Node* m_root;
|
Node* m_root;
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ std::string SearchMatch::searchMatchesToString(const std::vector<SearchMatch>& m
|
|||||||
SearchMatch SearchMatch::createCommand(CommandType type)
|
SearchMatch SearchMatch::createCommand(CommandType type)
|
||||||
{
|
{
|
||||||
SearchMatch match;
|
SearchMatch match;
|
||||||
match.text = getCommandName(type);
|
match.name = getCommandName(type);
|
||||||
|
match.text = match.name;
|
||||||
match.typeName = "command";
|
match.typeName = "command";
|
||||||
match.searchType = SEARCH_COMMAND;
|
match.searchType = SEARCH_COMMAND;
|
||||||
return match;
|
return match;
|
||||||
@@ -96,13 +97,60 @@ SearchMatch::SearchMatch()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchMatch::SearchMatch(const std::string& query)
|
SearchMatch::SearchMatch(const std::string& query)
|
||||||
: text(query)
|
: name(query)
|
||||||
, typeName("")
|
, typeName("")
|
||||||
, searchType(SEARCH_NONE)
|
, searchType(SEARCH_NONE)
|
||||||
, hasChildren(false)
|
, hasChildren(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SearchMatch::operator<(const SearchMatch& other) const
|
||||||
|
{
|
||||||
|
// score
|
||||||
|
if (score > other.score)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (score < other.score)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// text size
|
||||||
|
if (text.size() < other.text.size())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (text.size() > other.text.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lower case
|
||||||
|
for (size_t i = 0; i < text.size(); i++)
|
||||||
|
{
|
||||||
|
if (tolower(text[i]) != tolower(other.text[i]))
|
||||||
|
{
|
||||||
|
return tolower(text[i]) < tolower(other.text[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// alphabetical
|
||||||
|
if (text[i] < other.text[i])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (text[i] > other.text[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SearchMatch::isValid() const
|
bool SearchMatch::isValid() const
|
||||||
{
|
{
|
||||||
return searchType != SEARCH_NONE;
|
return searchType != SEARCH_NONE;
|
||||||
@@ -110,7 +158,7 @@ bool SearchMatch::isValid() const
|
|||||||
|
|
||||||
void SearchMatch::print(std::ostream& ostream) const
|
void SearchMatch::print(std::ostream& ostream) const
|
||||||
{
|
{
|
||||||
ostream << text << std::endl << '\t';
|
ostream << name << std::endl << '\t';
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (size_t index : indices)
|
for (size_t index : indices)
|
||||||
{
|
{
|
||||||
@@ -127,7 +175,12 @@ void SearchMatch::print(std::ostream& ostream) const
|
|||||||
|
|
||||||
std::string SearchMatch::getFullName() const
|
std::string SearchMatch::getFullName() const
|
||||||
{
|
{
|
||||||
return text;
|
if (searchType == SEARCH_TOKEN && nodeType == Node::NODE_FILE)
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SearchMatch::getNodeTypeAsString() const
|
std::string SearchMatch::getNodeTypeAsString() const
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ struct SearchMatch
|
|||||||
SearchMatch();
|
SearchMatch();
|
||||||
SearchMatch(const std::string& query);
|
SearchMatch(const std::string& query);
|
||||||
|
|
||||||
|
bool operator<(const SearchMatch& other) const;
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
void print(std::ostream& ostream) const;
|
void print(std::ostream& ostream) const;
|
||||||
@@ -49,12 +51,19 @@ struct SearchMatch
|
|||||||
std::string getNodeTypeAsString() const;
|
std::string getNodeTypeAsString() const;
|
||||||
std::string getSearchTypeName() const;
|
std::string getSearchTypeName() const;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
std::string subtext;
|
||||||
|
|
||||||
std::string typeName;
|
std::string typeName;
|
||||||
|
|
||||||
Node::NodeType nodeType;
|
Node::NodeType nodeType;
|
||||||
SearchType searchType;
|
SearchType searchType;
|
||||||
std::vector<size_t> indices;
|
std::vector<size_t> indices;
|
||||||
|
|
||||||
|
int score;
|
||||||
|
|
||||||
std::vector<NameHierarchy> nameHierarchies;
|
std::vector<NameHierarchy> nameHierarchies;
|
||||||
|
|
||||||
bool hasChildren;
|
bool hasChildren;
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
|
||||||
#include "component/view/GraphViewStyle.h"
|
#include "component/view/GraphViewStyle.h"
|
||||||
|
#include "qt/utility/QtDeviceScaledPixmap.h"
|
||||||
#include "settings/ApplicationSettings.h"
|
#include "settings/ApplicationSettings.h"
|
||||||
#include "settings/ColorScheme.h"
|
#include "settings/ColorScheme.h"
|
||||||
|
#include "utility/ResourcePaths.h"
|
||||||
|
|
||||||
QtAutocompletionModel::QtAutocompletionModel(QObject* parent)
|
QtAutocompletionModel::QtAutocompletionModel(QObject* parent)
|
||||||
: QAbstractTableModel(parent)
|
: QAbstractTableModel(parent)
|
||||||
@@ -30,7 +32,7 @@ int QtAutocompletionModel::rowCount(const QModelIndex &parent) const
|
|||||||
int QtAutocompletionModel::columnCount(const QModelIndex &parent) const
|
int QtAutocompletionModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent);
|
||||||
return 4;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
||||||
@@ -45,10 +47,14 @@ QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
|||||||
switch (index.column())
|
switch (index.column())
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return QString::fromStdString(match.getFullName());
|
return QString::fromStdString(match.name);
|
||||||
case 1:
|
case 1:
|
||||||
return QString::fromStdString(match.typeName);
|
return QString::fromStdString(match.text);
|
||||||
case 2:
|
case 2:
|
||||||
|
return QString::fromStdString(match.subtext);
|
||||||
|
case 3:
|
||||||
|
return QString::fromStdString(match.typeName);
|
||||||
|
case 4:
|
||||||
{
|
{
|
||||||
QList<QVariant> indices;
|
QList<QVariant> indices;
|
||||||
for (const size_t idx : match.indices)
|
for (const size_t idx : match.indices)
|
||||||
@@ -57,7 +63,7 @@ QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
return indices;
|
return indices;
|
||||||
}
|
}
|
||||||
case 3:
|
case 5:
|
||||||
return match.nodeType;
|
return match.nodeType;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@@ -73,10 +79,52 @@ const SearchMatch* QtAutocompletionModel::getSearchMatchAt(int idx) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QtAutocompletionModel::longestText() const
|
||||||
QtAutocompletionDelegate::QtAutocompletionDelegate(QObject* parent)
|
|
||||||
: QStyledItemDelegate(parent)
|
|
||||||
{
|
{
|
||||||
|
std::string str;
|
||||||
|
for (const SearchMatch& match : m_matchList)
|
||||||
|
{
|
||||||
|
if (match.text.size() > str.size())
|
||||||
|
{
|
||||||
|
str = match.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QtAutocompletionModel::longestSubText() const
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
for (const SearchMatch& match : m_matchList)
|
||||||
|
{
|
||||||
|
if (match.subtext.size() > str.size())
|
||||||
|
{
|
||||||
|
str = match.subtext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QtAutocompletionModel::longestType() const
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
for (const SearchMatch& match : m_matchList)
|
||||||
|
{
|
||||||
|
if (match.typeName.size() > str.size())
|
||||||
|
{
|
||||||
|
str = match.typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QtAutocompletionDelegate::QtAutocompletionDelegate(QtAutocompletionModel* model, QObject* parent)
|
||||||
|
: QStyledItemDelegate(parent)
|
||||||
|
, m_model(model)
|
||||||
|
, m_arrow()
|
||||||
|
{
|
||||||
|
resetCharSizes();
|
||||||
}
|
}
|
||||||
|
|
||||||
QtAutocompletionDelegate::~QtAutocompletionDelegate()
|
QtAutocompletionDelegate::~QtAutocompletionDelegate()
|
||||||
@@ -87,108 +135,219 @@ void QtAutocompletionDelegate::paint(QPainter* painter, const QStyleOptionViewIt
|
|||||||
{
|
{
|
||||||
painter->save();
|
painter->save();
|
||||||
|
|
||||||
ColorScheme* scheme = ColorScheme::getInstance().get();
|
// get data
|
||||||
|
|
||||||
if (option.state & QStyle::State_Selected)
|
|
||||||
{
|
|
||||||
painter->fillRect(option.rect, option.palette.color(QPalette::Highlight));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
painter->fillRect(option.rect, option.palette.color(QPalette::Base));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString name = index.data().toString();
|
QString name = index.data().toString();
|
||||||
|
QString text = index.sibling(index.row(), index.column() + 1).data().toString();
|
||||||
|
QString subtext = index.sibling(index.row(), index.column() + 2).data().toString();
|
||||||
|
QString type = index.sibling(index.row(), index.column() + 3).data().toString();
|
||||||
|
QList<QVariant> indices = index.sibling(index.row(), index.column() + 4).data().toList();
|
||||||
|
Node::NodeType nodeType = static_cast<Node::NodeType>(index.sibling(index.row(), index.column() + 5).data().toInt());
|
||||||
|
|
||||||
|
// define highlight colors
|
||||||
QString type = index.sibling(index.row(), index.column() + 1).data().toString();
|
ColorScheme* scheme = ColorScheme::getInstance().get();
|
||||||
QColor color("#FFFFFF");
|
QColor fillColor("#FFFFFF");
|
||||||
QColor textColor("#000000");
|
QColor textColor("#000000");
|
||||||
|
|
||||||
Node::NodeType nodeType = static_cast<Node::NodeType>(index.sibling(index.row(), index.column() + 3).data().toInt());
|
|
||||||
if (type.size() && type != "command")
|
if (type.size() && type != "command")
|
||||||
{
|
{
|
||||||
const GraphViewStyle::NodeColor& nodeColor = GraphViewStyle::getNodeColor(Node::getTypeString(nodeType), false);
|
const GraphViewStyle::NodeColor& nodeColor = GraphViewStyle::getNodeColor(Node::getTypeString(nodeType), false);
|
||||||
color = QColor(nodeColor.fill.c_str());
|
fillColor = QColor(nodeColor.fill.c_str());
|
||||||
textColor = QColor(nodeColor.text.c_str());
|
textColor = QColor(nodeColor.text.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "fill").c_str());
|
fillColor = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "fill").c_str());
|
||||||
textColor = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "text").c_str());
|
textColor = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "text").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
float charWidth = option.fontMetrics.width(
|
int top1 = 6;
|
||||||
"----------------------------------------------------------------------------------------------------"
|
int top2 = m_charHeight1 + 3;
|
||||||
"----------------------------------------------------------------------------------------------------"
|
|
||||||
"----------------------------------------------------------------------------------------------------"
|
|
||||||
"----------------------------------------------------------------------------------------------------"
|
|
||||||
"----------------------------------------------------------------------------------------------------"
|
|
||||||
) / 500.0f;
|
|
||||||
|
|
||||||
QString highlightName(name.size(), ' ');
|
// draw background
|
||||||
|
QColor backgroundColor = option.palette.color((option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base));
|
||||||
|
painter->fillRect(option.rect, backgroundColor);
|
||||||
|
|
||||||
QList<QVariant> indices = index.sibling(index.row(), index.column() + 2).data().toList();
|
// draw highlights at indices
|
||||||
|
QString highlightText(text.size(), ' ');
|
||||||
if (indices.size())
|
if (indices.size())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < indices.size(); i++)
|
for (int i = 0; i < indices.size(); i++)
|
||||||
{
|
{
|
||||||
int idx = indices[i].toInt();
|
int idx = indices[i].toInt() - (name.size() - text.size());
|
||||||
|
if (idx < 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QRect rect = option.rect.adjusted(charWidth * (idx + 1) + 2, 2, 0, -1);
|
QRect rect(
|
||||||
rect.setWidth(charWidth + 1);
|
option.rect.left() + m_charWidth1 * (idx + 1) + 2,
|
||||||
painter->fillRect(rect, color);
|
option.rect.top() + top1 - 1,
|
||||||
|
m_charWidth1 + 1,
|
||||||
|
m_charHeight1 - 1
|
||||||
|
);
|
||||||
|
painter->fillRect(rect, fillColor);
|
||||||
|
|
||||||
highlightName[idx] = name.at(idx);
|
highlightText[idx] = text.at(idx);
|
||||||
name[idx] = ' ';
|
text[idx] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QRect rect = option.rect.adjusted(0, 2, 0, -1);
|
QRect rect(option.rect.left(), option.rect.top() + top1, m_charWidth1 - 1, m_charHeight1 - 2);
|
||||||
rect.setWidth(charWidth - 1);
|
painter->fillRect(rect, fillColor);
|
||||||
painter->fillRect(rect, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->drawText(option.rect.adjusted(charWidth + 2, -1, 0, 0), Qt::AlignLeft, name);
|
// draw text normal
|
||||||
|
painter->drawText(option.rect.adjusted(m_charWidth1 + 2, top1 - 3, 0, 0), Qt::AlignLeft, text);
|
||||||
|
|
||||||
|
// draw text highlighted
|
||||||
painter->save();
|
painter->save();
|
||||||
QPen highlightPen = painter->pen();
|
QPen highlightPen = painter->pen();
|
||||||
highlightPen.setColor(textColor);
|
highlightPen.setColor(textColor);
|
||||||
painter->setPen(highlightPen);
|
painter->setPen(highlightPen);
|
||||||
painter->drawText(option.rect.adjusted(charWidth + 2, -1, 0, 0), Qt::AlignLeft, highlightName);
|
painter->drawText(option.rect.adjusted(m_charWidth1 + 2, top1 - 3, 0, 0), Qt::AlignLeft, highlightText);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
|
|
||||||
if (type.size())
|
// draw subtext
|
||||||
|
if (subtext.size())
|
||||||
{
|
{
|
||||||
QFont font = painter->font();
|
// draw arrow icon
|
||||||
font.setPixelSize(ApplicationSettings::getInstance()->getFontSize() - 4);
|
painter->drawPixmap(
|
||||||
painter->setFont(font);
|
option.rect.left() + m_charWidth2 * 2,
|
||||||
|
option.rect.top() + top2 + 1 + (m_charHeight2 - m_arrow.height()) / 2,
|
||||||
|
m_arrow.pixmap()
|
||||||
|
);
|
||||||
|
|
||||||
|
painter->setFont(m_font2);
|
||||||
|
|
||||||
|
QString highlightSubtext(subtext.size(), ' ');
|
||||||
|
if (indices.size())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < indices.size(); i++)
|
||||||
|
{
|
||||||
|
int idx = indices[i].toInt();
|
||||||
|
if (idx >= subtext.size())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect rect(
|
||||||
|
option.rect.left() + m_charWidth2 * (idx + 3) + 2,
|
||||||
|
option.rect.top() + top2 + 1,
|
||||||
|
m_charWidth2 + 1,
|
||||||
|
m_charHeight2
|
||||||
|
);
|
||||||
|
painter->fillRect(rect, fillColor);
|
||||||
|
|
||||||
|
highlightSubtext[idx] = subtext.at(idx);
|
||||||
|
subtext[idx] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QPen typePen = painter->pen();
|
QPen typePen = painter->pen();
|
||||||
typePen.setColor(scheme->getColor("search/popup/by_text").c_str());
|
typePen.setColor(scheme->getColor("search/popup/by_text").c_str());
|
||||||
painter->setPen(typePen);
|
painter->setPen(typePen);
|
||||||
|
|
||||||
painter->drawText(option.rect.adjusted(0, 3, -charWidth, 0), Qt::AlignRight, type);
|
// draw subtext normal
|
||||||
|
painter->drawText(option.rect.adjusted((3 * m_charWidth2) + 2, top2, 0, 0), Qt::AlignLeft, subtext);
|
||||||
|
|
||||||
|
// draw subtext highlighted
|
||||||
|
painter->save();
|
||||||
|
QPen highlightPen = painter->pen();
|
||||||
|
highlightPen.setColor(textColor);
|
||||||
|
painter->setPen(highlightPen);
|
||||||
|
painter->drawText(option.rect.adjusted((3 * m_charWidth2) + 2, top2, 0, 0), Qt::AlignLeft, highlightSubtext);
|
||||||
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw type
|
||||||
|
if (type.size())
|
||||||
|
{
|
||||||
|
painter->setFont(m_font2);
|
||||||
|
|
||||||
|
QPen typePen = painter->pen();
|
||||||
|
typePen.setColor(scheme->getColor("search/popup/by_text").c_str());
|
||||||
|
painter->setPen(typePen);
|
||||||
|
|
||||||
|
int width = m_charWidth2 * type.size();
|
||||||
|
int x = painter->viewport().right() - width - m_charWidth2;
|
||||||
|
int y = option.rect.top() + top2;
|
||||||
|
|
||||||
|
painter->fillRect(QRect(x - m_charWidth2, y, width + m_charWidth2 * 3, m_charHeight2 + 2), backgroundColor);
|
||||||
|
painter->drawText(QRect(x, y, width, m_charHeight2), Qt::AlignRight, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw bottom line
|
||||||
|
QRect rect(0, option.rect.bottom(), option.rect.width(), 1);
|
||||||
|
painter->fillRect(rect, scheme->getColor("search/popup/line").c_str());
|
||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize QtAutocompletionDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
QSize QtAutocompletionDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
QString name = index.data().toString();
|
const_cast<QtAutocompletionDelegate*>(this)->calculateCharSizes(option.font);
|
||||||
QString type = index.sibling(index.row(), index.column() + 1).data().toString();
|
|
||||||
return QSize(option.fontMetrics.width(name + type) + 5, option.fontMetrics.height());
|
QString text = m_model->longestText();
|
||||||
|
QString subtext = m_model->longestSubText();
|
||||||
|
QString type = m_model->longestType();
|
||||||
|
|
||||||
|
return QSize(
|
||||||
|
std::max((text.size() + 2) * m_charWidth1, (subtext.size() + type.size() + 6) * m_charWidth2),
|
||||||
|
m_charHeight1 * 2 + 3
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtAutocompletionDelegate::calculateCharSizes(QFont font)
|
||||||
|
{
|
||||||
|
if (m_charWidth1 > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_font1 = font;
|
||||||
|
|
||||||
|
QFontMetrics metrics1(font);
|
||||||
|
m_charWidth1 = metrics1.width(
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
) / 500.0f;
|
||||||
|
m_charHeight1 = metrics1.height();
|
||||||
|
|
||||||
|
font.setPixelSize(ApplicationSettings::getInstance()->getFontSize() - 3);
|
||||||
|
m_font2 = font;
|
||||||
|
|
||||||
|
QFontMetrics metrics2(font);
|
||||||
|
m_charWidth2 = metrics2.width(
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
"----------------------------------------------------------------------------------------------------"
|
||||||
|
) / 500.0f;
|
||||||
|
m_charHeight2 = metrics2.height();
|
||||||
|
|
||||||
|
m_arrow = QtDeviceScaledPixmap(QString::fromStdString(ResourcePaths::getGuiPath() + "search_view/images/arrow.png"));
|
||||||
|
m_arrow.scaleToWidth(m_charWidth2);
|
||||||
|
m_arrow.colorize(ColorScheme::getInstance()->getColor("search/popup/by_text").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtAutocompletionDelegate::resetCharSizes()
|
||||||
|
{
|
||||||
|
m_charWidth1 = m_charHeight1 = m_charWidth2 = m_charHeight2 = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QtAutocompletionList::QtAutocompletionList(QWidget* parent)
|
QtAutocompletionList::QtAutocompletionList(QWidget* parent)
|
||||||
: QCompleter(parent)
|
: QCompleter(parent)
|
||||||
{
|
{
|
||||||
m_model = std::make_shared<QtAutocompletionModel>(this);
|
m_model = std::make_shared<QtAutocompletionModel>(this);
|
||||||
setModel(m_model.get());
|
setModel(m_model.get());
|
||||||
|
|
||||||
m_delegate = std::make_shared<QtAutocompletionDelegate>(this);
|
m_delegate = std::make_shared<QtAutocompletionDelegate>(m_model.get(), this);
|
||||||
|
|
||||||
QListView* list = new QListView(parent);
|
QListView* list = new QListView(parent);
|
||||||
list->setItemDelegateForColumn(0, m_delegate.get());
|
list->setItemDelegateForColumn(0, m_delegate.get());
|
||||||
@@ -201,7 +360,7 @@ QtAutocompletionList::QtAutocompletionList(QWidget* parent)
|
|||||||
setCompletionMode(QCompleter::UnfilteredPopupCompletion);
|
setCompletionMode(QCompleter::UnfilteredPopupCompletion);
|
||||||
setModelSorting(QCompleter::UnsortedModel);
|
setModelSorting(QCompleter::UnsortedModel);
|
||||||
setCompletionPrefix("");
|
setCompletionPrefix("");
|
||||||
setMaxVisibleItems(20);
|
setMaxVisibleItems(8);
|
||||||
|
|
||||||
m_scrollSpeedChangeListenerHorizontal.setScrollBar(list->horizontalScrollBar());
|
m_scrollSpeedChangeListenerHorizontal.setScrollBar(list->horizontalScrollBar());
|
||||||
m_scrollSpeedChangeListenerVertical.setScrollBar(list->verticalScrollBar());
|
m_scrollSpeedChangeListenerVertical.setScrollBar(list->verticalScrollBar());
|
||||||
@@ -222,6 +381,8 @@ void QtAutocompletionList::completeAt(const QPoint& pos, const std::vector<Searc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_delegate->resetCharSizes();
|
||||||
|
|
||||||
disconnect(); // must be done because of a bug where signals are no longer received by QtSmartSearchBox
|
disconnect(); // must be done because of a bug where signals are no longer received by QtSmartSearchBox
|
||||||
connect(this, SIGNAL(highlighted(const QModelIndex&)), this, SLOT(onHighlighted(const QModelIndex&)), Qt::DirectConnection);
|
connect(this, SIGNAL(highlighted(const QModelIndex&)), this, SLOT(onHighlighted(const QModelIndex&)), Qt::DirectConnection);
|
||||||
connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(onActivated(const QModelIndex&)), Qt::DirectConnection);
|
connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(onActivated(const QModelIndex&)), Qt::DirectConnection);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <QListView>
|
#include <QListView>
|
||||||
|
|
||||||
#include "data/search/SearchMatch.h"
|
#include "data/search/SearchMatch.h"
|
||||||
|
#include "qt/utility/QtDeviceScaledPixmap.h"
|
||||||
#include "qt/utility/QtScrollSpeedChangeListener.h"
|
#include "qt/utility/QtScrollSpeedChangeListener.h"
|
||||||
|
|
||||||
class QtAutocompletionModel
|
class QtAutocompletionModel
|
||||||
@@ -30,6 +31,10 @@ public:
|
|||||||
|
|
||||||
const SearchMatch* getSearchMatchAt(int idx) const;
|
const SearchMatch* getSearchMatchAt(int idx) const;
|
||||||
|
|
||||||
|
QString longestText() const;
|
||||||
|
QString longestSubText() const;
|
||||||
|
QString longestType() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<SearchMatch> m_matchList;
|
std::vector<SearchMatch> m_matchList;
|
||||||
};
|
};
|
||||||
@@ -39,11 +44,27 @@ class QtAutocompletionDelegate
|
|||||||
: public QStyledItemDelegate
|
: public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit QtAutocompletionDelegate(QObject* parent = 0);
|
explicit QtAutocompletionDelegate(QtAutocompletionModel* model, QObject* parent = 0);
|
||||||
virtual ~QtAutocompletionDelegate();
|
virtual ~QtAutocompletionDelegate();
|
||||||
|
|
||||||
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
|
||||||
|
void calculateCharSizes(QFont font);
|
||||||
|
void resetCharSizes();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QtAutocompletionModel* m_model;
|
||||||
|
|
||||||
|
QFont m_font1;
|
||||||
|
QFont m_font2;
|
||||||
|
|
||||||
|
float m_charWidth1;
|
||||||
|
float m_charHeight1;
|
||||||
|
float m_charWidth2;
|
||||||
|
float m_charHeight2;
|
||||||
|
|
||||||
|
QtDeviceScaledPixmap m_arrow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -146,11 +146,11 @@ bool QtSmartSearchBox::event(QEvent *event)
|
|||||||
{
|
{
|
||||||
if (m_highlightedMatch.hasChildren)
|
if (m_highlightedMatch.hasChildren)
|
||||||
{
|
{
|
||||||
setEditText((m_highlightedMatch.text + NameHierarchy::getDelimiter()).c_str());
|
setEditText((m_highlightedMatch.getFullName() + NameHierarchy::getDelimiter()).c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setEditText(m_highlightedMatch.text.c_str());
|
setEditText(m_highlightedMatch.getFullName().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAutoCompletions();
|
requestAutoCompletions();
|
||||||
@@ -456,7 +456,7 @@ void QtSmartSearchBox::onTextEdited(const QString& text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.text.size() && !m_allowMultipleElements)
|
if (match.name.size() && !m_allowMultipleElements)
|
||||||
{
|
{
|
||||||
if (m_matches.size())
|
if (m_matches.size())
|
||||||
{
|
{
|
||||||
@@ -475,7 +475,7 @@ void QtSmartSearchBox::onTextEdited(const QString& text)
|
|||||||
layoutElements();
|
layoutElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.text.size() || m_elements.size())
|
if (match.name.size() || m_elements.size())
|
||||||
{
|
{
|
||||||
requestAutoCompletions();
|
requestAutoCompletions();
|
||||||
}
|
}
|
||||||
@@ -510,7 +510,7 @@ void QtSmartSearchBox::onAutocompletionActivated(const SearchMatch& match)
|
|||||||
{
|
{
|
||||||
addMatchAndUpdate(match);
|
addMatchAndUpdate(match);
|
||||||
|
|
||||||
if (match.text.size())
|
if (match.name.size())
|
||||||
{
|
{
|
||||||
search();
|
search();
|
||||||
}
|
}
|
||||||
@@ -580,7 +580,7 @@ void QtSmartSearchBox::moveCursorTo(int target)
|
|||||||
|
|
||||||
void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
||||||
{
|
{
|
||||||
if (!match.text.size())
|
if (!match.name.size())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -607,7 +607,7 @@ void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
|||||||
|
|
||||||
void QtSmartSearchBox::addMatchAndUpdate(const SearchMatch& match)
|
void QtSmartSearchBox::addMatchAndUpdate(const SearchMatch& match)
|
||||||
{
|
{
|
||||||
if (match.text.size())
|
if (match.name.size())
|
||||||
{
|
{
|
||||||
m_oldText.clear();
|
m_oldText.clear();
|
||||||
clearLineEdit();
|
clearLineEdit();
|
||||||
|
|||||||
@@ -2,12 +2,18 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "qt/utility/utilityQt.h"
|
||||||
|
|
||||||
qreal QtDeviceScaledPixmap::devicePixelRatio()
|
qreal QtDeviceScaledPixmap::devicePixelRatio()
|
||||||
{
|
{
|
||||||
QApplication* app = dynamic_cast<QApplication*>(QCoreApplication::instance());
|
QApplication* app = dynamic_cast<QApplication*>(QCoreApplication::instance());
|
||||||
return app->devicePixelRatio();
|
return app->devicePixelRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtDeviceScaledPixmap::QtDeviceScaledPixmap()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QtDeviceScaledPixmap::QtDeviceScaledPixmap(QString filePath)
|
QtDeviceScaledPixmap::QtDeviceScaledPixmap(QString filePath)
|
||||||
: m_pixmap(filePath)
|
: m_pixmap(filePath)
|
||||||
{
|
{
|
||||||
@@ -48,3 +54,8 @@ void QtDeviceScaledPixmap::mirror(bool horizontal, bool vertical)
|
|||||||
m_pixmap = QPixmap::fromImage(m_pixmap.toImage().mirrored(horizontal, vertical));
|
m_pixmap = QPixmap::fromImage(m_pixmap.toImage().mirrored(horizontal, vertical));
|
||||||
m_pixmap.setDevicePixelRatio(devicePixelRatio());
|
m_pixmap.setDevicePixelRatio(devicePixelRatio());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtDeviceScaledPixmap::colorize(QColor color)
|
||||||
|
{
|
||||||
|
m_pixmap = utility::colorizePixmap(m_pixmap, color);
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ class QtDeviceScaledPixmap
|
|||||||
public:
|
public:
|
||||||
static qreal devicePixelRatio();
|
static qreal devicePixelRatio();
|
||||||
|
|
||||||
explicit QtDeviceScaledPixmap(QString filePath);
|
QtDeviceScaledPixmap();
|
||||||
|
QtDeviceScaledPixmap(QString filePath);
|
||||||
virtual ~QtDeviceScaledPixmap();
|
virtual ~QtDeviceScaledPixmap();
|
||||||
|
|
||||||
const QPixmap& pixmap() const;
|
const QPixmap& pixmap() const;
|
||||||
@@ -20,6 +21,7 @@ public:
|
|||||||
void scaleToHeight(int height);
|
void scaleToHeight(int height);
|
||||||
|
|
||||||
void mirror(bool horizontal = false, bool vertical = true);
|
void mirror(bool horizontal = false, bool vertical = true);
|
||||||
|
void colorize(QColor color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPixmap m_pixmap;
|
QPixmap m_pixmap;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public:
|
|||||||
void test_search_index_finds_id_of_element_added()
|
void test_search_index_finds_id_of_element_added()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("foo\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("foo\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
std::vector<SearchResult> results = index.search("oo", 0);
|
std::vector<SearchResult> results = index.search("oo", 0);
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ public:
|
|||||||
void test_search_index_finds_correct_indices_for_query()
|
void test_search_index_finds_correct_indices_for_query()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("foo\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("foo\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
std::vector<SearchResult> results = index.search("oo", 0);
|
std::vector<SearchResult> results = index.search("oo", 0);
|
||||||
|
|
||||||
@@ -36,8 +36,8 @@ public:
|
|||||||
void test_search_index_finds_ids_for_ambiguous_query()
|
void test_search_index_finds_ids_for_ambiguous_query()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("for\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("for\tsvoid\tp() const").getQualifiedName());
|
||||||
index.addNode(2, NameHierarchy::deserialize("fos\tsvoid\tp() const"));
|
index.addNode(2, NameHierarchy::deserialize("fos\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
std::vector<SearchResult> results = index.search("fo", 0);
|
std::vector<SearchResult> results = index.search("fo", 0);
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
void test_search_index_does_not_find_anything_after_clear()
|
void test_search_index_does_not_find_anything_after_clear()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("foo\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("foo\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
index.clear();
|
index.clear();
|
||||||
std::vector<SearchResult> results = index.search("oo", 0);
|
std::vector<SearchResult> results = index.search("oo", 0);
|
||||||
@@ -62,8 +62,8 @@ public:
|
|||||||
void test_search_index_does_not_find_all_results_when_max_amount_is_limited()
|
void test_search_index_does_not_find_all_results_when_max_amount_is_limited()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("foo1\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("foo1\tsvoid\tp() const").getQualifiedName());
|
||||||
index.addNode(2, NameHierarchy::deserialize("foo2\tsvoid\tp() const"));
|
index.addNode(2, NameHierarchy::deserialize("foo2\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
std::vector<SearchResult> results = index.search("oo", 1);
|
std::vector<SearchResult> results = index.search("oo", 1);
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@ public:
|
|||||||
void test_search_index_query_is_case_insensitive()
|
void test_search_index_query_is_case_insensitive()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("foo1\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("foo1\tsvoid\tp() const").getQualifiedName());
|
||||||
index.addNode(2, NameHierarchy::deserialize("FOO2\tsvoid\tp() const"));
|
index.addNode(2, NameHierarchy::deserialize("FOO2\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
std::vector<SearchResult> results = index.search("oo", 0);
|
std::vector<SearchResult> results = index.search("oo", 0);
|
||||||
|
|
||||||
@@ -85,8 +85,8 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(1, NameHierarchy::deserialize("oaabbcc\tsvoid\tp() const"));
|
index.addNode(1, NameHierarchy::deserialize("oaabbcc\tsvoid\tp() const").getQualifiedName());
|
||||||
index.addNode(2, NameHierarchy::deserialize("ocbcabc\tsvoid\tp() const"));
|
index.addNode(2, NameHierarchy::deserialize("ocbcabc\tsvoid\tp() const").getQualifiedName());
|
||||||
index.finishSetup();
|
index.finishSetup();
|
||||||
std::vector<SearchResult> results = index.search("abc", 0);
|
std::vector<SearchResult> results = index.search("abc", 0);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user