diff --git a/src/app/qt/element/QtSmartSearchBox.cpp b/src/app/qt/element/QtSmartSearchBox.cpp index 1bf4515b..08c40855 100644 --- a/src/app/qt/element/QtSmartSearchBox.cpp +++ b/src/app/qt/element/QtSmartSearchBox.cpp @@ -36,6 +36,7 @@ void QtSmartSearchBox::search() QtSmartSearchBox::QtSmartSearchBox(QWidget* parent) : QLineEdit(parent) + , m_allowTextChange(false) , m_cursorIndex(0) , m_shiftKeyDown(false) , m_mousePressed(false) @@ -55,6 +56,12 @@ void QtSmartSearchBox::setAutocompletionList(const std::vectorpopup()->setCurrentIndex(completer->completionModel()->index(0, 0)); } void QtSmartSearchBox::setQuery(const std::string& text) @@ -223,7 +232,7 @@ void QtSmartSearchBox::keyPressEvent(QKeyEvent* event) } else if (event->matches(QKeySequence::Paste)) { - setText(text() + QApplication::clipboard()->text()); + setEditText(text() + QApplication::clipboard()->text()); onTextEdited(text()); return; } @@ -304,8 +313,11 @@ void QtSmartSearchBox::mouseReleaseEvent(QMouseEvent* event) void QtSmartSearchBox::onTextEdited(const QString& text) { + m_allowTextChange = true; deleteSelectedElements(); + bool tokensChanged = false; + std::string token; std::deque tokens = QueryTree::tokenizeQuery(text.toStdString()); while (tokens.size()) @@ -317,12 +329,13 @@ void QtSmartSearchBox::onTextEdited(const QString& text) { textToToken(token); token.clear(); + tokensChanged = true; } } - if (text.toStdString() != token) + if (tokensChanged) { - setText(QString::fromStdString(token)); + setEditText(QString::fromStdString(token)); updateElements(); } else @@ -338,18 +351,28 @@ void QtSmartSearchBox::onTextEdited(const QString& text) void QtSmartSearchBox::onTextChanged(const QString& text) { - if (m_oldText.size()) + if (!m_allowTextChange) { setText(m_oldText); + + // This prevents the completer from disappearing while navigating the completion popup. + if (completer() && !completer()->signalsBlocked()) + { + completer()->popup()->show(); + } + } + else + { + m_oldText = text; } - m_oldText.clear(); + m_allowTextChange = false; + updatePlaceholder(); } void QtSmartSearchBox::onSearchCompletionHighlighted(const QModelIndex& index) { - m_oldText = text(); } void QtSmartSearchBox::onSearchCompletionActivated(const QModelIndex& index) @@ -443,6 +466,12 @@ void QtSmartSearchBox::textToToken(std::string text) m_cursorIndex++; } +void QtSmartSearchBox::setEditText(const QString& text) +{ + m_allowTextChange = true; + setText(text); +} + bool QtSmartSearchBox::editTextToElement() { if (text().size()) @@ -471,7 +500,7 @@ void QtSmartSearchBox::editElement(QtQueryElement* element) std::string token = QueryTree::getTokenName(m_tokens[m_cursorIndex]); m_tokens.erase(m_tokens.begin() + m_cursorIndex); - setText(QString::fromStdString(token)); + setEditText(QString::fromStdString(token)); updateElements(); MessageSearchAutocomplete(token).dispatch(); @@ -631,7 +660,7 @@ void QtSmartSearchBox::updatePlaceholder() void QtSmartSearchBox::clearLineEdit() { - setText(""); + setEditText(""); if (completer()) { diff --git a/src/app/qt/element/QtSmartSearchBox.h b/src/app/qt/element/QtSmartSearchBox.h index f5f3485c..928c55ed 100644 --- a/src/app/qt/element/QtSmartSearchBox.h +++ b/src/app/qt/element/QtSmartSearchBox.h @@ -64,6 +64,7 @@ private: void moveCursorTo(int goal); void textToToken(std::string text); + void setEditText(const QString& text); bool editTextToElement(); void editElement(QtQueryElement* element); @@ -80,6 +81,7 @@ private: void updatePlaceholder(); void clearLineEdit(); + bool m_allowTextChange; QString m_oldText; std::deque m_tokens; diff --git a/src/lib/data/query/QueryOperator.cpp b/src/lib/data/query/QueryOperator.cpp index 7a4730e6..d778bfd4 100644 --- a/src/lib/data/query/QueryOperator.cpp +++ b/src/lib/data/query/QueryOperator.cpp @@ -15,8 +15,8 @@ const std::map& QueryOperator::getOperatorTyp operatorMap.emplace(' ', OPERATOR_NONE); operatorMap.emplace('!', OPERATOR_NOT); - operatorMap.emplace('.', OPERATOR_SUB); - operatorMap.emplace('>', OPERATOR_HAS); + operatorMap.emplace('.', OPERATOR_HAS); + operatorMap.emplace('>', OPERATOR_SUB); operatorMap.emplace('&', OPERATOR_AND); operatorMap.emplace('|', OPERATOR_OR); diff --git a/src/lib/data/query/QueryOperator.h b/src/lib/data/query/QueryOperator.h index a510cb1f..f34b70ce 100644 --- a/src/lib/data/query/QueryOperator.h +++ b/src/lib/data/query/QueryOperator.h @@ -15,8 +15,8 @@ public: OPERATOR_NONE, OPERATOR_NOT, - OPERATOR_SUB, OPERATOR_HAS, + OPERATOR_SUB, OPERATOR_AND, OPERATOR_OR, diff --git a/src/test/GraphFilterConductorTestSuite.h b/src/test/GraphFilterConductorTestSuite.h index 41965897..856d605e 100644 --- a/src/test/GraphFilterConductorTestSuite.h +++ b/src/test/GraphFilterConductorTestSuite.h @@ -108,7 +108,7 @@ public: void test_operator_sub() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("'class'.'base'"), + printedFilteredTestGraph("'class'>'base'"), "1 nodes: class:A\n" "0 edges:\n" @@ -118,7 +118,7 @@ public: void test_operator_has() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("\"A\">'field'"), + printedFilteredTestGraph("\"A\".'field'"), "1 nodes: field:A::count\n" "0 edges:\n" @@ -138,7 +138,7 @@ public: void test_operator_group() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("('static'|'const').'public'"), + printedFilteredTestGraph("('static'|'const')>'public'"), "1 nodes: method:A::getCount\n" "0 edges:\n" diff --git a/src/test/QueryTreeTestSuite.h b/src/test/QueryTreeTestSuite.h index 09345ec6..10767868 100644 --- a/src/test/QueryTreeTestSuite.h +++ b/src/test/QueryTreeTestSuite.h @@ -75,7 +75,7 @@ public: "A \" INVALID\n" " \"A\"\n" - ". IMPLICIT\n" + "> IMPLICIT\n" " \"\"\n" ); } @@ -276,36 +276,36 @@ public: "\"A\" ( \"B\" )\n" " \"A\"\n" - ". IMPLICIT\n" + "> IMPLICIT\n" " (\"B\")\n" ); } - void test_operator_precedence_not_before_sub() + void test_operator_precedence_not_before_has() { TS_ASSERT_EQUALS( - printedQueryTree("!'method'.!'const'"), + printedQueryTree("!'struct'.!'const'"), - "! 'method' . ! 'const'\n" + "! 'struct' . ! 'const'\n" " !\n" - " 'method'\n" + " 'struct'\n" ".\n" " !\n" " 'const'\n" ); } - void test_operator_precedence_sub_before_has() + void test_operator_precedence_has_before_sub() { TS_ASSERT_EQUALS( - printedQueryTree("'namespace'.'class'>'method'"), + printedQueryTree("'namespace'.'class'>'base'"), - "'namespace' . 'class' > 'method'\n" + "'namespace' . 'class' > 'base'\n" " 'namespace'\n" " .\n" " 'class'\n" ">\n" - " 'method'\n" + " 'base'\n" ); }