ui: integrated autocompletion and filtering into SearchView

- QtSearchView was split into QtSearchView and QtSearchBox.
- QtSearchBox contains all Qt elements and can use them purely
- QtSearchView forwards calls from the SearchController to QtSearchBox
- Searching is initiated with MessageSearch to the SearchController
- Autocompletion is initiated with MessageSearchAutocomplete to the SearchController
- The search field is able to create filter queries by only giving autocompletions for the last token in the query
- For named tokens the search field adds their token ids to the query in the form of "A,25" for faster lookup

bug id = #21
This commit is contained in:
Eberhard Graether
2014-09-11 14:53:03 +02:00
parent 760e5ffafd
commit fec7abbc9b
48 changed files with 786 additions and 391 deletions
+75 -1
View File
@@ -17,12 +17,69 @@ public:
);
}
void test_token_query_with_id()
{
std::set<Id> ids = getIdsForNodeWithName("main");
std::stringstream ss;
ss << "\"main";
for (Id id : ids)
{
ss << ',' << id;
}
ss << '"';
TS_ASSERT_EQUALS(
printedFilteredTestGraph(ss.str()), // "main,<id>"
"1 nodes: function:main\n"
"0 edges:\n"
);
}
void test_token_query_with_id_and_wrong_name_uses_id()
{
std::set<Id> ids = getIdsForNodeWithName("main");
std::stringstream ss;
ss << "\"hello";
for (Id id : ids)
{
ss << ',' << id;
}
ss << '"';
TS_ASSERT_EQUALS(
printedFilteredTestGraph(ss.str()), // "hello,<id>"
"1 nodes: function:main\n"
"0 edges:\n"
);
}
void test_token_query_with_ids()
{
std::set<Id> ids = getIdsForNodeWithName("A::A");
std::stringstream ss;
ss << "\"A::A";
for (Id id : ids)
{
ss << ',' << id;
}
ss << '"';
TS_ASSERT_EQUALS(
printedFilteredTestGraph(ss.str()), // "A::A,<id1>,<id2>"
"2 nodes: method:A::A method:A::A\n"
"0 edges:\n"
);
}
void test_command_query()
{
TS_ASSERT_EQUALS(
printedFilteredTestGraph("method"),
"4 nodes: method:A::A method:A::getCount method:A::process method:B::process\n"
"5 nodes: method:A::A method:A::A method:A::getCount method:A::process method:B::process\n"
"0 edges:\n"
);
@@ -104,6 +161,19 @@ private:
return ss.str();
}
std::set<Id> getIdsForNodeWithName(const std::string& name)
{
createTestStorage();
std::vector<SearchIndex::SearchMatch> matches = m_storage->getAutocompletionMatches(name);
if (matches.size() && matches[0].fullName == name)
{
return matches[0].tokenIds;
}
return std::set<Id>();
}
void createTestStorage()
{
if (m_storage)
@@ -121,6 +191,10 @@ private:
" count++;\n"
" }\n"
"\n"
" A(int c) {\n"
" count += c;\n"
" }\n"
"\n"
" static int getCount()\n"
" {\n"
" return count;\n"
+1 -1
View File
@@ -161,7 +161,7 @@ public:
void test_GraphFilterToken()
{
GraphFilterToken filter("main");
GraphFilterToken filter("main", std::set<Id>());
TS_ASSERT_EQUALS(
printedFilteredTestGraph(&filter),
+45 -26
View File
@@ -10,7 +10,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree(""),
"INVALID\n"
" INVALID\n"
);
}
@@ -28,7 +28,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("class"),
"class \n"
"class\n"
"class\n"
);
}
@@ -47,7 +47,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\""),
"\" A \" \n"
"\"A\"\n"
"\"A\"\n"
);
}
@@ -57,14 +57,13 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A"),
"\" A INVALID\n"
"\"A\" INVALID\n"
"\"A INVALID\n"
);
TS_ASSERT_EQUALS(
printedQueryTree("\"\""),
"\" \" INVALID\n"
"\"\" INVALID\n"
);
TS_ASSERT_EQUALS(
@@ -74,12 +73,32 @@ public:
);
}
void test_token_query_with_id()
{
TS_ASSERT_EQUALS(
printedQueryTree("\"A,1\""),
"\"A,1\"\n"
"\"A,1\"\n"
);
}
void test_token_query_with_ids()
{
TS_ASSERT_EQUALS(
printedQueryTree("\"A,1,2\""),
"\"A,1,2\"\n"
"\"A,1,2\"\n"
);
}
void test_operator_not_query()
{
TS_ASSERT_EQUALS(
printedQueryTree("!field"),
"! field \n"
"! field\n"
"!\n"
" field\n"
);
@@ -87,7 +106,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("!!field"),
"! ! field \n"
"! ! field\n"
"!\n"
" !\n"
" field\n"
@@ -117,7 +136,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\".\"B\""),
"\" A \" . \" B \" \n"
"\"A\" . \"B\"\n"
" \"A\"\n"
".\n"
" \"B\"\n"
@@ -129,7 +148,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\"."),
"\" A \" . INVALID\n"
"\"A\" . INVALID\n"
" \"A\"\n"
". INVALID\n"
);
@@ -144,7 +163,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree(".\"A\""),
". \" A \" INVALID\n"
". \"A\" INVALID\n"
". INVALID\n"
" \"A\"\n"
);
@@ -152,7 +171,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\"..\"B\""),
"\" A \" . . \" B \" INVALID\n"
"\"A\" . . \"B\" INVALID\n"
" \"A\"\n"
".\n"
" . INVALID\n"
@@ -165,7 +184,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\":\"B\""),
"\" A \" : \" B \" \n"
"\"A\" : \"B\"\n"
" \"A\"\n"
":\n"
" \"B\"\n"
@@ -177,7 +196,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\"&\"B\""),
"\" A \" & \" B \" \n"
"\"A\" & \"B\"\n"
" \"A\"\n"
"&\n"
" \"B\"\n"
@@ -189,7 +208,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\"|\"B\""),
"\" A \" | \" B \" \n"
"\"A\" | \"B\"\n"
" \"A\"\n"
"|\n"
" \"B\"\n"
@@ -201,14 +220,14 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("(\"A\")"),
"( \" A \" ) \n"
"( \"A\" )\n"
"(\"A\")\n"
);
TS_ASSERT_EQUALS(
printedQueryTree("(\"A\"|\"B\")"),
"( \" A \" | \" B \" ) \n"
"( \"A\" | \"B\" )\n"
" \"A\"\n"
"(|)\n"
" \"B\"\n"
@@ -226,14 +245,14 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("(\"A\""),
"( \" A \" INVALID\n"
"( \"A\" INVALID\n"
"(\"A\") INVALID\n"
);
TS_ASSERT_EQUALS(
printedQueryTree("\"A\")"),
"\" A \" ) INVALID\n"
"\"A\" ) INVALID\n"
);
TS_ASSERT_EQUALS(
@@ -248,7 +267,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("\"A\"(\"B\")"),
"\" A \" ( \" B \" ) \n"
"\"A\" ( \"B\" )\n"
" \"A\"\n"
".\n"
" (\"B\")\n"
@@ -260,7 +279,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("!method.!const"),
"! method . ! const \n"
"! method . ! const\n"
" !\n"
" method\n"
".\n"
@@ -274,7 +293,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("namespace.class:method"),
"namespace . class : method \n"
"namespace . class : method\n"
" namespace\n"
" .\n"
" class\n"
@@ -288,7 +307,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("class:method|field"),
"class : method | field \n"
"class : method | field\n"
" class\n"
" :\n"
" method\n"
@@ -302,7 +321,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("namespace.(class:method)"),
"namespace . ( class : method ) \n"
"namespace . ( class : method )\n"
" namespace\n"
".\n"
" class\n"
@@ -313,7 +332,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree("class:(method|field)"),
"class : ( method | field ) \n"
"class : ( method | field )\n"
" class\n"
":\n"
" method\n"
@@ -327,7 +346,7 @@ public:
TS_ASSERT_EQUALS(
printedQueryTree(" \"Field \":(method | field) .const | public "),
"\" Field \" : ( method | field ) . const | public \n"
"\"Field\" : ( method | field ) . const | public\n"
" \"Field\"\n"
" :\n"
" method\n"
+21 -21
View File
@@ -102,7 +102,7 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("u");
TS_ASSERT_EQUALS(1, matches.size());
TS_ASSERT_EQUALS("util", matches[0].node->getName());
TS_ASSERT_EQUALS("util", matches[0].fullName);
TS_ASSERT_EQUALS(1, matches[0].indices.size());
TS_ASSERT_EQUALS(0, matches[0].indices[0]);
@@ -120,14 +120,14 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("MATH", matches[0].node->getName());
TS_ASSERT_EQUALS("util", matches[1].node->getName());
TS_ASSERT_EQUALS("MATH", matches[0].fullName);
TS_ASSERT_EQUALS("util", matches[1].fullName);
matches = index.findFuzzyMatches("T");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("MATH", matches[0].node->getName());
TS_ASSERT_EQUALS("util", matches[1].node->getName());
TS_ASSERT_EQUALS("MATH", matches[0].fullName);
TS_ASSERT_EQUALS("util", matches[1].fullName);
}
void test_fuzzy_matching_wheighs_by_distance_and_alphabet()
@@ -140,9 +140,9 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
TS_ASSERT_EQUALS(3, matches.size());
TS_ASSERT_EQUALS("string", matches[0].node->getName());
TS_ASSERT_EQUALS("util", matches[1].node->getName());
TS_ASSERT_EQUALS("math", matches[2].node->getName());
TS_ASSERT_EQUALS("string", matches[0].fullName);
TS_ASSERT_EQUALS("util", matches[1].fullName);
TS_ASSERT_EQUALS("math", matches[2].fullName);
TS_ASSERT_EQUALS(1, matches[0].indices.size());
TS_ASSERT_EQUALS(1, matches[0].indices[0]);
@@ -163,8 +163,8 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("uTil", matches[0].node->getName());
TS_ASSERT_EQUALS("string", matches[1].node->getName());
TS_ASSERT_EQUALS("uTil", matches[0].fullName);
TS_ASSERT_EQUALS("string", matches[1].fullName);
}
void test_fuzzy_matching_wheighs_higher_on_consecutive_letters()
@@ -176,8 +176,8 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("abc");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("ocbaabc", matches[0].node->getName());
TS_ASSERT_EQUALS("oaabbcc", matches[1].node->getName());
TS_ASSERT_EQUALS("ocbaabc", matches[0].fullName);
TS_ASSERT_EQUALS("oaabbcc", matches[1].fullName);
}
void test_fuzzy_matching_in_hierarchy()
@@ -190,13 +190,13 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
TS_ASSERT_EQUALS(1, matches.size());
TS_ASSERT_EQUALS("util", matches[0].node->getName());
TS_ASSERT_EQUALS("util", matches[0].fullName);
matches = index.findFuzzyMatches("uml");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("floor", matches[0].node->getName());
TS_ASSERT_EQUALS("ceil", matches[1].node->getName());
TS_ASSERT_EQUALS("util::math::floor", matches[0].fullName);
TS_ASSERT_EQUALS("util::math::ceil", matches[1].fullName);
}
void test_fuzzy_matching_in_hierarchy_respects_collin()
@@ -209,13 +209,13 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("u:i");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("string", matches[0].node->getName());
TS_ASSERT_EQUALS("ceil", matches[1].node->getName());
TS_ASSERT_EQUALS("util::string", matches[0].fullName);
TS_ASSERT_EQUALS("util::math::ceil", matches[1].fullName);
matches = index.findFuzzyMatches("u:t:i");
TS_ASSERT_EQUALS(1, matches.size());
TS_ASSERT_EQUALS("ceil", matches[0].node->getName());
TS_ASSERT_EQUALS("util::math::ceil", matches[0].fullName);
}
void test_fuzzy_matching_in_hierarchy_weighs_front_letters_higher()
@@ -227,8 +227,8 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("g");
TS_ASSERT_EQUALS(2, matches.size());
TS_ASSERT_EQUALS("ghi", matches[0].node->getName());
TS_ASSERT_EQUALS("hgi", matches[1].node->getName());
TS_ASSERT_EQUALS("abc::dfe::ghi", matches[0].fullName);
TS_ASSERT_EQUALS("abc::hgi", matches[1].fullName);
}
void test_fuzzy_matching_with_defined_start_node()
@@ -241,7 +241,7 @@ public:
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("\"math\"c");
TS_ASSERT_EQUALS(1, matches.size());
TS_ASSERT_EQUALS("ceil", matches[0].node->getName());
TS_ASSERT_EQUALS("math::ceil", matches[0].fullName);
matches = index.findFuzzyMatches("\"mathc");
TS_ASSERT_EQUALS(0, matches.size());
+40
View File
@@ -71,6 +71,46 @@ public:
TS_ASSERT_EQUALS(result[2], "");
}
void test_join_with_char_delimiter()
{
std::vector<std::string> list;
list.push_back("A");
list.push_back("B");
list.push_back("C");
std::string result = utility::join<std::vector<std::string> >(list, ',');
TS_ASSERT_EQUALS(result, "A,B,C");
}
void test_join_with_string_delimiter()
{
std::vector<std::string> list;
list.push_back("A");
list.push_back("B");
list.push_back("C");
std::string result = utility::join<std::vector<std::string> >(list, "==");
TS_ASSERT_EQUALS(result, "A==B==C");
}
void test_join_on_empty_list()
{
std::vector<std::string> list;
std::string result = utility::join<std::vector<std::string> >(list, ',');
TS_ASSERT_EQUALS(result, "");
}
void test_join_with_empty_strings_in_list()
{
std::vector<std::string> list;
list.push_back("A");
list.push_back("");
list.push_back("");
std::string result = utility::join<std::vector<std::string> >(list, ':');
TS_ASSERT_EQUALS(result, "A::");
}
void test_tokenize_with_string()
{
std::vector<std::string> result = utility::tokenize<std::vector<std::string> >("A->B->C", "->");