diff --git a/src/app/qt/element/QtCodeFile.cpp b/src/app/qt/element/QtCodeFile.cpp index 3dd2ca2b..173e7d3a 100644 --- a/src/app/qt/element/QtCodeFile.cpp +++ b/src/app/qt/element/QtCodeFile.cpp @@ -37,8 +37,9 @@ const std::string& QtCodeFile::getFileName() const void QtCodeFile::addCodeSnippet( const std::string& str, const TokenLocationFile& locationFile, int startLineNumber, Id activeTokenId ){ - std::shared_ptr snippet = - std::make_shared(m_parentView, str, locationFile, startLineNumber, activeTokenId, this); + std::shared_ptr snippet( + new QtCodeSnippet(m_parentView, str, locationFile, startLineNumber, activeTokenId, this) + ); layout()->addWidget(snippet.get()); m_snippets.push_back(snippet); } diff --git a/src/app/qt/element/QtEditBox.cpp b/src/app/qt/element/QtEditBox.cpp index c91ba832..9669bacc 100644 --- a/src/app/qt/element/QtEditBox.cpp +++ b/src/app/qt/element/QtEditBox.cpp @@ -1,10 +1,13 @@ #include "qt/element/QtEditBox.h" +#include "utility/logging/logging.h" QtEditBox::QtEditBox(QWidget *parent) : QLineEdit(parent) , m_onReturnPressed(nullptr) + , m_onTextEdited(nullptr) { connect(this, SIGNAL(returnPressed()), this, SLOT(slotOnReturnPressed())); + connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(slotOnTextEdited(const QString&))); } QtEditBox::~QtEditBox() @@ -16,8 +19,23 @@ void QtEditBox::setCallbackOnReturnPressed(std::function callback) m_onReturnPressed = callback; } +void QtEditBox::setCallbackOnTextEdited(std::function callback) +{ + m_onTextEdited = callback; +} + void QtEditBox::slotOnReturnPressed() { if (m_onReturnPressed) + { m_onReturnPressed(); + } +} + +void QtEditBox::slotOnTextEdited(const QString& text) +{ + if (m_onTextEdited) + { + m_onTextEdited(text.toStdString()); + } } diff --git a/src/app/qt/element/QtEditBox.h b/src/app/qt/element/QtEditBox.h index faccaeb1..744db97a 100644 --- a/src/app/qt/element/QtEditBox.h +++ b/src/app/qt/element/QtEditBox.h @@ -14,12 +14,15 @@ public: ~QtEditBox(); void setCallbackOnReturnPressed(std::function callback); + void setCallbackOnTextEdited(std::function callback); private slots: void slotOnReturnPressed(); + void slotOnTextEdited(const QString& text); private: std::function m_onReturnPressed; + std::function m_onTextEdited; }; #endif // QT_EDIT_BOX_H diff --git a/src/app/qt/view/QtSearchView.cpp b/src/app/qt/view/QtSearchView.cpp index aafcd4da..3d40a6f7 100644 --- a/src/app/qt/view/QtSearchView.cpp +++ b/src/app/qt/view/QtSearchView.cpp @@ -10,6 +10,8 @@ QtSearchView::QtSearchView(ViewLayout* viewLayout) : SearchView(viewLayout) + , m_setTextFunctor(std::bind(&QtSearchView::doSetText, this, std::placeholders::_1)) + , m_setAutocompletionListFunctor(std::bind(&QtSearchView::doSetAutocompletionList, this, std::placeholders::_1)) { } @@ -36,6 +38,11 @@ void QtSearchView::initGui() m_searchBox->setPlaceholderText("Please enter your search string."); m_searchBox->setCallbackOnReturnPressed(std::bind(&QtSearchView::onSeachButtonClick, this)); + std::vector autocompletionList; + autocompletionList.push_back("tralala"); + autocompletionList.push_back("lalila"); + setAutocompletionList(autocompletionList); + m_searchButton = new QtButton(widget); m_searchButton->setText("Search"); m_searchButton->setCallbackOnClick(std::bind(&QtSearchView::onSeachButtonClick, this)); @@ -44,7 +51,26 @@ void QtSearchView::initGui() widget->layout()->addWidget(m_searchButton); } -void QtSearchView::setText(const std::string& s) const +void QtSearchView::setText(const std::string& s) +{ + m_setTextFunctor(s); +} + +void QtSearchView::setAutocompletionList(const std::vector& autocompletionList) +{ + m_setAutocompletionListFunctor(autocompletionList); +} + +void QtSearchView::onSeachButtonClick() +{ + SearchController* controller = getController(); + if (controller) + { + controller->search(m_searchBox->text().toStdString()); + } +} + +void QtSearchView::doSetText(const std::string& s) { if (m_searchBox->text() != s.c_str()) { @@ -52,7 +78,12 @@ void QtSearchView::setText(const std::string& s) const } } -void QtSearchView::onSeachButtonClick() +void QtSearchView::doSetAutocompletionList(const std::vector& autocompletionList) { - getController()->search(m_searchBox->text().toStdString()); + QStringList wordList; + for (const std::string& s: autocompletionList) + wordList << s.c_str(); + QCompleter *completer = new QCompleter(wordList, m_searchBox); + completer->setCaseSensitivity(Qt::CaseInsensitive); + m_searchBox->setCompleter(completer); } diff --git a/src/app/qt/view/QtSearchView.h b/src/app/qt/view/QtSearchView.h index f094659e..3c85ab7d 100644 --- a/src/app/qt/view/QtSearchView.h +++ b/src/app/qt/view/QtSearchView.h @@ -1,7 +1,10 @@ #ifndef QT_SEARCH_VIEW_H #define QT_SEARCH_VIEW_H +#include + #include "component/view/SearchView.h" +#include "qt/utility/QtThreadedFunctor.h" class QtEditBox; class QtButton; @@ -17,13 +20,19 @@ public: virtual void initGui(); // SearchView implementation - virtual void setText(const std::string& s) const; + virtual void setText(const std::string& s); + virtual void setAutocompletionList(const std::vector& autocompletionList); private: void onSeachButtonClick(); + void doSetText(const std::string& s); + void doSetAutocompletionList(const std::vector& autocompletionList); + QtEditBox* m_searchBox; QtButton* m_searchButton; + QtThreadedFunctor m_setTextFunctor; + QtThreadedFunctor&> m_setAutocompletionListFunctor; }; # endif // QT_SEARCH_VIEW_H diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index 2e8a9118..44ef05d5 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -7,6 +7,7 @@ #include "utility/logging/ConsoleLogger.h" #include "utility/logging/LogManager.h" #include "utility/messaging/MessageQueue.h" +#include "utility/messaging/type/MessageActivateToken.h" std::shared_ptr Application::create(GuiFactory* guiFactory) { @@ -42,4 +43,7 @@ void Application::loadProject() m_project->loadProjectSettings("data/ProjectSettings.xml"); m_project->parseCode(); + + MessageActivateToken message(1); + message.dispatch(); } diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index 03f96826..4bc04542 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -5,7 +5,7 @@ #include "data/parser/cxx/CxxParser.h" #include "utility/FileSystem.h" -#include "utility/messaging/type/MessageActivateToken.h" +#include "utility/messaging/type/MessageFinishedParsing.h" #include "utility/logging/logging.h" std::shared_ptr Project::create( @@ -46,7 +46,7 @@ void Project::parseCode() m_storage->logGraph(); m_storage->logLocations(); - MessageActivateToken message(1); + MessageFinishedParsing message; message.dispatch(); } } diff --git a/src/lib/component/controller/SearchController.cpp b/src/lib/component/controller/SearchController.cpp index 31a60cfb..1eeba057 100644 --- a/src/lib/component/controller/SearchController.cpp +++ b/src/lib/component/controller/SearchController.cpp @@ -2,7 +2,6 @@ #include "component/view/SearchView.h" #include "data/access/GraphAccess.h" -#include "utility/messaging/type/MessageActivateToken.h" SearchController::SearchController(std::shared_ptr graphAccess) : m_graphAccess(graphAccess) @@ -34,6 +33,11 @@ void SearchController::handleMessage(MessageActivateToken* message) getView()->setText(m_graphAccess->getNameForNodeWithId(message->tokenId)); } +void SearchController::handleMessage(MessageFinishedParsing* message) +{ + getView()->setAutocompletionList(m_graphAccess->getNamesForNodesWithNamePrefix("")); +} + SearchView* SearchController::getView() { return Controller::getView(); diff --git a/src/lib/component/controller/SearchController.h b/src/lib/component/controller/SearchController.h index de0f6b6e..2cb37cfa 100644 --- a/src/lib/component/controller/SearchController.h +++ b/src/lib/component/controller/SearchController.h @@ -6,6 +6,7 @@ #include "component/controller/Controller.h" #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateToken.h" +#include "utility/messaging/type/MessageFinishedParsing.h" class GraphAccess; class SearchView; @@ -13,6 +14,7 @@ class SearchView; class SearchController : public Controller , public MessageListener + , public MessageListener { public: SearchController(std::shared_ptr graphAccess); @@ -23,6 +25,7 @@ public: private: virtual void handleMessage(MessageActivateToken* message); + virtual void handleMessage(MessageFinishedParsing* message); SearchView* getView(); std::shared_ptr m_graphAccess; diff --git a/src/lib/component/view/SearchView.h b/src/lib/component/view/SearchView.h index 9d2f2a91..298c5da0 100644 --- a/src/lib/component/view/SearchView.h +++ b/src/lib/component/view/SearchView.h @@ -13,7 +13,8 @@ public: virtual std::string getName() const; - virtual void setText(const std::string& s) const = 0; + virtual void setText(const std::string& s) = 0; + virtual void setAutocompletionList(const std::vector& autocompletionList) = 0; protected: SearchController* getController(); diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index d4d5fcb2..ef186d45 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -8,6 +8,7 @@ #include "data/parser/ParseLocation.h" #include "data/parser/ParseVariable.h" #include "utility/logging/logging.h" +#include "utility/utilityString.h" Storage::Storage() { @@ -191,6 +192,20 @@ std::string Storage::getNameForNodeWithId(Id id) const return (node ? node->getName() : ""); } +std::vector Storage::getNamesForNodesWithNamePrefix(const std::string& prefix) const +{ + std::vector names; + m_graph.forEachNode([&](Node* node){ + const std::string& nodeName = node->getName(); + if (utility::isPrefix(prefix, nodeName)) + { + names.push_back(nodeName); + } + }); + + return names; +} + TokenLocationCollection Storage::getTokenLocationsForTokenId(Id id) const { TokenLocationCollection ret; diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index ca6f1829..ca0af783 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -48,6 +48,7 @@ public: // GraphAccess implementation virtual Id getIdForNodeWithName(const std::string& name) const; virtual std::string getNameForNodeWithId(Id id) const; + virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const; // LocationAccess implementation virtual TokenLocationCollection getTokenLocationsForTokenId(Id locationId) const; diff --git a/src/lib/data/access/GraphAccess.h b/src/lib/data/access/GraphAccess.h index d2b231ed..64cd5424 100644 --- a/src/lib/data/access/GraphAccess.h +++ b/src/lib/data/access/GraphAccess.h @@ -2,6 +2,7 @@ #define GRAPH_ACCESS_H #include +#include #include "utility/types.h" @@ -14,6 +15,7 @@ public: virtual Id getIdForNodeWithName(const std::string& name) const = 0; virtual std::string getNameForNodeWithId(Id id) const = 0; + virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const = 0; }; diff --git a/src/lib/utility/messaging/type/MessageActivateToken.h b/src/lib/utility/messaging/type/MessageActivateToken.h index 1f4c9e98..4bf6d18e 100644 --- a/src/lib/utility/messaging/type/MessageActivateToken.h +++ b/src/lib/utility/messaging/type/MessageActivateToken.h @@ -17,7 +17,6 @@ public: return "MessageActivateToken"; } -public: const Id tokenId; }; diff --git a/src/lib/utility/messaging/type/MessageFinishedParsing.h b/src/lib/utility/messaging/type/MessageFinishedParsing.h new file mode 100644 index 00000000..c41978ee --- /dev/null +++ b/src/lib/utility/messaging/type/MessageFinishedParsing.h @@ -0,0 +1,19 @@ +#ifndef MESSAGE_FINISHED_PARSING_H +#define MESSAGE_FINISHED_PARSING_H + +#include "utility/messaging/Message.h" + +class MessageFinishedParsing: public Message +{ +public: + MessageFinishedParsing() + { + } + + static const std::string getStaticType() + { + return "MessageFinishedParsing"; + } +}; + +#endif // MESSAGE_FINISHED_PARSING_H diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index 3f19589d..ec1a9119 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -23,4 +23,12 @@ namespace utility return vec; } + + bool isPrefix(const std::string& prefix, const std::string& text) + { + typedef std::pair ResType; + ResType res = std::mismatch(prefix.begin(), prefix.end(), text.begin()); + + return res.first == prefix.end(); + } } diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 23c31f54..884ef726 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -8,6 +8,8 @@ namespace utility { std::vector split(const std::string& str, char delimiter); std::vector split(const std::string& str, const std::string& delimiter); + + bool isPrefix(const std::string& prefix, const std::string& text); } #endif // UTILITY_STRING_H diff --git a/src/test/UtilityStringTestSuite.h b/src/test/UtilityStringTestSuite.h index ca502c75..a5e7742f 100644 --- a/src/test/UtilityStringTestSuite.h +++ b/src/test/UtilityStringTestSuite.h @@ -50,4 +50,35 @@ public: TS_ASSERT_EQUALS(result[2], "B"); TS_ASSERT_EQUALS(result[3], "C"); } + + void test_empty_string_is_detected_as_prefix_of_any_other_string() + { + const std::string foo = "foo"; + + TS_ASSERT(utility::isPrefix("", foo)); + } + + void test_prefix_of_bigger_text_is_detected_as_prefix() + { + const std::string foobar = "foobar"; + const std::string foo = "foo"; + + TS_ASSERT(utility::isPrefix(foo, foobar)); + } + + void test_prefix_is_detected_as_prefix_of_self() + { + const std::string foo = "foo"; + + TS_ASSERT(utility::isPrefix(foo, foo)); + } + + void test_different_texts_are_not_detected_of_prefixes_of_each_other() + { + const std::string foo = "foo"; + const std::string bar = "bar"; + + TS_ASSERT(!utility::isPrefix(foo, bar)); + TS_ASSERT(!utility::isPrefix(bar, foo)); + } };