From 1690479b0e451ca96ce69c153c077226704659cd Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Tue, 3 Feb 2015 14:27:39 +0100 Subject: [PATCH] ui/logic/data: refreshing only source files that have been updated This change adds the refresh component that allows for refreshing the source code via UI or shortcut. If automatic refreshing is activated via the UI, the code is refreshed anytime the window gets focus. The contents of all the updated source files get removed from Storage, before reparsing them. File dependencies are not respected yet. --- CMakeLists.txt | 2 +- .../gui/refresh_view/images/auto_refresh.png | Bin 0 -> 3142 bytes .../data/gui/refresh_view/images/refresh.png | Bin 0 -> 3154 bytes .../data/gui/refresh_view/refresh_view.css | 32 ++++ bin/app/data/src/test/main.cpp | 2 +- bin/test/data/FileSystemTestSuite/update.c | 1 + bin/test/data/log/test_log.txt | 51 ++++--- src/app/CMakeLists.txt | 4 + src/app/qt/element/QtMainWindow.cpp | 11 ++ src/app/qt/element/QtMainWindow.h | 3 + src/app/qt/element/QtRefreshBar.cpp | 56 +++++++ src/app/qt/element/QtRefreshBar.h | 28 ++++ src/app/qt/element/QtSearchBar.h | 6 +- src/app/qt/view/QtRefreshView.cpp | 43 ++++++ src/app/qt/view/QtRefreshView.h | 34 +++++ src/app/qt/view/QtViewFactory.cpp | 6 + src/app/qt/view/QtViewFactory.h | 1 + src/lib/Application.cpp | 7 +- src/lib/CMakeLists.txt | 6 + src/lib/Project.cpp | 30 +++- src/lib/Project.h | 4 +- src/lib/component/ComponentFactory.cpp | 11 ++ src/lib/component/ComponentFactory.h | 1 + src/lib/component/ComponentManager.cpp | 9 +- .../controller/RefreshController.cpp | 35 +++++ .../component/controller/RefreshController.h | 32 ++++ .../controller/StatusBarController.cpp | 1 + src/lib/component/view/RefreshView.cpp | 22 +++ src/lib/component/view/RefreshView.h | 21 +++ src/lib/component/view/ViewFactory.h | 2 + src/lib/data/Storage.cpp | 115 +++++++++++++-- src/lib/data/Storage.h | 4 +- src/lib/data/graph/Graph.cpp | 34 ++++- src/lib/data/graph/Graph.h | 1 + src/lib/data/graph/Node.cpp | 31 ++++ src/lib/data/graph/Node.h | 2 + .../data/location/TokenLocationCollection.cpp | 26 +++- .../data/location/TokenLocationCollection.h | 2 + src/lib/data/search/SearchIndex.cpp | 51 +++++++ src/lib/data/search/SearchIndex.h | 6 + src/lib/data/search/SearchNode.cpp | 67 ++++++++- src/lib/data/search/SearchNode.h | 9 +- src/lib/utility/FileSystem.cpp | 77 +++++++--- src/lib/utility/FileSystem.h | 14 +- .../type/MessageAutoRefreshChanged.h | 22 +++ .../messaging/type/MessageFinishedParsing.h | 6 +- .../utility/messaging/type/MessageRefresh.h | 1 - .../messaging/type/MessageWindowFocus.h | 19 +++ src/test/FileSystemTestSuite.h | 29 +++- src/test/GraphTestSuite.h | 67 +++++++++ src/test/SearchIndexTestSuite.h | 56 ++++++- src/test/StorageTestSuite.h | 137 +++++++++++++++++- 52 files changed, 1145 insertions(+), 92 deletions(-) create mode 100644 bin/app/data/gui/refresh_view/images/auto_refresh.png create mode 100755 bin/app/data/gui/refresh_view/images/refresh.png create mode 100644 bin/app/data/gui/refresh_view/refresh_view.css create mode 100644 bin/test/data/FileSystemTestSuite/update.c create mode 100644 src/app/qt/element/QtRefreshBar.cpp create mode 100644 src/app/qt/element/QtRefreshBar.h create mode 100644 src/app/qt/view/QtRefreshView.cpp create mode 100644 src/app/qt/view/QtRefreshView.h create mode 100644 src/lib/component/controller/RefreshController.cpp create mode 100644 src/lib/component/controller/RefreshController.h create mode 100644 src/lib/component/view/RefreshView.cpp create mode 100644 src/lib/component/view/RefreshView.h create mode 100644 src/lib/utility/messaging/type/MessageAutoRefreshChanged.h create mode 100644 src/lib/utility/messaging/type/MessageWindowFocus.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 966a826c..08ad50b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ set(Boost_USE_MULTITHREAD ON) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_STATIC_RUNTIME OFF) set(BOOST_LIBRARYDIR $ENV{BOOST_155_DIR}) -find_package(Boost 1.55 COMPONENTS system filesystem REQUIRED) +find_package(Boost 1.55 COMPONENTS system filesystem date_time REQUIRED) # Eigen ------------------------------------------------------------------------- diff --git a/bin/app/data/gui/refresh_view/images/auto_refresh.png b/bin/app/data/gui/refresh_view/images/auto_refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..ae7bc7c4b671ca9074eb51e705e03ebad46535a3 GIT binary patch literal 3142 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 literal 0 HcmV?d00001 diff --git a/bin/app/data/gui/refresh_view/images/refresh.png b/bin/app/data/gui/refresh_view/images/refresh.png new file mode 100755 index 0000000000000000000000000000000000000000..f674bd4f096384300c1a8d711da253bf80743bc7 GIT binary patch literal 3154 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 +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::getCount +Storage.cpp INFO: global usage: A::getCount -> A::count +Storage.cpp INFO: method: A::process +Storage.cpp INFO: field: A::count +Storage.cpp INFO: class: B +Storage.cpp INFO: inheritance: B : A +Storage.cpp INFO: method: B::process +Storage.cpp INFO: type usage: B::process -> int +Storage.cpp INFO: function: main +Storage.cpp INFO: type usage: main -> B +Storage.cpp INFO: call: main -> B::B +Storage.cpp INFO: call: main -> A::getCount Storage.cpp INFO: class: A Storage.cpp INFO: method: A::A Storage.cpp INFO: global usage: A::A -> A::count @@ -31,24 +52,6 @@ SearchMatch.cpp INFO: 237 A::A ^^^^ -Storage.cpp INFO: class: A -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::getCount -Storage.cpp INFO: global usage: A::getCount -> A::count -Storage.cpp INFO: method: A::process -Storage.cpp INFO: field: A::count -Storage.cpp INFO: class: B -Storage.cpp INFO: inheritance: B : A -Storage.cpp INFO: method: B::process -Storage.cpp INFO: type usage: B::process -> int -Storage.cpp INFO: function: main -Storage.cpp INFO: type usage: main -> B -Storage.cpp INFO: call: main -> B::B -Storage.cpp INFO: call: main -> A::getCount -Token.cpp ERROR: Location Id was not referenced by this Token. -Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class -Edge.cpp ERROR: Nodes are not plain copies. Settings.cpp WARNING: File for Settings not found. ConfigManager.cpp ERROR: value Bool is not present in config. ConfigManager.cpp ERROR: value Int is not present in config. @@ -64,7 +67,6 @@ ConfigManager.cpp ERROR: value Int is not present in config. ConfigManager.cpp ERROR: value Float is not present in config. ConfigManager.cpp ERROR: value String is not present in config. ConfigManager.cpp ERROR: value NewBool is not present in config. -Graph.cpp ERROR: Can't remove member edge, without removing the child node. Storage.cpp INFO: typedef: type -> int Storage.cpp INFO: class: Class Storage.cpp INFO: struct: Struct @@ -107,6 +109,17 @@ Storage.cpp INFO: global usage: isTrue -> global Storage.cpp INFO: function: isTrue Storage.cpp INFO: struct: Struct Storage.cpp INFO: type usage: isTrue -> Struct +Storage.cpp INFO: function: isTrue +Storage.cpp INFO: function: isTrue +Storage.cpp INFO: function: main +Storage.cpp INFO: call: main -> isTrue +Storage.cpp INFO: function: isTrue +Storage.cpp INFO: function: main +Storage.cpp INFO: call: main -> isTrue +Storage.cpp INFO: function: isTrue +Storage.cpp INFO: function: main +Storage.cpp INFO: call: main -> isTrue +Graph.cpp ERROR: Can't remove member edge, without removing the child node. TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 38dbee85..2574d379 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -15,6 +15,8 @@ add_files( qt/element/QtCodeSnippet.h qt/element/QtMainWindow.cpp qt/element/QtMainWindow.h + qt/element/QtRefreshBar.cpp + qt/element/QtRefreshBar.h qt/element/QtSearchBar.cpp qt/element/QtSearchBar.h qt/element/QtSmartSearchBox.cpp @@ -56,6 +58,8 @@ add_files( qt/view/QtGraphView.h qt/view/QtMainView.cpp qt/view/QtMainView.h + qt/view/QtRefreshView.cpp + qt/view/QtRefreshView.h qt/view/QtSearchView.cpp qt/view/QtSearchView.h qt/view/QtStatusBarView.cpp diff --git a/src/app/qt/element/QtMainWindow.cpp b/src/app/qt/element/QtMainWindow.cpp index cdc3c151..36548920 100644 --- a/src/app/qt/element/QtMainWindow.cpp +++ b/src/app/qt/element/QtMainWindow.cpp @@ -17,6 +17,7 @@ #include "utility/messaging/type/MessageRefresh.h" #include "utility/messaging/type/MessageSaveProject.h" #include "utility/messaging/type/MessageUndo.h" +#include "utility/messaging/type/MessageWindowFocus.h" QtMainWindow::QtMainWindow() { @@ -208,6 +209,16 @@ void QtMainWindow::saveLayout() } } +bool QtMainWindow::event(QEvent* event) +{ + if (event->type() == QEvent::WindowActivate) + { + MessageWindowFocus().dispatch(); + } + + return QMainWindow::event(event); +} + void QtMainWindow::setupProjectMenu() { QMenu *menu = new QMenu(tr("&Project"), this); diff --git a/src/app/qt/element/QtMainWindow.h b/src/app/qt/element/QtMainWindow.h index d5d41a68..bdf2099a 100644 --- a/src/app/qt/element/QtMainWindow.h +++ b/src/app/qt/element/QtMainWindow.h @@ -26,6 +26,9 @@ public: void loadLayout(); void saveLayout(); +protected: + bool event(QEvent* event); + public slots: void about(); void newProject(); diff --git a/src/app/qt/element/QtRefreshBar.cpp b/src/app/qt/element/QtRefreshBar.cpp new file mode 100644 index 00000000..7c3b86e1 --- /dev/null +++ b/src/app/qt/element/QtRefreshBar.cpp @@ -0,0 +1,56 @@ +#include "qt/element/QtRefreshBar.h" + +#include +#include + +#include "utility/messaging/type/MessageAutoRefreshChanged.h" +#include "utility/messaging/type/MessageRefresh.h" + +QtRefreshBar::QtRefreshBar() +{ + setObjectName("refresh_bar"); + + QBoxLayout* layout = new QHBoxLayout(); + layout->setSpacing(0); + layout->setAlignment(Qt::AlignTop); + setLayout(layout); + + m_refreshButton = new QPushButton(this); + m_refreshButton->setObjectName("refresh_button"); + m_refreshButton->setToolTip("refresh"); + m_refreshButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac + m_refreshButton->setIcon(QIcon("data/gui/refresh_view/images/refresh.png")); + m_refreshButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); + layout->addWidget(m_refreshButton); + + m_autoRefreshButton = new QPushButton(this); + m_autoRefreshButton->setObjectName("auto_refresh_button"); + m_autoRefreshButton->setCheckable(true); + m_autoRefreshButton->setToolTip("automatic refresh on window focus"); + m_autoRefreshButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac + m_autoRefreshButton->setIcon(QIcon("data/gui/refresh_view/images/auto_refresh.png")); + m_autoRefreshButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); + layout->addWidget(m_autoRefreshButton); + + connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(refreshClicked())); + connect(m_autoRefreshButton, SIGNAL(clicked()), this, SLOT(autoRefreshClicked())); +} + +QtRefreshBar::~QtRefreshBar() +{ +} + +QSize QtRefreshBar::sizeHint() const +{ + return QSize(150, 100); +} + +void QtRefreshBar::refreshClicked() +{ + MessageRefresh().dispatch(); +} + +void QtRefreshBar::autoRefreshClicked() +{ + MessageAutoRefreshChanged(m_autoRefreshButton->isChecked()).dispatch(); +} diff --git a/src/app/qt/element/QtRefreshBar.h b/src/app/qt/element/QtRefreshBar.h new file mode 100644 index 00000000..2fb37c21 --- /dev/null +++ b/src/app/qt/element/QtRefreshBar.h @@ -0,0 +1,28 @@ +#ifndef QT_REFRESH_BAR_H +#define QT_REFRESH_BAR_H + +#include + +class QPushButton; + +class QtRefreshBar + : public QFrame +{ + Q_OBJECT + +public: + QtRefreshBar(); + virtual ~QtRefreshBar(); + + virtual QSize sizeHint() const; + +private slots: + void refreshClicked(); + void autoRefreshClicked(); + +private: + QPushButton* m_refreshButton; + QPushButton* m_autoRefreshButton; +}; + +#endif // QT_REFRESH_BAR_H diff --git a/src/app/qt/element/QtSearchBar.h b/src/app/qt/element/QtSearchBar.h index fdb3bfd9..2706cc7d 100644 --- a/src/app/qt/element/QtSearchBar.h +++ b/src/app/qt/element/QtSearchBar.h @@ -1,5 +1,5 @@ -#ifndef QT_SEARCH_BOX_H -#define QT_SEARCH_BOX_H +#ifndef QT_SEARCH_BAR_H +#define QT_SEARCH_BAR_H #include @@ -35,4 +35,4 @@ private: // QPushButton* m_caseSensitiveButton; }; -#endif // QT_SEARCH_BOX_H +#endif // QT_SEARCH_BAR_H diff --git a/src/app/qt/view/QtRefreshView.cpp b/src/app/qt/view/QtRefreshView.cpp new file mode 100644 index 00000000..5594fbe8 --- /dev/null +++ b/src/app/qt/view/QtRefreshView.cpp @@ -0,0 +1,43 @@ +#include "qt/view/QtRefreshView.h" + +#include "component/controller/RefreshController.h" +#include "qt/view/QtViewWidgetWrapper.h" +#include "utility/text/TextAccess.h" + +QtRefreshView::QtRefreshView(ViewLayout* viewLayout) + : RefreshView(viewLayout) + , m_refreshViewFunctor(std::bind(&QtRefreshView::doRefreshView, this)) +{ + m_widget = std::make_shared(); + setStyleSheet(); +} + +QtRefreshView::~QtRefreshView() +{ +} + +void QtRefreshView::createWidgetWrapper() +{ + setWidgetWrapper(std::make_shared(m_widget)); +} + +void QtRefreshView::initView() +{ +} + +void QtRefreshView::refreshView() +{ + m_refreshViewFunctor(); +} + +void QtRefreshView::doRefreshView() +{ + setStyleSheet(); +} + +void QtRefreshView::setStyleSheet() +{ + std::string css = TextAccess::createFromFile("data/gui/refresh_view/refresh_view.css")->getText(); + + m_widget->setStyleSheet(css.c_str()); +} diff --git a/src/app/qt/view/QtRefreshView.h b/src/app/qt/view/QtRefreshView.h new file mode 100644 index 00000000..16811347 --- /dev/null +++ b/src/app/qt/view/QtRefreshView.h @@ -0,0 +1,34 @@ +#ifndef QT_REFRESH_VIEW_H +#define QT_REFRESH_VIEW_H + +#include + +#include "component/view/RefreshView.h" +#include "qt/element/QtRefreshBar.h" +#include "qt/utility/QtThreadedFunctor.h" + +class QtRefreshView + : public RefreshView +{ +public: + QtRefreshView(ViewLayout* viewLayout); + ~QtRefreshView(); + + // View implementation + virtual void createWidgetWrapper(); + virtual void initView(); + virtual void refreshView(); + + // RefreshView implementation + +private: + void doRefreshView(); + + void setStyleSheet(); + + QtThreadedFunctor<> m_refreshViewFunctor; + + std::shared_ptr m_widget; +}; + +# endif // QT_REFRESH_VIEW_H diff --git a/src/app/qt/view/QtViewFactory.cpp b/src/app/qt/view/QtViewFactory.cpp index caec59e8..42413763 100644 --- a/src/app/qt/view/QtViewFactory.cpp +++ b/src/app/qt/view/QtViewFactory.cpp @@ -3,6 +3,7 @@ #include "qt/view/QtCodeView.h" #include "qt/view/QtGraphView.h" #include "qt/view/QtMainView.h" +#include "qt/view/QtRefreshView.h" #include "qt/view/QtSearchView.h" #include "qt/view/QtStatusBarView.h" #include "qt/view/QtUndoRedoView.h" @@ -30,6 +31,11 @@ std::shared_ptr QtViewFactory::createGraphView(ViewLayout* viewLayout return View::create(viewLayout); } +std::shared_ptr QtViewFactory::createRefreshView(ViewLayout* viewLayout) const +{ + return View::create(viewLayout); +} + std::shared_ptr QtViewFactory::createSearchView(ViewLayout* viewLayout) const { return View::create(viewLayout); diff --git a/src/app/qt/view/QtViewFactory.h b/src/app/qt/view/QtViewFactory.h index 73fe5481..62ca74f0 100644 --- a/src/app/qt/view/QtViewFactory.h +++ b/src/app/qt/view/QtViewFactory.h @@ -12,6 +12,7 @@ public: virtual std::shared_ptr createMainView() const; virtual std::shared_ptr createCodeView(ViewLayout* viewLayout) const; virtual std::shared_ptr createGraphView(ViewLayout* viewLayout) const; + virtual std::shared_ptr createRefreshView(ViewLayout* viewLayout) const; virtual std::shared_ptr createSearchView(ViewLayout* viewLayout) const; virtual std::shared_ptr createStatusBarView(ViewLayout* viewLayout) const; virtual std::shared_ptr createUndoRedoView(ViewLayout* viewLayout) const; diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index 49aaec60..b4a1d6df 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -46,7 +46,7 @@ void Application::loadProject(const std::string& projectSettingsFilePath) m_project = Project::create(m_graphAccessProxy.get(), m_locationAccessProxy.get()); m_project->loadProjectSettings(projectSettingsFilePath); - m_project->parseCode(); + m_project->parseCode(false); } void Application::loadSource(const std::string& sourceDirectoryPath) @@ -55,13 +55,12 @@ void Application::loadSource(const std::string& sourceDirectoryPath) m_project->clearProjectSettings(); m_project->setSourceDirectoryPath(sourceDirectoryPath); - m_project->parseCode(); + m_project->parseCode(false); } void Application::reloadProject() { - m_project->clearStorage(); - m_project->parseCode(); + m_project->parseCode(true); } void Application::saveProject(const std::string& projectSettingsFilePath) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index e1293a66..70499397 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -32,6 +32,8 @@ add_files( component/controller/GraphController.h component/controller/GraphLayouter.cpp component/controller/GraphLayouter.h + component/controller/RefreshController.cpp + component/controller/RefreshController.h component/controller/SearchController.cpp component/controller/SearchController.h component/controller/StatusBarController.cpp @@ -50,6 +52,8 @@ add_files( component/view/GraphView.h component/view/MainView.cpp component/view/MainView.h + component/view/RefreshView.cpp + component/view/RefreshView.h component/view/SearchView.cpp component/view/SearchView.h component/view/StatusBarView.cpp @@ -204,6 +208,7 @@ add_files( utility/messaging/type/MessageActivateTokenLocation.h utility/messaging/type/MessageActivateTokens.h + utility/messaging/type/MessageAutoRefreshChanged.h utility/messaging/type/MessageError.h utility/messaging/type/MessageFind.h utility/messaging/type/MessageFinishedParsing.h @@ -219,6 +224,7 @@ add_files( utility/messaging/type/MessageStatus.h utility/messaging/type/MessageRedo.h utility/messaging/type/MessageUndo.h + utility/messaging/type/MessageWindowFocus.h utility/messaging/Message.h utility/messaging/MessageBase.h diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index 4b914e77..030ce032 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -77,7 +77,7 @@ void Project::clearStorage() Token::resetNextId(); } -void Project::parseCode() +void Project::parseCode(bool refresh) { std::string sourcePath = ProjectSettings::getInstance()->getSourcePath(); if (sourcePath.size()) @@ -92,11 +92,33 @@ void Project::parseCode() std::vector headerSearchPaths = ProjectSettings::getInstance()->getHeaderSearchPaths(); headerSearchPaths.push_back(sourcePath); - CxxParser parser(m_storage.get()); + std::vector filePaths; + if (refresh) + { + filePaths = FileSystem::getFileNamesFromDirectoryUpdatedAfter(sourcePath, extensions, m_lastParseTimeString); + } + else + { + filePaths = FileSystem::getFileNamesFromDirectory(sourcePath, extensions); + } + if (!filePaths.size()) + { + MessageFinishedParsing(0, 0, m_storage->getErrorCount()).dispatch(); + return; + } + + m_lastParseTimeString = FileSystem::getTimeStringNow(); + + if (refresh) + { + m_storage->clearFileData(filePaths); + } + + CxxParser parser(m_storage.get()); clock_t time = clock(); parser.parseFiles( - FileSystem::getSourceFilesFromDirectory(sourcePath, extensions), + filePaths, ApplicationSettings::getInstance()->getHeaderSearchPaths(), headerSearchPaths ); @@ -108,7 +130,7 @@ void Project::parseCode() double parseTime = (double)(time) / CLOCKS_PER_SEC; LOG_INFO_STREAM(<< "parse time: " << parseTime); - MessageFinishedParsing(parseTime, m_storage->getErrorCount()).dispatch(); + MessageFinishedParsing(filePaths.size(), parseTime, m_storage->getErrorCount()).dispatch(); } } diff --git a/src/lib/Project.h b/src/lib/Project.h index dfe2c666..edd1989a 100644 --- a/src/lib/Project.h +++ b/src/lib/Project.h @@ -23,7 +23,7 @@ public: bool setSourceDirectoryPath(const std::string& sourceDirectoryPath); void clearStorage(); - void parseCode(); + void parseCode(bool refresh); private: Project(GraphAccessProxy* graphAccessProxy, LocationAccessProxy* locationAccessProxy); @@ -36,6 +36,8 @@ private: LocationAccessProxy* const m_locationAccessProxy; std::shared_ptr m_storage; + + std::string m_lastParseTimeString; }; #endif // PROJECT_H diff --git a/src/lib/component/ComponentFactory.cpp b/src/lib/component/ComponentFactory.cpp index 0fd8f6bc..ee632b62 100644 --- a/src/lib/component/ComponentFactory.cpp +++ b/src/lib/component/ComponentFactory.cpp @@ -3,11 +3,13 @@ #include "component/Component.h" #include "component/controller/CodeController.h" #include "component/controller/GraphController.h" +#include "component/controller/RefreshController.h" #include "component/controller/SearchController.h" #include "component/controller/StatusBarController.h" #include "component/controller/UndoRedoController.h" #include "component/view/CodeView.h" #include "component/view/GraphView.h" +#include "component/view/RefreshView.h" #include "component/view/SearchView.h" #include "component/view/StatusBarView.h" #include "component/view/UndoRedoView.h" @@ -47,6 +49,15 @@ std::shared_ptr ComponentFactory::createGraphComponent() return component; } +std::shared_ptr ComponentFactory::createRefreshComponent() +{ + std::shared_ptr view = m_viewFactory->createRefreshView(m_viewLayout); + std::shared_ptr controller = std::make_shared(); + + std::shared_ptr component = std::make_shared(view, controller); + return component; +} + std::shared_ptr ComponentFactory::createSearchComponent() { std::shared_ptr view = m_viewFactory->createSearchView(m_viewLayout); diff --git a/src/lib/component/ComponentFactory.h b/src/lib/component/ComponentFactory.h index f72fe47a..61e81333 100644 --- a/src/lib/component/ComponentFactory.h +++ b/src/lib/component/ComponentFactory.h @@ -21,6 +21,7 @@ public: std::shared_ptr createCodeComponent(); std::shared_ptr createGraphComponent(); + std::shared_ptr createRefreshComponent(); std::shared_ptr createSearchComponent(); std::shared_ptr createStatusBarComponent(); std::shared_ptr createUndoRedoComponent(); diff --git a/src/lib/component/ComponentManager.cpp b/src/lib/component/ComponentManager.cpp index a809c146..42ad9c16 100644 --- a/src/lib/component/ComponentManager.cpp +++ b/src/lib/component/ComponentManager.cpp @@ -24,14 +24,17 @@ void ComponentManager::setup() std::shared_ptr codeComponent = m_componentFactory->createCodeComponent(); m_components.push_back(codeComponent); + std::shared_ptr undoRedoComponent = m_componentFactory->createUndoRedoComponent(); + m_components.push_back(undoRedoComponent); + + std::shared_ptr refreshComponent = m_componentFactory->createRefreshComponent(); + m_components.push_back(refreshComponent); + std::shared_ptr searchComponent = m_componentFactory->createSearchComponent(); m_components.push_back(searchComponent); std::shared_ptr statusBarComponent = m_componentFactory->createStatusBarComponent(); m_components.push_back(statusBarComponent); - - std::shared_ptr undoRedoComponent = m_componentFactory->createUndoRedoComponent(); - m_components.push_back(undoRedoComponent); } ComponentManager::ComponentManager() diff --git a/src/lib/component/controller/RefreshController.cpp b/src/lib/component/controller/RefreshController.cpp new file mode 100644 index 00000000..4112fa3b --- /dev/null +++ b/src/lib/component/controller/RefreshController.cpp @@ -0,0 +1,35 @@ +#include "component/controller/RefreshController.h" + +#include "component/view/RefreshView.h" + +RefreshController::RefreshController() + : m_autoRefreshEnabled(false) +{ +} + +RefreshController::~RefreshController() +{ +} + +void RefreshController::handleMessage(MessageAutoRefreshChanged* message) +{ + m_autoRefreshEnabled = message->enabled; +} + +void RefreshController::handleMessage(MessageRefresh* message) +{ + getView()->refreshView(); +} + +void RefreshController::handleMessage(MessageWindowFocus* message) +{ + if (m_autoRefreshEnabled) + { + MessageRefresh().dispatch(); + } +} + +RefreshView* RefreshController::getView() +{ + return Controller::getView(); +} diff --git a/src/lib/component/controller/RefreshController.h b/src/lib/component/controller/RefreshController.h new file mode 100644 index 00000000..54ae9d1c --- /dev/null +++ b/src/lib/component/controller/RefreshController.h @@ -0,0 +1,32 @@ +#ifndef REFRESH_CONTROLLER_H +#define REFRESH_CONTROLLER_H + +#include "component/controller/Controller.h" +#include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageAutoRefreshChanged.h" +#include "utility/messaging/type/MessageRefresh.h" +#include "utility/messaging/type/MessageWindowFocus.h" + +class RefreshView; + +class RefreshController + : public Controller + , public MessageListener + , public MessageListener + , public MessageListener +{ +public: + RefreshController(); + virtual ~RefreshController(); + +private: + virtual void handleMessage(MessageAutoRefreshChanged* message); + virtual void handleMessage(MessageRefresh* message); + virtual void handleMessage(MessageWindowFocus* message); + + RefreshView* getView(); + + bool m_autoRefreshEnabled; +}; + +#endif // REFRESH_CONTROLLER_H diff --git a/src/lib/component/controller/StatusBarController.cpp b/src/lib/component/controller/StatusBarController.cpp index 8b63bc37..847cef6f 100644 --- a/src/lib/component/controller/StatusBarController.cpp +++ b/src/lib/component/controller/StatusBarController.cpp @@ -28,6 +28,7 @@ void StatusBarController::handleMessage(MessageFinishedParsing* message) { std::stringstream ss; ss << "Parsing Finished: "; + ss << message->fileCount << " files, "; ss << std::setprecision(2) << message->parseTime << " seconds, "; ss << message->errorCount << " error(s)"; diff --git a/src/lib/component/view/RefreshView.cpp b/src/lib/component/view/RefreshView.cpp new file mode 100644 index 00000000..368eef47 --- /dev/null +++ b/src/lib/component/view/RefreshView.cpp @@ -0,0 +1,22 @@ +#include "component/view/RefreshView.h" + +#include "component/controller/RefreshController.h" + +RefreshView::RefreshView(ViewLayout* viewLayout) + : View(viewLayout, Vec2i(100, 100)) +{ +} + +RefreshView::~RefreshView() +{ +} + +std::string RefreshView::getName() const +{ + return "RefreshView"; +} + +RefreshController* RefreshView::getController() +{ + return View::getController(); +} diff --git a/src/lib/component/view/RefreshView.h b/src/lib/component/view/RefreshView.h new file mode 100644 index 00000000..3c70d834 --- /dev/null +++ b/src/lib/component/view/RefreshView.h @@ -0,0 +1,21 @@ +#ifndef REFRESH_VIEW_H +#define REFRESH_VIEW_H + +#include "component/view/View.h" + +class RefreshController; + +class RefreshView + : public View +{ +public: + RefreshView(ViewLayout* viewLayout); + virtual ~RefreshView(); + + virtual std::string getName() const; + +private: + RefreshController* getController(); +}; + +#endif // REFRESH_VIEW_H diff --git a/src/lib/component/view/ViewFactory.h b/src/lib/component/view/ViewFactory.h index 96938be9..880aa385 100644 --- a/src/lib/component/view/ViewFactory.h +++ b/src/lib/component/view/ViewFactory.h @@ -6,6 +6,7 @@ class CodeView; class GraphView; class MainView; +class RefreshView; class SearchView; class StatusBarView; class UndoRedoView; @@ -20,6 +21,7 @@ public: virtual std::shared_ptr createMainView() const = 0; virtual std::shared_ptr createCodeView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createGraphView(ViewLayout* viewLayout) const = 0; + virtual std::shared_ptr createRefreshView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createSearchView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createStatusBarView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createUndoRedoView(ViewLayout* viewLayout) const = 0; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 8e01c7e5..69395184 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -1,7 +1,5 @@ #include "data/Storage.h" -#include - #include "utility/logging/logging.h" #include "utility/utilityString.h" @@ -38,6 +36,66 @@ void Storage::clear() m_graph.clear(); m_locationCollection.clear(); m_tokenIndex.clear(); + + m_errorMessages.clear(); + m_errorLocationCollection.clear(); +} + +void Storage::clearFileData(const std::vector& filePaths) +{ + for (const std::string& filePath : filePaths) + { + TokenLocationFile* errorFile = m_errorLocationCollection.findTokenLocationFileByPath(filePath); + if (errorFile) + { + m_errorLocationCollection.removeTokenLocationFile(errorFile); + } + + TokenLocationFile* file = m_locationCollection.findTokenLocationFileByPath(filePath); + if (!file) + { + continue; + } + + file->forEachTokenLocation( + [&](TokenLocation* location) + { + if (location->isEndTokenLocation()) + { + return; + } + + Token* token = m_graph.getTokenById(location->getTokenId()); + if (!token) + { + return; + } + + token->removeLocationId(location->getId()); + if (token->getLocationIds().size()) + { + return; + } + + if (token->isEdge()) + { + Edge* edge = dynamic_cast(token); + Node* from = edge->getFrom(); + Node* to = edge->getTo(); + + m_graph.removeEdge(edge); + removeNodeIfUnreferenced(from); + removeNodeIfUnreferenced(to); + } + else + { + removeNodeIfUnreferenced(dynamic_cast(token)); + } + } + ); + + m_locationCollection.removeTokenLocationFile(file); + } } void Storage::logGraph() const @@ -52,7 +110,7 @@ void Storage::logLocations() const size_t Storage::getErrorCount() const { - return m_errorMessages.size(); + return m_errorLocationCollection.getTokenLocationCount(); } void Storage::onError(const ParseLocation& location, const std::string& message) @@ -64,15 +122,38 @@ void Storage::onError(const ParseLocation& location, const std::string& message) return; } - Id errorId = m_errorMessages.size(); + bool duplicate = false; + std::string filePath = location.filePath; + TokenLocationFile* file = m_errorLocationCollection.findTokenLocationFileByPath(filePath); - TokenLocation* loc = m_errorLocationCollection.addTokenLocation( - errorId, location.filePath, - location.startLineNumber, location.startColumnNumber, - location.endLineNumber, location.endColumnNumber - ); + if (file) + { + file->forEachTokenLocation( + [&](TokenLocation* loc) + { + if (loc->isStartTokenLocation() && + loc->getLineNumber() == location.startLineNumber && + loc->getColumnNumber() == location.startColumnNumber && + m_errorMessages[loc->getTokenId()] == message) + { + duplicate = true; + } + } + ); + } - m_errorMessages.push_back(message); + if (!duplicate) + { + Id errorId = m_errorMessages.size(); + + TokenLocation* loc = m_errorLocationCollection.addTokenLocation( + errorId, filePath, + location.startLineNumber, location.startColumnNumber, + location.endLineNumber, location.endColumnNumber + ); + + m_errorMessages.push_back(message); + } } Id Storage::onTypedefParsed( @@ -1030,6 +1111,20 @@ bool Storage::getSubQuerySearchResults( return true; } +void Storage::removeNodeIfUnreferenced(Node* node) +{ + Id tokenId = node->getId(); + SearchNode* searchNode = m_tokenIndex.getNode(node->getTokenComponentName()->getSearchNode()); + + bool removed = m_graph.removeNodeIfUnreferencedRecursive(node); + + if (removed && searchNode) + { + searchNode->removeTokenId(tokenId); + m_tokenIndex.removeNodeIfUnreferencedRecursive(searchNode); + } +} + void Storage::log(std::string type, std::string str, const ParseLocation& location) const { LOG_INFO_STREAM( diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 9cfbad6c..7314c202 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -23,6 +23,7 @@ public: virtual ~Storage(); void clear(); + void clearFileData(const std::vector& filePaths); void logGraph() const; void logLocations() const; @@ -125,7 +126,6 @@ protected: const SearchIndex& getSearchIndex() const; private: - Node* addNodeHierarchy(Node::NodeType type, std::vector nameHierarchy); Node* addNodeHierarchyWithDistinctSignature(Node::NodeType type, const ParseFunction& function); @@ -141,6 +141,8 @@ private: bool getSubQuerySearchResults( const std::string& query, const std::string& word, SearchResults* results) const; + void removeNodeIfUnreferenced(Node* node); + void log(std::string type, std::string str, const ParseLocation& location) const; StorageGraph m_graph; diff --git a/src/lib/data/graph/Graph.cpp b/src/lib/data/graph/Graph.cpp index 213657d2..50971547 100644 --- a/src/lib/data/graph/Graph.cpp +++ b/src/lib/data/graph/Graph.cpp @@ -114,13 +114,16 @@ void Graph::removeNode(Node* node) return; } - node->forEachEdgeOfType(Edge::EDGE_MEMBER, [this, node](Edge* e) - { - if (node == e->getFrom()) + node->forEachEdgeOfType( + Edge::EDGE_MEMBER, + [this, node](Edge* e) { - this->removeNode(e->getTo()); + if (node == e->getFrom()) + { + this->removeNode(e->getTo()); + } } - }); + ); node->forEachEdge( [this](Edge* e) @@ -131,7 +134,7 @@ void Graph::removeNode(Node* node) if (node->getEdges().size()) { - LOG_ERROR("Node has still edges."); + LOG_ERROR("Node still has edges."); } m_nodes.erase(it); @@ -154,6 +157,25 @@ void Graph::removeEdge(Edge* edge) m_edges.erase(it); } +bool Graph::removeNodeIfUnreferencedRecursive(Node* node) +{ + if (!node->hasReferences()) + { + Node* parent = node->getParentNode(); + + removeNode(node); + + if (parent) + { + removeNodeIfUnreferencedRecursive(parent); + } + + return true; + } + + return false; +} + Node* Graph::findNode(std::function func) const { std::map>::const_iterator it = find_if(m_nodes.begin(), m_nodes.end(), diff --git a/src/lib/data/graph/Graph.h b/src/lib/data/graph/Graph.h index d9ec378a..62581f8a 100644 --- a/src/lib/data/graph/Graph.h +++ b/src/lib/data/graph/Graph.h @@ -40,6 +40,7 @@ public: void removeNode(Node* node); void removeEdge(Edge* edge); + bool removeNodeIfUnreferencedRecursive(Node* node); Node* findNode(std::function func) const; Edge* findEdge(std::function func) const; diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index cd14e6cc..d8c106c1 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -203,6 +203,37 @@ void Node::forEachChildNode(std::function func) const ); } +bool Node::hasReferences() const +{ + if (getLocationIds().size() > 0) + { + return true; + } + + bool hasChildrenWithReferences = false; + size_t childNodeCount = 0; + + forEachEdgeOfType( + Edge::EDGE_MEMBER, + [&](Edge* edge) + { + childNodeCount++; + + if (!hasChildrenWithReferences && edge->getTo() != this && edge->getTo()->hasReferences()) + { + hasChildrenWithReferences = true; + } + } + ); + + if (hasChildrenWithReferences || getEdges().size() > childNodeCount) + { + return true; + } + + return false; +} + bool Node::isNode() const { return true; diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index fb868061..7a5020c4 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -68,6 +68,8 @@ public: void forEachEdgeOfType(Edge::EdgeType type, std::function func) const; void forEachChildNode(std::function func) const; + bool hasReferences() const; + // Token implementation. virtual bool isNode() const; virtual bool isEdge() const; diff --git a/src/lib/data/location/TokenLocationCollection.cpp b/src/lib/data/location/TokenLocationCollection.cpp index df2de11f..6fc12f20 100644 --- a/src/lib/data/location/TokenLocationCollection.cpp +++ b/src/lib/data/location/TokenLocationCollection.cpp @@ -1,9 +1,13 @@ #include "data/location/TokenLocationCollection.h" +#include + +#include "utility/FileSystem.h" +#include "utility/logging/logging.h" + #include "data/location/TokenLocation.h" #include "data/location/TokenLocationFile.h" #include "data/location/TokenLocationLine.h" -#include "utility/logging/logging.h" TokenLocationCollection::TokenLocationCollection() { @@ -85,7 +89,13 @@ TokenLocation* TokenLocationCollection::findTokenLocationById(Id id) const TokenLocationFile* TokenLocationCollection::findTokenLocationFileByPath(const std::string& filePath) const { - std::map >::const_iterator it = m_files.find(filePath); + std::map>::const_iterator it = + find_if(m_files.begin(), m_files.end(), + [&](const std::pair>& p) + { + return FileSystem::equivalent(p.first, filePath); + } + ); if (it != m_files.end()) { @@ -119,6 +129,18 @@ void TokenLocationCollection::forEachTokenLocation(std::functionforEachTokenLocation( + [&](TokenLocation* location) + { + m_locations.erase(location->getId()); + } + ); + + m_files.erase(file->getFilePath()); +} + TokenLocation* TokenLocationCollection::addTokenLocationAsPlainCopy(const TokenLocation* location) { const std::string& filePath = location->getTokenLocationLine()->getTokenLocationFile()->getFilePath(); diff --git a/src/lib/data/location/TokenLocationCollection.h b/src/lib/data/location/TokenLocationCollection.h index a9daeedd..c8f8081c 100644 --- a/src/lib/data/location/TokenLocationCollection.h +++ b/src/lib/data/location/TokenLocationCollection.h @@ -41,6 +41,8 @@ public: void forEachTokenLocationLine(std::function func) const; void forEachTokenLocation(std::function func) const; + void removeTokenLocationFile(TokenLocationFile* file); + TokenLocation* addTokenLocationAsPlainCopy(const TokenLocation* location); void clear(); diff --git a/src/lib/data/search/SearchIndex.cpp b/src/lib/data/search/SearchIndex.cpp index 5fa7f4b4..8d79d2b7 100644 --- a/src/lib/data/search/SearchIndex.cpp +++ b/src/lib/data/search/SearchIndex.cpp @@ -3,6 +3,8 @@ #include #include +#include "utility/logging/logging.h" + #include "data/search/SearchMatch.h" std::vector SearchIndex::getMatches( @@ -34,6 +36,11 @@ void SearchIndex::clear() m_root.m_nodes.clear(); } +size_t SearchIndex::getNodeCount() const +{ + return m_root.getNodeCount() - 1; +} + Id SearchIndex::getWordId(const std::string& word) { return m_dictionary.getWordId(word); @@ -71,6 +78,50 @@ SearchNode* SearchIndex::getNode(const std::string& fullName) const return nullptr; } +SearchNode* SearchIndex::getNode(const SearchNode* searchNode) const +{ + std::deque nameIds = searchNode->getNameIdsRecursive(); + + if (nameIds.size()) + { + return m_root.getNodeRecursive(&nameIds).get(); + } + + return nullptr; +} + +void SearchIndex::removeNode(SearchNode* searchNode) +{ + SearchNode* parent = searchNode->getParent(); + + if (!parent) + { + LOG_ERROR_STREAM(<< "SearchNode to be removed has no parent: " << searchNode->getFullName()); + return; + } + + parent->removeSearchNode(searchNode); +} + +bool SearchIndex::removeNodeIfUnreferencedRecursive(SearchNode* searchNode) +{ + if (!searchNode->hasTokenIdsRecursive()) + { + SearchNode* parent = searchNode->getParent(); + + removeNode(searchNode); + + if (parent && parent != &m_root) + { + removeNodeIfUnreferencedRecursive(parent); + } + + return true; + } + + return false; +} + SearchResults SearchIndex::runFuzzySearch(const std::string& query) const { return m_root.runFuzzySearch(query); diff --git a/src/lib/data/search/SearchIndex.h b/src/lib/data/search/SearchIndex.h index 2e41300a..79526d9e 100644 --- a/src/lib/data/search/SearchIndex.h +++ b/src/lib/data/search/SearchIndex.h @@ -20,11 +20,17 @@ public: void clear(); + size_t getNodeCount() const; + Id getWordId(const std::string& word); const std::string& getWord(Id wordId) const; SearchNode* addNode(std::vector nameHierarchy); SearchNode* getNode(const std::string& fullName) const; + SearchNode* getNode(const SearchNode* searchNode) const; + + void removeNode(SearchNode* searchNode); + bool removeNodeIfUnreferencedRecursive(SearchNode* searchNode); SearchResults runFuzzySearch(const std::string& query) const; std::vector runFuzzySearchAndGetMatches(const std::string& query) const; diff --git a/src/lib/data/search/SearchNode.cpp b/src/lib/data/search/SearchNode.cpp index b5ccf14a..c5802f90 100644 --- a/src/lib/data/search/SearchNode.cpp +++ b/src/lib/data/search/SearchNode.cpp @@ -19,6 +19,18 @@ SearchNode::~SearchNode() { } +size_t SearchNode::getNodeCount() const +{ + size_t count = 1; + + for (std::shared_ptr n: m_nodes) + { + count += n->getNodeCount(); + } + + return count; +} + const std::string& SearchNode::getName() const { return m_name; @@ -28,7 +40,7 @@ std::vector SearchNode::getNameHierarchy() const { std::vector nameHierarchy; const SearchNode* parent = getParent(); - if (parent) + if (parent && parent->m_nameId) { nameHierarchy = parent->getNameHierarchy(); } @@ -53,6 +65,22 @@ Id SearchNode::getNameId() const return m_nameId; } +std::deque SearchNode::getNameIdsRecursive() const +{ + std::deque ids; + + ids.push_front(m_nameId); + + SearchNode* parent = m_parent; + while (parent && parent->m_nameId) + { + ids.push_front(parent->getNameId()); + parent = parent->getParent(); + } + + return ids; +} + Id SearchNode::getFirstTokenId() const { if (m_tokenIds.size()) @@ -68,14 +96,37 @@ const std::set& SearchNode::getTokenIds() const return m_tokenIds; } +bool SearchNode::hasTokenIdsRecursive() const +{ + if (m_tokenIds.size()) + { + return true; + } + + for (std::shared_ptr n: m_nodes) + { + if (n->hasTokenIdsRecursive()) + { + return true; + } + } + + return false; +} + void SearchNode::addTokenId(Id tokenId) { m_tokenIds.insert(tokenId); } +void SearchNode::removeTokenId(Id tokenId) +{ + m_tokenIds.erase(tokenId); +} + SearchNode* SearchNode::getParent() const { - if (m_parent && m_parent->m_nameId) + if (m_parent) { return m_parent; } @@ -183,6 +234,18 @@ std::shared_ptr SearchNode::getNodeRecursive(std::deque* nameIds return nullptr; } +void SearchNode::removeSearchNode(SearchNode* node) +{ + for (std::set>::iterator it = m_nodes.begin(); it != m_nodes.end(); it++) + { + if ((*it)->m_nameId == node->m_nameId) + { + m_nodes.erase(it); + return; + } + } +} + SearchMatch SearchNode::fuzzyMatchData(const std::string& query, const SearchNode* parent) const { SearchMatch data; diff --git a/src/lib/data/search/SearchNode.h b/src/lib/data/search/SearchNode.h index 1dad5d89..44b85df7 100644 --- a/src/lib/data/search/SearchNode.h +++ b/src/lib/data/search/SearchNode.h @@ -22,15 +22,21 @@ public: SearchNode(SearchNode* parent, const std::string& name, Id nameId); ~SearchNode(); + size_t getNodeCount() const; + const std::string& getName() const; std::vector getNameHierarchy() const; std::string getFullName() const; Id getNameId() const; + std::deque getNameIdsRecursive() const; Id getFirstTokenId() const; const std::set& getTokenIds() const; + bool hasTokenIdsRecursive() const; + void addTokenId(Id tokenId); + void removeTokenId(Id tokenId); SearchNode* getParent() const; std::deque getParentsWithoutTokenId(); @@ -46,11 +52,12 @@ private: typedef std::multimap FuzzyMap; typedef FuzzyMap::const_iterator FuzzyMapIterator; - // Accessed by SearchIndex std::shared_ptr addNodeRecursive(std::deque* nameIds, const Dictionary& dictionary); std::shared_ptr getNodeRecursive(std::deque* nameIds) const; + void removeSearchNode(SearchNode* node); + SearchMatch fuzzyMatchData(const std::string& query, const SearchNode* parent) const; friend class SearchIndex; diff --git a/src/lib/utility/FileSystem.cpp b/src/lib/utility/FileSystem.cpp index 9aee8a21..a9aebc7a 100644 --- a/src/lib/utility/FileSystem.cpp +++ b/src/lib/utility/FileSystem.cpp @@ -1,12 +1,12 @@ #include "utility/FileSystem.h" +#include "boost/date_time.hpp" #include "boost/filesystem.hpp" -#include "utility/logging/logging.h" - -std::vector FileSystem::getSourceFilesFromDirectory( +std::vector FileSystem::getFileNamesFromDirectory( const std::string& path, const std::vector& extensions -){ +) +{ std::vector files; if (boost::filesystem::is_directory(path)) @@ -25,25 +25,37 @@ std::vector FileSystem::getSourceFilesFromDirectory( return files; } -std::vector FileSystem::getFileNamesFromDirectory( - const std::string& path, const std::vector& extensions -) -{ - return getSourceFilesFromDirectory(path, extensions); -} +std::vector FileSystem::getFileNamesFromDirectoryUpdatedAfter( + const std::string& path, const std::vector& extensions, const std::string& timeString +){ + std::vector files; -bool FileSystem::isValidExtension(const std::string& filepath, const std::vector& extensions) -{ - boost::filesystem::path path(filepath); + const boost::posix_time::ptime time = boost::posix_time::from_iso_string(timeString); - for (std::string extension : extensions) + if (boost::filesystem::is_directory(path)) { - if (path.extension() == extension) + boost::filesystem::recursive_directory_iterator it(path); + boost::filesystem::recursive_directory_iterator endit; + while (it != endit) { - return true; + if (boost::filesystem::is_regular_file(*it) && isValidExtension(it->path().string(), extensions)) + { + std::time_t t = boost::filesystem::last_write_time(*it); + boost::posix_time::ptime lastWriteTime = boost::posix_time::from_time_t(t); + if (lastWriteTime >= time) + { + files.push_back(it->path().generic_string()); + } + } + ++it; } } - return false; + return files; +} + +std::string FileSystem::getTimeStringNow() +{ + return boost::posix_time::to_iso_string(boost::posix_time::second_clock::universal_time()); } bool FileSystem::exists(const std::string& path) @@ -64,4 +76,33 @@ std::string FileSystem::extension(const std::string& path) std::string FileSystem::filePathWithoutExtension(const std::string& path) { return boost::filesystem::path(path).replace_extension().generic_string(); -} \ No newline at end of file +} + +std::string FileSystem::absoluteFilePath(const std::string& path) +{ + return boost::filesystem::absolute(boost::filesystem::path(path)).generic_string(); +} + +bool FileSystem::equivalent(const std::string& pathA, const std::string& pathB) +{ + if (exists(pathA) && exists(pathB)) + { + return boost::filesystem::equivalent(boost::filesystem::path(pathA), boost::filesystem::path(pathB)); + } + + return boost::filesystem::path(pathA).compare(boost::filesystem::path(pathB)) == 0; +} + +bool FileSystem::isValidExtension(const std::string& filepath, const std::vector& extensions) +{ + boost::filesystem::path path(filepath); + + for (std::string extension : extensions) + { + if (path.extension() == extension) + { + return true; + } + } + return false; +} diff --git a/src/lib/utility/FileSystem.h b/src/lib/utility/FileSystem.h index d0d20d11..9d1cf468 100644 --- a/src/lib/utility/FileSystem.h +++ b/src/lib/utility/FileSystem.h @@ -7,18 +7,20 @@ class FileSystem { public: - static std::vector getSourceFilesFromDirectory( // TODO: Replace this with getFileNamesFromDirectory. - const std::string& path, const std::vector& extensions - ); - static std::vector getFileNamesFromDirectory( - const std::string& path, const std::vector& extensions - ); + const std::string& path, const std::vector& extensions); + static std::vector getFileNamesFromDirectoryUpdatedAfter( + const std::string& path, const std::vector& extensions, const std::string& timeString); + + static std::string getTimeStringNow(); static bool exists(const std::string& path); static std::string fileName(const std::string& path); static std::string extension(const std::string& path); static std::string filePathWithoutExtension(const std::string& path); + static std::string absoluteFilePath(const std::string& path); + + static bool equivalent(const std::string& pathA, const std::string& pathB); private: static bool isValidExtension(const std::string& filepath, const std::vector& extensions); diff --git a/src/lib/utility/messaging/type/MessageAutoRefreshChanged.h b/src/lib/utility/messaging/type/MessageAutoRefreshChanged.h new file mode 100644 index 00000000..004d728e --- /dev/null +++ b/src/lib/utility/messaging/type/MessageAutoRefreshChanged.h @@ -0,0 +1,22 @@ +#ifndef MESSAGE_AUTO_REFRESH_CHANGED_H +#define MESSAGE_AUTO_REFRESH_CHANGED_H + +#include "utility/messaging/Message.h" + +class MessageAutoRefreshChanged: public Message +{ +public: + MessageAutoRefreshChanged(bool enabled) + : enabled(enabled) + { + } + + static const std::string getStaticType() + { + return "MessageAutoRefreshChanged"; + } + + bool enabled; +}; + +#endif // MESSAGE_AUTO_REFRESH_CHANGED_H diff --git a/src/lib/utility/messaging/type/MessageFinishedParsing.h b/src/lib/utility/messaging/type/MessageFinishedParsing.h index 0eca55c3..a8f80c6d 100644 --- a/src/lib/utility/messaging/type/MessageFinishedParsing.h +++ b/src/lib/utility/messaging/type/MessageFinishedParsing.h @@ -6,8 +6,9 @@ class MessageFinishedParsing: public Message { public: - MessageFinishedParsing(float parseTime, size_t errorCount) - : parseTime(parseTime) + MessageFinishedParsing(size_t fileCount, float parseTime, size_t errorCount) + : fileCount(fileCount) + , parseTime(parseTime) , errorCount(errorCount) { } @@ -17,6 +18,7 @@ public: return "MessageFinishedParsing"; } + size_t fileCount; float parseTime; size_t errorCount; }; diff --git a/src/lib/utility/messaging/type/MessageRefresh.h b/src/lib/utility/messaging/type/MessageRefresh.h index 020bda4b..4946d8d5 100644 --- a/src/lib/utility/messaging/type/MessageRefresh.h +++ b/src/lib/utility/messaging/type/MessageRefresh.h @@ -2,7 +2,6 @@ #define MESSAGE_REFRESH_H #include "utility/messaging/Message.h" -#include "utility/types.h" class MessageRefresh: public Message { diff --git a/src/lib/utility/messaging/type/MessageWindowFocus.h b/src/lib/utility/messaging/type/MessageWindowFocus.h new file mode 100644 index 00000000..2f43c6c2 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageWindowFocus.h @@ -0,0 +1,19 @@ +#ifndef MESSAGE_WINDOW_FOCUS_H +#define MESSAGE_WINDOW_FOCUS_H + +#include "utility/messaging/Message.h" + +class MessageWindowFocus: public Message +{ +public: + MessageWindowFocus() + { + } + + static const std::string getStaticType() + { + return "MessageWindowFocus"; + } +}; + +#endif // MESSAGE_WINDOW_FOCUS_H diff --git a/src/test/FileSystemTestSuite.h b/src/test/FileSystemTestSuite.h index 05c5fb6d..4fe22477 100644 --- a/src/test/FileSystemTestSuite.h +++ b/src/test/FileSystemTestSuite.h @@ -1,6 +1,7 @@ #include "cxxtest/TestSuite.h" #include +#include #include #include @@ -15,7 +16,7 @@ public: extensions.push_back(".cpp"); std::vector cppFiles = - FileSystem::getSourceFilesFromDirectory("data/FileSystemTestSuite", extensions); + FileSystem::getFileNamesFromDirectory("data/FileSystemTestSuite", extensions); TS_ASSERT_EQUALS(cppFiles.size(), 2); TS_ASSERT(isInVector(cppFiles, "data/FileSystemTestSuite/main.cpp")); @@ -28,7 +29,7 @@ public: extensions.push_back(".h"); std::vector headerFiles = - FileSystem::getSourceFilesFromDirectory("data/FileSystemTestSuite", extensions); + FileSystem::getFileNamesFromDirectory("data/FileSystemTestSuite", extensions); TS_ASSERT_EQUALS(headerFiles.size(), 2); TS_ASSERT(isInVector(headerFiles, "data/FileSystemTestSuite/tictactoe.h")); @@ -43,11 +44,33 @@ public: extensions.push_back(".cpp"); std::vector sourceFiles = - FileSystem::getSourceFilesFromDirectory("data/FileSystemTestSuite", extensions); + FileSystem::getFileNamesFromDirectory("data/FileSystemTestSuite", extensions); TS_ASSERT_EQUALS(sourceFiles.size(), 5); } + void test_find_updated_source_files() + { + std::string timeString = FileSystem::getTimeStringNow(); + + std::fstream fileStream; + fileStream.open("./data/FileSystemTestSuite/update.c"); + fileStream << "update"; + fileStream.close(); + + std::vector extensions; + extensions.push_back(".h"); + extensions.push_back(".c"); + extensions.push_back(".hpp"); + extensions.push_back(".cpp"); + + std::vector sourceFiles = + FileSystem::getFileNamesFromDirectoryUpdatedAfter("data/FileSystemTestSuite", extensions, timeString); + + TS_ASSERT_EQUALS(sourceFiles.size(), 1); + TS_ASSERT_EQUALS(sourceFiles[0], "data/FileSystemTestSuite/update.c"); + } + void test_filesystem_finds_existing_files() { TS_ASSERT(FileSystem::exists("data/FileSystemTestSuite")); diff --git a/src/test/GraphTestSuite.h b/src/test/GraphTestSuite.h index f4e79a72..9e964fe2 100644 --- a/src/test/GraphTestSuite.h +++ b/src/test/GraphTestSuite.h @@ -245,6 +245,21 @@ public: TS_ASSERT_EQUALS(children[1], &c); } + void test_node_has_references() + { + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); + Node c(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("C", "::"))); + Node d(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("D", "::"))); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + Edge e3(Edge::EDGE_USAGE, &c, &d); + + TS_ASSERT(a.hasReferences()); + TS_ASSERT(!b.hasReferences()); + TS_ASSERT(c.hasReferences()); + } + void test_graph_saves_nodes() { Graph graph; @@ -294,6 +309,58 @@ public: TS_ASSERT_EQUALS(Edge::EDGE_CALL, graph.getEdgeById(e.getId())->getType()); } + void test_graph_removes_nodes() + { + Graph graph; + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); + + graph.addNode(&a); + graph.addNode(&b); + + TS_ASSERT_EQUALS(2, graph.getNodeCount()); + TS_ASSERT_EQUALS(0, graph.getEdgeCount()); + + graph.removeNode(graph.getNodeById(a.getId())); + + TS_ASSERT_EQUALS(1, graph.getNodeCount()); + } + + void test_graph_removes_unreferenced_nodes() + { + Graph graph; + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); + Node c(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("C", "::"))); + Node d(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("D", "::"))); + Node e(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("E", "::"))); + + Edge e1(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + Edge e3(Edge::EDGE_USAGE, &c, &d); + Edge e4(Edge::EDGE_MEMBER, &b, &e); + + graph.addNode(&a); + graph.addNode(&b); + graph.addNode(&c); + graph.addNode(&d); + graph.addNode(&e); + + graph.addEdge(&e1); + graph.addEdge(&e2); + graph.addEdge(&e3); + graph.addEdge(&e4); + + TS_ASSERT_EQUALS(5, graph.getNodeCount()); + TS_ASSERT_EQUALS(4, graph.getEdgeCount()); + + TS_ASSERT(!graph.removeNodeIfUnreferencedRecursive(graph.getNodeById(a.getId()))); + TS_ASSERT(graph.removeNodeIfUnreferencedRecursive(graph.getNodeById(b.getId()))); + + TS_ASSERT_EQUALS(3, graph.getNodeCount()); + TS_ASSERT_EQUALS(2, graph.getEdgeCount()); + } + private: class TestToken: public Token { diff --git a/src/test/SearchIndexTestSuite.h b/src/test/SearchIndexTestSuite.h index d4582c50..a7da8400 100644 --- a/src/test/SearchIndexTestSuite.h +++ b/src/test/SearchIndexTestSuite.h @@ -17,7 +17,8 @@ public: TS_ASSERT(node->getNameId()); TS_ASSERT(!node->getFirstTokenId()); - TS_ASSERT(!node->getParent()); + TS_ASSERT(node->getParent()); + TS_ASSERT(!node->getParent()->getNameId()); } void test_get_node() @@ -32,7 +33,8 @@ public: TS_ASSERT(node->getNameId()); TS_ASSERT(!node->getFirstTokenId()); - TS_ASSERT(!node->getParent()); + TS_ASSERT(node->getParent()); + TS_ASSERT(!node->getParent()->getNameId()); node = index.getNode("math"); TS_ASSERT(!node); @@ -72,6 +74,55 @@ public: TS_ASSERT_EQUALS(node1->getParent(), node2->getParent()); } + void test_remove_nodes() + { + SearchIndex index; + index.addNode(utility::splitToVector("util::math::pow", "::")); + index.addNode(utility::splitToVector("util::math::floor", "::")); + + index.removeNode(index.getNode("util::math::pow")); + + TS_ASSERT(!index.getNode("util::math::pow")); + TS_ASSERT(index.getNode("util::math::floor")); + TS_ASSERT(index.getNode("util::math")); + + index.removeNode(index.getNode("util::math")); + + TS_ASSERT(!index.getNode("util::math::floor")); + TS_ASSERT(!index.getNode("util::math")); + TS_ASSERT(index.getNode("util")); + } + + void test_remove_unreferenced_nodes() + { + SearchIndex index; + SearchNode* node1 = index.addNode(utility::splitToVector("util::math::pow", "::")); + SearchNode* node2 = index.addNode(utility::splitToVector("util::math::floor", "::")); + + node1->addTokenId(1); + node2->addTokenId(2); + + TS_ASSERT(index.getNode("util")->hasTokenIdsRecursive()); + + TS_ASSERT(!index.removeNodeIfUnreferencedRecursive(index.getNode("util"))); + TS_ASSERT(!index.removeNodeIfUnreferencedRecursive(index.getNode("util::math"))); + TS_ASSERT(!index.removeNodeIfUnreferencedRecursive(index.getNode("util::math::pow"))); + + node1->removeTokenId(1); + + TS_ASSERT(index.removeNodeIfUnreferencedRecursive(index.getNode("util::math::pow"))); + TS_ASSERT(!index.getNode("util::math::pow")); + TS_ASSERT(index.getNode("util::math")); + TS_ASSERT(index.getNode("util")); + + node2->removeTokenId(2); + + TS_ASSERT(index.removeNodeIfUnreferencedRecursive(index.getNode("util::math"))); + + TS_ASSERT(!index.getNode("util::math")); + TS_ASSERT(!index.getNode("util")); + } + void test_clear() { SearchIndex index; @@ -83,6 +134,7 @@ public: index.clear(); TS_ASSERT(!index.getNode("math")); + TS_ASSERT(!index.getNode("string")); } void test_fuzzy_matching() diff --git a/src/test/StorageTestSuite.h b/src/test/StorageTestSuite.h index 09c79d3c..258bc4d7 100644 --- a/src/test/StorageTestSuite.h +++ b/src/test/StorageTestSuite.h @@ -15,6 +15,11 @@ class StorageTestSuite: public CxxTest::TestSuite { public: + void setUp() + { + m_filePath = "file.cpp"; + } + void test_storage_saves_typedef() { TestStorage storage; @@ -536,6 +541,117 @@ public: TS_ASSERT(isValidLocation(locations[0], 0)); } + void test_storage_clears_single_file_data_of_single_file_storage() + { + TestStorage storage; + storage.onFunctionParsed( + validLocation(), ParseFunction(typeUsage("bool"), utility::splitToVector("isTrue", "::"), + parameters("char")), validLocation() + ); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 3); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 2); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3); + + storage.clearFileData(std::vector(1, m_filePath)); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 0); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 0); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 0); + } + + void test_storage_clears_unreferenced_single_file_data_of_multi_file_storage() + { + m_filePath = "file.h"; + + TestStorage storage; + + ParseFunction isTrue = ParseFunction(typeUsage("bool"), utility::splitToVector("isTrue", "::"), parameters("char")); + storage.onFunctionParsed(validLocation(), isTrue, validLocation()); + + m_filePath = "file.cpp"; + + ParseFunction main = ParseFunction(typeUsage("int"), utility::splitToVector("main", "::"), parameters("void")); + storage.onFunctionParsed(validLocation(), main, validLocation()); + + storage.onCallParsed(validLocation(), main, isTrue); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 6); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 5); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 6); + + storage.clearFileData(std::vector(1, "file.cpp")); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 3); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 2); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3); + } + + void test_storage_clears_referenced_single_file_data_of_multi_file_storage() + { + m_filePath = "file.h"; + + TestStorage storage; + + ParseFunction isTrue = ParseFunction(typeUsage("bool"), utility::splitToVector("isTrue", "::"), parameters("void")); + storage.onFunctionParsed(validLocation(), isTrue, validLocation()); + + m_filePath = "file.cpp"; + + ParseFunction main = ParseFunction(typeUsage("int"), utility::splitToVector("main", "::"), parameters("void")); + storage.onFunctionParsed(validLocation(), main, validLocation()); + + storage.onCallParsed(validLocation(), main, isTrue); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 5); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 5); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5); + + storage.clearFileData(std::vector(1, "file.h")); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 4); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 3); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 5); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 4); + } + + void test_storage_clears_multi_file_data_of_multi_file_storage() + { + m_filePath = "file.h"; + + TestStorage storage; + + ParseFunction isTrue = ParseFunction(typeUsage("bool"), utility::splitToVector("isTrue", "::"), parameters("void")); + storage.onFunctionParsed(validLocation(), isTrue, validLocation()); + + m_filePath = "file.cpp"; + + ParseFunction main = ParseFunction(typeUsage("int"), utility::splitToVector("main", "::"), parameters("void")); + storage.onFunctionParsed(validLocation(), main, validLocation()); + + storage.onCallParsed(validLocation(), main, isTrue); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 5); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 5); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5); + + std::vector filePaths; + filePaths.push_back("file.cpp"); + filePaths.push_back("file.h"); + storage.clearFileData(filePaths); + + TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 0); + TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 0); + TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0); + TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 0); + } + private: class TestStorage : public Storage @@ -568,17 +684,32 @@ private: { return getSearchIndex().getWord(wordId); } + + const Graph& graph() const + { + return getGraph(); + } + + const TokenLocationCollection& tokenLocationCollection() const + { + return getTokenLocationCollection(); + } + + const SearchIndex& searchIndex() const + { + return getSearchIndex(); + } }; ParseLocation validLocation(Id locationId = 0) const { - return ParseLocation("file.cpp", 1, locationId, 1, locationId); + return ParseLocation(m_filePath, 1, locationId, 1, locationId); } bool isValidLocation(TokenLocation* location, Id locationId) const { return - location->getFilePath() == "file.cpp" && + location->getFilePath() == m_filePath && location->getLineNumber() == 1 && location->getColumnNumber() == locationId; } @@ -594,4 +725,6 @@ private: params.push_back(typeUsage(param)); return params; } + + std::string m_filePath; };