From 01864b4d0c62e06c8a30b3935bd4c71528e68fd4 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Mon, 31 Jul 2017 12:45:22 +0200 Subject: [PATCH] ui: Added custom tooltipping to code and graph (issue #195) * Tooltips show node type with access specifier, reference count and fully qualified name * Fields and global variables include the type name * Methods and functinos show whole signature. Gets broken into multiple lines if too long. Included changes: * Upgraded to C++14 * fixed clang warnings * Pass location of .srctrlprj file to build.sh script to load on launch * Split off QtCodeField for showing highlighted and annotated code fom QtCodeArea * removed TokenComponentSignature * added TaskDecoratorDelay bug id = 195 --- CMakeLists.txt | 2 +- bin/app/data/gui/code_view/code_view.css | 2 - bin/app/data/gui/tooltip_view/tooltip.css | 26 + script/build.sh | 10 +- src/lib/CMakeLists.txt | 19 +- src/lib/component/ComponentFactory.cpp | 10 + src/lib/component/ComponentFactory.h | 1 + src/lib/component/ComponentManager.cpp | 3 + .../controller/IDECommunicationController.cpp | 5 +- .../controller/TooltipController.cpp | 141 ++++ .../component/controller/TooltipController.h | 67 ++ src/lib/component/view/CodeView.cpp | 4 +- src/lib/component/view/CodeView.h | 2 + src/lib/component/view/GraphView.cpp | 4 +- src/lib/component/view/GraphView.h | 2 + src/lib/component/view/TooltipView.cpp | 16 + src/lib/component/view/TooltipView.h | 27 + src/lib/component/view/ViewFactory.h | 2 + src/lib/component/view/ViewLayout.cpp | 5 + src/lib/component/view/ViewLayout.h | 4 + src/lib/data/access/StorageAccess.h | 25 +- src/lib/data/access/StorageAccessProxy.cpp | 12 +- src/lib/data/access/StorageAccessProxy.h | 9 +- src/lib/data/graph/Node.cpp | 30 +- src/lib/data/graph/Node.h | 1 + .../TokenComponentSignature.cpp | 20 - .../token_component/TokenComponentSignature.h | 23 - src/lib/data/name/NameElement.cpp | 10 + src/lib/data/name/NameElement.h | 3 + src/lib/data/name/NameHierarchy.cpp | 10 + src/lib/data/name/NameHierarchy.h | 2 + src/lib/data/parser/AccessKind.cpp | 22 + src/lib/data/parser/AccessKind.h | 3 + src/lib/data/parser/TaskParseWrapper.cpp | 13 - src/lib/data/parser/TaskParseWrapper.h | 4 - src/lib/data/storage/PersistentStorage.cpp | 555 ++++++++++------ src/lib/data/storage/PersistentStorage.h | 31 +- src/lib/data/storage/sqlite/SqliteStorage.cpp | 3 +- src/lib/data/tooltip/TooltipInfo.h | 34 + src/lib/data/tooltip/TooltipOrigin.h | 10 + .../utility/messaging/type/MessageFocusIn.h | 6 +- .../messaging/type/MessageTooltipHide.h | 21 + .../messaging/type/MessageTooltipShow.h | 29 + .../messaging/type/MessageWindowFocus.h | 8 +- src/lib/utility/scheduling/Task.h | 1 + src/lib/utility/scheduling/TaskDecorator.cpp | 15 + src/lib/utility/scheduling/TaskDecorator.h | 9 +- .../utility/scheduling/TaskDecoratorDelay.cpp | 49 ++ .../utility/scheduling/TaskDecoratorDelay.h | 29 + .../scheduling/TaskDecoratorRepeat.cpp | 13 - .../utility/scheduling/TaskDecoratorRepeat.h | 4 - .../utility/scheduling/TaskGroupParallel.cpp | 2 +- .../utility/scheduling/TaskGroupSelector.cpp | 4 + .../utility/scheduling/TaskGroupSequence.cpp | 4 + src/lib/utility/scheduling/TaskScheduler.cpp | 9 +- src/lib/utility/utilityString.cpp | 106 +++ src/lib/utility/utilityString.h | 3 + .../data/indexer/IndexerCommandCxx.cpp | 2 +- .../CxxTemplateArgumentNameResolver.cpp | 1 - src/lib_gui/CMakeLists.txt | 6 + src/lib_gui/qt/element/QtCodeArea.cpp | 548 +--------------- src/lib_gui/qt/element/QtCodeArea.h | 90 +-- src/lib_gui/qt/element/QtCodeField.cpp | 613 ++++++++++++++++++ src/lib_gui/qt/element/QtCodeField.h | 122 ++++ src/lib_gui/qt/element/QtCodeNavigator.cpp | 15 +- src/lib_gui/qt/element/QtTooltip.cpp | 179 +++++ src/lib_gui/qt/element/QtTooltip.h | 43 ++ src/lib_gui/qt/view/QtMainView.cpp | 5 + src/lib_gui/qt/view/QtMainView.h | 2 + src/lib_gui/qt/view/QtTooltipView.cpp | 77 +++ src/lib_gui/qt/view/QtTooltipView.h | 36 + src/lib_gui/qt/view/QtViewFactory.cpp | 6 + src/lib_gui/qt/view/QtViewFactory.h | 1 + .../qt/view/graphElements/QtGraphEdge.cpp | 57 +- .../qt/view/graphElements/QtGraphEdge.h | 3 + .../qt/view/graphElements/QtGraphNodeData.cpp | 36 +- src/lib_gui/qt/window/QtMainWindow.cpp | 19 +- src/lib_gui/qt/window/QtMainWindow.h | 2 + .../QtProjectWizzardContentPaths.h | 2 +- 79 files changed, 2340 insertions(+), 1009 deletions(-) create mode 100644 bin/app/data/gui/tooltip_view/tooltip.css create mode 100644 src/lib/component/controller/TooltipController.cpp create mode 100644 src/lib/component/controller/TooltipController.h create mode 100644 src/lib/component/view/TooltipView.cpp create mode 100644 src/lib/component/view/TooltipView.h delete mode 100644 src/lib/data/graph/token_component/TokenComponentSignature.cpp delete mode 100644 src/lib/data/graph/token_component/TokenComponentSignature.h create mode 100644 src/lib/data/tooltip/TooltipInfo.h create mode 100644 src/lib/data/tooltip/TooltipOrigin.h create mode 100644 src/lib/utility/messaging/type/MessageTooltipHide.h create mode 100644 src/lib/utility/messaging/type/MessageTooltipShow.h create mode 100644 src/lib/utility/scheduling/TaskDecoratorDelay.cpp create mode 100644 src/lib/utility/scheduling/TaskDecoratorDelay.h create mode 100644 src/lib_gui/qt/element/QtCodeField.cpp create mode 100644 src/lib_gui/qt/element/QtCodeField.h create mode 100644 src/lib_gui/qt/element/QtTooltip.cpp create mode 100644 src/lib_gui/qt/element/QtTooltip.h create mode 100644 src/lib_gui/qt/view/QtTooltipView.cpp create mode 100644 src/lib_gui/qt/view/QtTooltipView.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 63b9c171..0c432805 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ if(UNIX AND NOT APPLE) endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_C_STANDARD 99) # Settings --------------------------------------------------------------------- diff --git a/bin/app/data/gui/code_view/code_view.css b/bin/app/data/gui/code_view/code_view.css index 230dc1c4..0acf8cb9 100644 --- a/bin/app/data/gui/code_view/code_view.css +++ b/bin/app/data/gui/code_view/code_view.css @@ -172,8 +172,6 @@ #code_area { background-color: transparent; color: ; - font-family: ""; - font-size: px; selection-color: ; selection-background-color: ; } diff --git a/bin/app/data/gui/tooltip_view/tooltip.css b/bin/app/data/gui/tooltip_view/tooltip.css new file mode 100644 index 00000000..dbf57142 --- /dev/null +++ b/bin/app/data/gui/tooltip_view/tooltip.css @@ -0,0 +1,26 @@ +#tooltip { + background-color: ; + border: 1px solid ; +} + +#tooltip_title { + color: ; + padding: 3px; + font-size: px; + font-weight: bold; +} + +#tooltip_references { + background-color: ; + color: ; + margin: 4px; + padding: 3px 5px; + border-radius: 8px; + font-size: px; +} + +#tooltip_widget { + background-color: ; + padding: 3px; + color: ; +} diff --git a/script/build.sh b/script/build.sh index 2f870e2a..ff818c0f 100755 --- a/script/build.sh +++ b/script/build.sh @@ -12,6 +12,12 @@ fi cd $MY_PATH/.. +# determine if needs to load project +if [ ! -z "$3" ] +then + PROJECT_PATH="-p $3" +fi + # run target if [ "$1" = "release" ] || [ "$1" = "r" ] || [ "$1" = "" ] @@ -26,7 +32,7 @@ then cd build/Release/license_generator && ./Sourcetrail_license_generator else #echo "release app" - cd build/Release/app && ./Sourcetrail + cd build/Release/app && ./Sourcetrail $PROJECT_PATH fi elif [ "$1" = "debug" ] || [ "$1" = "d" ] then @@ -40,7 +46,7 @@ then cd build/Debug/license_generator && ./Sourcetrail_license_generator else #echo "debug app" - cd build/Debug/app && ./Sourcetrail + cd build/Debug/app && ./Sourcetrail $PROJECT_PATH fi else echo "no arguments: first argument 'release' or 'debug', second argument 'test' for tests" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index a35a0291..e9c25ba0 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -41,6 +41,8 @@ add_files( component/controller/StatusBarController.h component/controller/StatusController.cpp component/controller/StatusController.h + component/controller/TooltipController.cpp + component/controller/TooltipController.h component/controller/UndoRedoController.cpp component/controller/UndoRedoController.h @@ -75,6 +77,8 @@ add_files( component/view/StatusView.h component/view/TabbedView.cpp component/view/TabbedView.h + component/view/TooltipView.cpp + component/view/TooltipView.h component/view/UndoRedoView.cpp component/view/UndoRedoView.h component/view/View.cpp @@ -125,8 +129,6 @@ add_files( data/graph/token_component/TokenComponentFilePath.cpp data/graph/token_component/TokenComponentFilePath.h data/graph/token_component/TokenComponentInheritanceChain.h - data/graph/token_component/TokenComponentSignature.cpp - data/graph/token_component/TokenComponentSignature.h data/graph/token_component/TokenComponentStatic.cpp data/graph/token_component/TokenComponentStatic.h @@ -211,13 +213,13 @@ add_files( data/search/SearchIndex.h data/search/SearchMatch.cpp data/search/SearchMatch.h - + data/storage/migration/SqliteStorageMigration.cpp data/storage/migration/SqliteStorageMigration.h data/storage/migration/SqliteStorageMigrationLambda.cpp data/storage/migration/SqliteStorageMigrationLambda.h data/storage/migration/SqliteStorageMigrator.h - + data/storage/sqlite/SqliteBookmarkStorage.cpp data/storage/sqlite/SqliteBookmarkStorage.h data/storage/sqlite/SqliteDatabaseIndex.cpp @@ -226,7 +228,7 @@ add_files( data/storage/sqlite/SqliteIndexStorage.h data/storage/sqlite/SqliteStorage.cpp data/storage/sqlite/SqliteStorage.h - + data/storage/IntermediateStorage.cpp data/storage/IntermediateStorage.h data/storage/PersistentStorage.cpp @@ -240,6 +242,9 @@ add_files( data/storage/StorageTypes.h data/storage/StorageStats.h + data/tooltip/TooltipInfo.h + data/tooltip/TooltipOrigin.h + data/DefinitionKind.cpp data/DefinitionKind.h data/ErrorCountInfo.h @@ -410,6 +415,8 @@ add_files( utility/messaging/type/MessageStatus.h utility/messaging/type/MessageStatusFilterChanged.h utility/messaging/type/MessageSwitchColorScheme.h + utility/messaging/type/MessageTooltipHide.h + utility/messaging/type/MessageTooltipShow.h utility/messaging/type/MessageToUndoRedoPosition.h utility/messaging/type/MessageUndo.h utility/messaging/type/MessageWindowClosed.h @@ -438,6 +445,8 @@ add_files( utility/scheduling/TaskDecorator.h utility/scheduling/TaskDecoratorRepeat.cpp utility/scheduling/TaskDecoratorRepeat.h + utility/scheduling/TaskDecoratorDelay.cpp + utility/scheduling/TaskDecoratorDelay.h utility/scheduling/TaskGroup.cpp utility/scheduling/TaskGroup.h utility/scheduling/TaskGroupParallel.cpp diff --git a/src/lib/component/ComponentFactory.cpp b/src/lib/component/ComponentFactory.cpp index 7f10028c..882ffa67 100644 --- a/src/lib/component/ComponentFactory.cpp +++ b/src/lib/component/ComponentFactory.cpp @@ -11,6 +11,7 @@ #include "component/controller/SearchController.h" #include "component/controller/StatusBarController.h" #include "component/controller/StatusController.h" +#include "component/controller/TooltipController.h" #include "component/controller/UndoRedoController.h" #include "component/view/BookmarkView.h" #include "component/view/CodeView.h" @@ -20,6 +21,7 @@ #include "component/view/SearchView.h" #include "component/view/StatusBarView.h" #include "component/view/StatusView.h" +#include "component/view/TooltipView.h" #include "component/view/UndoRedoView.h" #include "component/view/ViewFactory.h" @@ -56,6 +58,14 @@ std::shared_ptr ComponentFactory::createActivationComponent() return std::make_shared(nullptr, controller); } +std::shared_ptr ComponentFactory::createTooltipComponent(ViewLayout* viewLayout) +{ + std::shared_ptr view = m_viewFactory->createTooltipView(viewLayout); + std::shared_ptr controller = std::make_shared(m_storageAccess); + + return std::make_shared(view, controller); +} + std::shared_ptr ComponentFactory::createBookmarkComponent(ViewLayout* viewLayout) { std::shared_ptr view = m_viewFactory->createBookmarkView(viewLayout); diff --git a/src/lib/component/ComponentFactory.h b/src/lib/component/ComponentFactory.h index a0a49060..433941b7 100644 --- a/src/lib/component/ComponentFactory.h +++ b/src/lib/component/ComponentFactory.h @@ -29,6 +29,7 @@ public: std::shared_ptr createSearchComponent(ViewLayout* viewLayout); std::shared_ptr createStatusBarComponent(ViewLayout* viewLayout); std::shared_ptr createStatusComponent(ViewLayout* viewLayout); + std::shared_ptr createTooltipComponent(ViewLayout* viewLayout); std::shared_ptr createUndoRedoComponent(ViewLayout* viewLayout); private: diff --git a/src/lib/component/ComponentManager.cpp b/src/lib/component/ComponentManager.cpp index 081c5b4d..acb7fcaa 100644 --- a/src/lib/component/ComponentManager.cpp +++ b/src/lib/component/ComponentManager.cpp @@ -51,6 +51,9 @@ void ComponentManager::setup(ViewLayout* viewLayout) std::shared_ptr activationComponent = m_componentFactory->createActivationComponent(); m_components.push_back(activationComponent); + std::shared_ptr tooltipComponent = m_componentFactory->createTooltipComponent(viewLayout); + m_components.push_back(tooltipComponent); + m_dialogView = m_componentFactory->getViewFactory()->createDialogView(viewLayout, m_componentFactory->getStorageAccess()); std::shared_ptr tabbedView = diff --git a/src/lib/component/controller/IDECommunicationController.cpp b/src/lib/component/controller/IDECommunicationController.cpp index 16895146..aaf52cf0 100644 --- a/src/lib/component/controller/IDECommunicationController.cpp +++ b/src/lib/component/controller/IDECommunicationController.cpp @@ -196,7 +196,10 @@ void IDECommunicationController::handlePing(const NetworkProtocolHelper::PingMes void IDECommunicationController::handleMessage(MessageWindowFocus* message) { - sendUpdatePing(); + if (message->focusIn) + { + sendUpdatePing(); + } } void IDECommunicationController::handleMessage(MessageIDECreateCDB* message) diff --git a/src/lib/component/controller/TooltipController.cpp b/src/lib/component/controller/TooltipController.cpp new file mode 100644 index 00000000..1d97b53b --- /dev/null +++ b/src/lib/component/controller/TooltipController.cpp @@ -0,0 +1,141 @@ +#include "TooltipController.h" + +#include "component/view/CodeView.h" +#include "component/view/GraphView.h" +#include "component/view/TooltipView.h" +#include "data/access/StorageAccess.h" + +#include "utility/scheduling/TaskDecoratorDelay.h" +#include "utility/scheduling/TaskLambda.h" + +Id TooltipController::TooltipRequest::s_requestId = 1; + +TooltipController::TooltipController(StorageAccess* storageAccess) + : m_storageAccess(storageAccess) + , m_hideRequest(false) +{ +} + +TooltipController::~TooltipController() +{ +} + +void TooltipController::clear() +{ + m_showRequest.reset(); + m_hideRequest = false; + getView()->hideTooltip(true); +} + +void TooltipController::handleMessage(MessageActivateTokens* message) +{ + clear(); +} + +void TooltipController::handleMessage(MessageFocusIn* message) +{ + if (!message->tokenIds.size()) + { + return; + } + + requestTooltipShow(message->tokenIds, TooltipInfo(), message->origin); +} + +void TooltipController::handleMessage(MessageFocusOut* message) +{ + requestTooltipHide(); +} + +void TooltipController::handleMessage(MessageGraphNodeExpand* message) +{ + clear(); +} + +void TooltipController::handleMessage(MessageTooltipHide* message) +{ + clear(); +} + +void TooltipController::handleMessage(MessageTooltipShow* message) +{ + requestTooltipShow(std::vector(), message->tooltipInfo, message->origin); +} + +void TooltipController::handleMessage(MessageWindowFocus* message) +{ + clear(); +} + +TooltipView* TooltipController::getView() const +{ + return Controller::getView(); +} + +View* TooltipController::getViewForOrigin(TooltipOrigin origin) const +{ + std::string viewName = (origin == TOOLTIP_ORIGIN_CODE ? CodeView::VIEW_NAME : GraphView::VIEW_NAME); + return getView()->getViewLayout()->findFloatingView(viewName); +} + +void TooltipController::requestTooltipShow(const std::vector tokenIds, TooltipInfo info, TooltipOrigin origin) +{ + Id requestId = TooltipRequest::s_requestId++; + + m_showRequest = std::make_unique(); + m_showRequest->requestId = requestId; + m_showRequest->tokenIds = tokenIds; + m_showRequest->info = info; + m_showRequest->origin = origin; + + size_t delayMS = 700; + if (getView()->tooltipVisible()) + { + delayMS = 300; + } + + Task::dispatch(std::make_shared(delayMS)->addChildTask( + std::make_shared( + [requestId, this]() + { + if (m_showRequest && m_showRequest->requestId == requestId) + { + if (!m_showRequest->info.isValid() && m_showRequest->tokenIds.size()) + { + m_showRequest->info = m_storageAccess->getTooltipInfoForTokenIds( + m_showRequest->tokenIds, m_showRequest->origin); + } + + TooltipView* view = getView(); + if (m_showRequest->info.isValid()) + { + view->showTooltip(m_showRequest->info, getViewForOrigin(m_showRequest->origin)); + + m_showRequest.reset(); + m_hideRequest = false; + } + } + } + ) + )); +} + +void TooltipController::requestTooltipHide() +{ + m_showRequest.reset(); + m_hideRequest = true; + + Task::dispatch(std::make_shared(500)->addChildTask( + std::make_shared( + [this]() + { + if (m_hideRequest) + { + m_hideRequest = false; + + getView()->hideTooltip(false); + } + } + ) + )); +} diff --git a/src/lib/component/controller/TooltipController.h b/src/lib/component/controller/TooltipController.h new file mode 100644 index 00000000..aff4627d --- /dev/null +++ b/src/lib/component/controller/TooltipController.h @@ -0,0 +1,67 @@ +#ifndef TOOLTIP_CONTROLLER_H +#define TOOLTIP_CONTROLLER_H + +#include "component/controller/Controller.h" +#include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageActivateTokens.h" +#include "utility/messaging/type/MessageFocusIn.h" +#include "utility/messaging/type/MessageFocusOut.h" +#include "utility/messaging/type/MessageGraphNodeExpand.h" +#include "utility/messaging/type/MessageTooltipHide.h" +#include "utility/messaging/type/MessageTooltipShow.h" +#include "utility/messaging/type/MessageWindowFocus.h" + +class StorageAccess; +class TooltipView; + +class TooltipController + : public Controller + , public MessageListener + , public MessageListener + , public MessageListener + , public MessageListener + , public MessageListener + , public MessageListener + , public MessageListener +{ +public: + TooltipController(StorageAccess* storageAccess); + virtual ~TooltipController(); + + // Controller + virtual void clear(); + + // MessageListener + virtual void handleMessage(MessageActivateTokens* message); + virtual void handleMessage(MessageFocusIn* message); + virtual void handleMessage(MessageFocusOut* message); + virtual void handleMessage(MessageGraphNodeExpand* message); + virtual void handleMessage(MessageTooltipHide* message); + virtual void handleMessage(MessageTooltipShow* message); + virtual void handleMessage(MessageWindowFocus* message); + +private: + struct TooltipRequest + { + static Id s_requestId; + + Id requestId; + std::vector tokenIds; + + TooltipInfo info; + TooltipOrigin origin; + }; + + TooltipView* getView() const; + View* getViewForOrigin(TooltipOrigin origin) const; + + void requestTooltipShow(const std::vector tokenIds, TooltipInfo info, TooltipOrigin origin); + void requestTooltipHide(); + + StorageAccess* m_storageAccess; + + std::unique_ptr m_showRequest; + bool m_hideRequest; +}; + +#endif // TOOLTIP_CONTROLLER_H diff --git a/src/lib/component/view/CodeView.cpp b/src/lib/component/view/CodeView.cpp index f3d8128a..f6159d84 100644 --- a/src/lib/component/view/CodeView.cpp +++ b/src/lib/component/view/CodeView.cpp @@ -2,6 +2,8 @@ #include "component/controller/CodeController.h" +const char* CodeView::VIEW_NAME = "Code"; + CodeView::CodeView(ViewLayout* viewLayout) : View(viewLayout) { @@ -13,7 +15,7 @@ CodeView::~CodeView() std::string CodeView::getName() const { - return "Code"; + return VIEW_NAME; } CodeController* CodeView::getController() diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h index bc49b1af..74b497db 100644 --- a/src/lib/component/view/CodeView.h +++ b/src/lib/component/view/CodeView.h @@ -16,6 +16,8 @@ class CodeView : public View { public: + static const char* VIEW_NAME; + enum FileState { FILE_MINIMIZED, diff --git a/src/lib/component/view/GraphView.cpp b/src/lib/component/view/GraphView.cpp index 435d8617..a498e653 100644 --- a/src/lib/component/view/GraphView.cpp +++ b/src/lib/component/view/GraphView.cpp @@ -1,5 +1,7 @@ #include "component/view/GraphView.h" +const char* GraphView::VIEW_NAME = "Graph"; + GraphView::GraphView(ViewLayout* viewLayout) : View(viewLayout) { @@ -11,5 +13,5 @@ GraphView::~GraphView() std::string GraphView::getName() const { - return "Graph"; + return VIEW_NAME; } diff --git a/src/lib/component/view/GraphView.h b/src/lib/component/view/GraphView.h index 087cf71c..2a5d1277 100644 --- a/src/lib/component/view/GraphView.h +++ b/src/lib/component/view/GraphView.h @@ -16,6 +16,8 @@ class GraphView : public View { public: + static const char* VIEW_NAME; + struct GraphParams { bool animatedTransition; diff --git a/src/lib/component/view/TooltipView.cpp b/src/lib/component/view/TooltipView.cpp new file mode 100644 index 00000000..02ed3cbf --- /dev/null +++ b/src/lib/component/view/TooltipView.cpp @@ -0,0 +1,16 @@ +#include "component/view/TooltipView.h" + +TooltipView::TooltipView(ViewLayout* viewLayout) + : View(viewLayout) +{ +} + +TooltipView::~TooltipView() +{ +} + +std::string TooltipView::getName() const +{ + return "TooltipView"; +} + diff --git a/src/lib/component/view/TooltipView.h b/src/lib/component/view/TooltipView.h new file mode 100644 index 00000000..1873777f --- /dev/null +++ b/src/lib/component/view/TooltipView.h @@ -0,0 +1,27 @@ +#ifndef TOOLTIP_VIEW_H +#define TOOLTIP_VIEW_H + +#include + +#include "component/view/View.h" +#include "data/name/NameHierarchy.h" +#include "data/tooltip/TooltipInfo.h" +#include "utility/types.h" + +class TooltipView + : public View +{ +public: + TooltipView(ViewLayout* viewLayout); + virtual ~TooltipView(); + + // View implementation + virtual std::string getName() const; + + virtual void showTooltip(TooltipInfo info, const View* parent) = 0; + virtual void hideTooltip(bool force) = 0; + + virtual bool tooltipVisible() const = 0; +}; + +#endif // TOOLTIP_VIEW_H diff --git a/src/lib/component/view/ViewFactory.h b/src/lib/component/view/ViewFactory.h index 9260f70b..aba4675a 100644 --- a/src/lib/component/view/ViewFactory.h +++ b/src/lib/component/view/ViewFactory.h @@ -18,6 +18,7 @@ class StatusBarView; class StatusView; class StorageAccess; class TabbedView; +class TooltipView; class UndoRedoView; class ViewLayout; @@ -41,6 +42,7 @@ public: virtual std::shared_ptr createSearchView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createStatusBarView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createStatusView(ViewLayout* viewLayout) const = 0; + virtual std::shared_ptr createTooltipView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createUndoRedoView(ViewLayout* viewLayout) const = 0; virtual std::shared_ptr createDialogView(ViewLayout* viewLayout, StorageAccess* storageAccess) const = 0; diff --git a/src/lib/component/view/ViewLayout.cpp b/src/lib/component/view/ViewLayout.cpp index 1b3c5ac9..c393fdbb 100644 --- a/src/lib/component/view/ViewLayout.cpp +++ b/src/lib/component/view/ViewLayout.cpp @@ -7,3 +7,8 @@ ViewLayout::ViewLayout() ViewLayout::~ViewLayout() { } + +View* ViewLayout::findFloatingView(const std::string& name) const +{ + return nullptr; +} diff --git a/src/lib/component/view/ViewLayout.h b/src/lib/component/view/ViewLayout.h index 59b5e5e5..96534fd3 100644 --- a/src/lib/component/view/ViewLayout.h +++ b/src/lib/component/view/ViewLayout.h @@ -1,6 +1,8 @@ #ifndef VIEW_LAYOUT_H #define VIEW_LAYOUT_H +#include + class View; class ViewLayout @@ -14,6 +16,8 @@ public: virtual void showView(View* view) = 0; virtual void hideView(View* view) = 0; + + virtual View* findFloatingView(const std::string& name) const; }; #endif // VIEW_LAYOUT_H diff --git a/src/lib/data/access/StorageAccess.h b/src/lib/data/access/StorageAccess.h index 320e0a36..c97b4f12 100644 --- a/src/lib/data/access/StorageAccess.h +++ b/src/lib/data/access/StorageAccess.h @@ -16,14 +16,17 @@ #include "data/ErrorFilter.h" #include "data/ErrorInfo.h" #include "data/storage/StorageStats.h" +#include "data/tooltip/TooltipInfo.h" +#include "data/tooltip/TooltipOrigin.h" class FilePath; -struct FileInfo; class Graph; class SourceLocationCollection; class SourceLocationFile; class TextAccess; +struct FileInfo; + class StorageAccess { public: @@ -34,7 +37,7 @@ public: virtual std::vector getNodeIdsForNameHierarchies(const std::vector nameHierarchies) const = 0; virtual NameHierarchy getNameHierarchyForNodeId(Id id) const = 0; - virtual std::vector getNameHierarchiesForNodeIds(const std::vector nodeIds) const = 0; + virtual std::vector getNameHierarchiesForNodeIds(const std::vector& nodeIds) const = 0; virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const = 0; @@ -79,20 +82,22 @@ public: virtual void setErrorFilter(const ErrorFilter& filter); - virtual Id addNodeBookmark(const NodeBookmark& bookmark) = 0; // todo: remove these from storage access - virtual Id addEdgeBookmark(const EdgeBookmark& bookmark) = 0; // todo: remove these from storage access - virtual Id addBookmarkCategory(const std::string& categoryName) = 0; // todo: remove these from storage access + // todo: remove bookmark related methods from storage access + virtual Id addNodeBookmark(const NodeBookmark& bookmark) = 0; + virtual Id addEdgeBookmark(const EdgeBookmark& bookmark) = 0; + virtual Id addBookmarkCategory(const std::string& categoryName) = 0; - virtual void updateBookmark(const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName) = 0; // todo: remove these from storage access - - virtual void removeBookmark(const Id id) = 0; // todo: remove these from storage access - virtual void removeBookmarkCategory(const Id id) = 0; // todo: remove these from storage access + virtual void updateBookmark( + const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName) = 0; + virtual void removeBookmark(const Id id) = 0; + virtual void removeBookmarkCategory(const Id id) = 0; virtual std::vector getAllNodeBookmarks() const = 0; virtual std::vector getAllEdgeBookmarks() const = 0; - virtual std::vector getAllBookmarkCategories() const = 0; + virtual TooltipInfo getTooltipInfoForTokenIds(const std::vector& tokenIds, TooltipOrigin origin) const = 0; + protected: ErrorFilter m_errorFilter; }; diff --git a/src/lib/data/access/StorageAccessProxy.cpp b/src/lib/data/access/StorageAccessProxy.cpp index 04241127..cf041f1c 100644 --- a/src/lib/data/access/StorageAccessProxy.cpp +++ b/src/lib/data/access/StorageAccessProxy.cpp @@ -75,7 +75,7 @@ NameHierarchy StorageAccessProxy::getNameHierarchyForNodeId(Id id) const return NameHierarchy(NAME_DELIMITER_UNKNOWN); } -std::vector StorageAccessProxy::getNameHierarchiesForNodeIds(const std::vector nodeIds) const +std::vector StorageAccessProxy::getNameHierarchiesForNodeIds(const std::vector& nodeIds) const { if (hasSubject()) { @@ -415,6 +415,16 @@ std::vector StorageAccessProxy::getAllBookmarkCategories() con return std::vector(); } +TooltipInfo StorageAccessProxy::getTooltipInfoForTokenIds(const std::vector& tokenIds, TooltipOrigin origin) const +{ + if (hasSubject()) + { + return m_subject->getTooltipInfoForTokenIds(tokenIds, origin); + } + + return TooltipInfo(); +} + void StorageAccessProxy::setErrorFilter(const ErrorFilter& filter) { StorageAccess::setErrorFilter(filter); diff --git a/src/lib/data/access/StorageAccessProxy.h b/src/lib/data/access/StorageAccessProxy.h index e3af44b2..23aaca7a 100644 --- a/src/lib/data/access/StorageAccessProxy.h +++ b/src/lib/data/access/StorageAccessProxy.h @@ -23,7 +23,7 @@ public: virtual std::vector getNodeIdsForNameHierarchies(const std::vector nameHierarchies) const; virtual NameHierarchy getNameHierarchyForNodeId(Id id) const; - virtual std::vector getNameHierarchiesForNodeIds(const std::vector nodeIds) const; + virtual std::vector getNameHierarchiesForNodeIds(const std::vector& nodeIds) const; virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const; @@ -73,16 +73,17 @@ public: virtual Id addEdgeBookmark(const EdgeBookmark& bookmark); virtual Id addBookmarkCategory(const std::string& categoryName); - virtual void updateBookmark(const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName); - + virtual void updateBookmark( + const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName); virtual void removeBookmark(const Id id); virtual void removeBookmarkCategory(const Id id); virtual std::vector getAllNodeBookmarks() const; virtual std::vector getAllEdgeBookmarks() const; - virtual std::vector getAllBookmarkCategories() const; + virtual TooltipInfo getTooltipInfoForTokenIds(const std::vector& tokenIds, TooltipOrigin origin) const; + protected: virtual void setErrorFilter(const ErrorFilter& filter); diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index a4eebe4f..67871e3d 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -10,13 +10,14 @@ #include "data/graph/token_component/TokenComponentConst.h" #include "data/graph/token_component/TokenComponentStatic.h" #include "data/graph/token_component/TokenComponentFilePath.h" -#include "data/graph/token_component/TokenComponentSignature.h" -const Node::NodeTypeMask Node::NODE_NOT_VISIBLE = Node::NODE_NAMESPACE | Node::NODE_PACKAGE; -const Node::NodeTypeMask Node::NODE_USEABLE_TYPE = Node::NODE_NON_INDEXED | Node::NODE_BUILTIN_TYPE | - Node::NODE_STRUCT | Node::NODE_CLASS | Node::NODE_INTERFACE | Node::NODE_TYPEDEF; -const Node::NodeTypeMask Node::NODE_INHERITABLE_TYPE = Node::NODE_NON_INDEXED | Node::NODE_BUILTIN_TYPE | - NODE_TYPE | Node::NODE_STRUCT | Node::NODE_CLASS | Node::NODE_INTERFACE; +const Node::NodeTypeMask Node::NODE_NOT_VISIBLE = NODE_NAMESPACE | NODE_PACKAGE; +const Node::NodeTypeMask Node::NODE_USEABLE_TYPE = NODE_NON_INDEXED | NODE_BUILTIN_TYPE | NODE_STRUCT | NODE_CLASS | + NODE_UNION | NODE_INTERFACE | NODE_TYPEDEF; +const Node::NodeTypeMask Node::NODE_INHERITABLE_TYPE = NODE_NON_INDEXED | NODE_BUILTIN_TYPE | NODE_TYPE | NODE_STRUCT | + NODE_CLASS | NODE_INTERFACE; +const Node::NodeTypeMask Node::NODE_MEMBER_TYPE = NODE_METHOD | NODE_FIELD | NODE_CLASS | NODE_INTERFACE | NODE_STRUCT | + NODE_UNION | NODE_TYPEDEF | NODE_ENUM; std::string Node::getUnderscoredTypeString(NodeType type) { @@ -469,23 +470,6 @@ void Node::addComponentFilePath(std::shared_ptr componen } } -void Node::addComponentSignature(std::shared_ptr component) -{ - if (getComponent()) - { - LOG_ERROR("TokenComponentSignature has been set before!"); - return; - } - else if (!isType(NODE_FUNCTION | NODE_METHOD)) - { - LOG_ERROR("TokenComponentFilePath can't be set on node of type: " + getReadableTypeString()); - } - else - { - addComponent(component); - } -} - void Node::addComponentAccess(std::shared_ptr component) { if (getComponent()) diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index 80e93139..c678a8d5 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -58,6 +58,7 @@ public: static const NodeTypeMask NODE_NOT_VISIBLE; static const NodeTypeMask NODE_USEABLE_TYPE; static const NodeTypeMask NODE_INHERITABLE_TYPE; + static const NodeTypeMask NODE_MEMBER_TYPE; Node(Id id, NodeType type, NameHierarchy nameHierarchy, bool defined); Node(const Node& other); diff --git a/src/lib/data/graph/token_component/TokenComponentSignature.cpp b/src/lib/data/graph/token_component/TokenComponentSignature.cpp deleted file mode 100644 index 25e7273f..00000000 --- a/src/lib/data/graph/token_component/TokenComponentSignature.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "data/graph/token_component/TokenComponentSignature.h" - -TokenComponentSignature::TokenComponentSignature(const std::string& signature) - : m_signature(signature) -{ -} - -TokenComponentSignature::~TokenComponentSignature() -{ -} - -std::shared_ptr TokenComponentSignature::copy() const -{ - return std::make_shared(*this); -} - -const std::string& TokenComponentSignature::getSignature() const -{ - return m_signature; -} diff --git a/src/lib/data/graph/token_component/TokenComponentSignature.h b/src/lib/data/graph/token_component/TokenComponentSignature.h deleted file mode 100644 index e767854c..00000000 --- a/src/lib/data/graph/token_component/TokenComponentSignature.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TOKEN_COMPONENT_SIGNATURE_H -#define TOKEN_COMPONENT_SIGNATURE_H - -#include - -#include "data/graph/token_component/TokenComponent.h" - -class TokenComponentSignature - : public TokenComponent -{ -public: - TokenComponentSignature(const std::string& signature); - virtual ~TokenComponentSignature(); - - virtual std::shared_ptr copy() const; - - const std::string& getSignature() const; - -private: - const std::string m_signature; -}; - -#endif // TOKEN_COMPONENT_SIGNATURE_H diff --git a/src/lib/data/name/NameElement.cpp b/src/lib/data/name/NameElement.cpp index 1f59824b..3b10462a 100644 --- a/src/lib/data/name/NameElement.cpp +++ b/src/lib/data/name/NameElement.cpp @@ -61,6 +61,16 @@ bool NameElement::Signature::isValid() const return ((m_prefix + m_postfix).size() > 0); } +const std::string& NameElement::Signature::getPrefix() const +{ + return m_prefix; +} + +const std::string& NameElement::Signature::getPostfix() const +{ + return m_postfix; +} + NameElement::NameElement(const std::string& name) : m_name(name) { diff --git a/src/lib/data/name/NameElement.h b/src/lib/data/name/NameElement.h index 565ea039..2b9aea67 100644 --- a/src/lib/data/name/NameElement.h +++ b/src/lib/data/name/NameElement.h @@ -21,6 +21,9 @@ public: std::string qualifyName(const std::string& name) const; bool isValid() const; + const std::string& getPrefix() const; + const std::string& getPostfix() const; + private: std::string m_prefix; std::string m_postfix; diff --git a/src/lib/data/name/NameHierarchy.cpp b/src/lib/data/name/NameHierarchy.cpp index e908b4e4..6f794965 100644 --- a/src/lib/data/name/NameHierarchy.cpp +++ b/src/lib/data/name/NameHierarchy.cpp @@ -161,3 +161,13 @@ std::string NameHierarchy::getRawNameWithSignature() const } return ""; } + +NameElement::Signature NameHierarchy::getSignature() const +{ + if (m_elements.size()) + { + return m_elements.back()->getSignature(); // todo: use separator for signature! + } + + return NameElement::Signature(); +} diff --git a/src/lib/data/name/NameHierarchy.h b/src/lib/data/name/NameHierarchy.h index aab79d1a..ab555faf 100644 --- a/src/lib/data/name/NameHierarchy.h +++ b/src/lib/data/name/NameHierarchy.h @@ -37,6 +37,8 @@ public: std::string getRawName() const; std::string getRawNameWithSignature() const; + NameElement::Signature getSignature() const; + private: std::vector> m_elements; NameDelimiterType m_delimiter; diff --git a/src/lib/data/parser/AccessKind.cpp b/src/lib/data/parser/AccessKind.cpp index 057a599e..55031b4a 100644 --- a/src/lib/data/parser/AccessKind.cpp +++ b/src/lib/data/parser/AccessKind.cpp @@ -25,3 +25,25 @@ int accessKindToInt(AccessKind t) return t; } +std::string accessKindToString(AccessKind t) +{ + switch (t) + { + case ACCESS_NONE: + return ""; + case ACCESS_PUBLIC: + return "public"; + case ACCESS_PROTECTED: + return "protected"; + case ACCESS_PRIVATE: + return "private"; + case ACCESS_DEFAULT: + return "default"; + case ACCESS_TEMPLATE_PARAMETER: + return "template parameter"; + case ACCESS_TYPE_PARAMETER: + return "type parameter"; + } + return ""; +} + diff --git a/src/lib/data/parser/AccessKind.h b/src/lib/data/parser/AccessKind.h index 1689b9cd..308fb5c2 100644 --- a/src/lib/data/parser/AccessKind.h +++ b/src/lib/data/parser/AccessKind.h @@ -1,6 +1,8 @@ #ifndef ACCESS_KIND_H #define ACCESS_KIND_H +#include + enum AccessKind { // these values need to be the same as AccessKind in Java code ACCESS_NONE = 0, @@ -14,5 +16,6 @@ enum AccessKind AccessKind intToAccessKind(int v); int accessKindToInt(AccessKind t); +std::string accessKindToString(AccessKind t); #endif // ACCESS_KIND_H diff --git a/src/lib/data/parser/TaskParseWrapper.cpp b/src/lib/data/parser/TaskParseWrapper.cpp index 718bd499..cbc9b976 100644 --- a/src/lib/data/parser/TaskParseWrapper.cpp +++ b/src/lib/data/parser/TaskParseWrapper.cpp @@ -15,14 +15,6 @@ TaskParseWrapper::~TaskParseWrapper() { } -void TaskParseWrapper::setTask(std::shared_ptr task) -{ - if (task) - { - m_taskRunner = std::make_shared(task); - } -} - void TaskParseWrapper::doEnter(std::shared_ptr blackboard) { int sourceFileCount = 0; @@ -54,8 +46,3 @@ void TaskParseWrapper::doReset(std::shared_ptr blackboard) { m_taskRunner->reset(); } - -void TaskParseWrapper::doTerminate() -{ - m_taskRunner->terminate(); -} diff --git a/src/lib/data/parser/TaskParseWrapper.h b/src/lib/data/parser/TaskParseWrapper.h index 7f14446e..81be25ff 100644 --- a/src/lib/data/parser/TaskParseWrapper.h +++ b/src/lib/data/parser/TaskParseWrapper.h @@ -19,19 +19,15 @@ public: TaskParseWrapper(PersistentStorage* storage); virtual ~TaskParseWrapper(); - virtual void setTask(std::shared_ptr task); - private: virtual void doEnter(std::shared_ptr blackboard); virtual TaskState doUpdate(std::shared_ptr blackboard); virtual void doExit(std::shared_ptr blackboard); virtual void doReset(std::shared_ptr blackboard); - virtual void doTerminate(); PersistentStorage* m_storage; TimePoint m_start; - std::shared_ptr m_taskRunner; }; #endif // TASK_PARSE_WRAPPER_H diff --git a/src/lib/data/storage/PersistentStorage.cpp b/src/lib/data/storage/PersistentStorage.cpp index 7a34f745..39ca7594 100644 --- a/src/lib/data/storage/PersistentStorage.cpp +++ b/src/lib/data/storage/PersistentStorage.cpp @@ -18,12 +18,12 @@ #include "data/graph/token_component/TokenComponentAggregation.h" #include "data/graph/token_component/TokenComponentFilePath.h" #include "data/graph/token_component/TokenComponentInheritanceChain.h" -#include "data/graph/token_component/TokenComponentSignature.h" #include "data/graph/Graph.h" #include "data/location/SourceLocationCollection.h" #include "data/location/SourceLocationFile.h" #include "data/parser/AccessKind.h" #include "data/parser/ParseLocation.h" +#include "settings/ApplicationSettings.h" PersistentStorage::PersistentStorage(const FilePath& dbPath, const FilePath& bookmarkPath) : m_sqliteIndexStorage(dbPath) @@ -147,182 +147,6 @@ void PersistentStorage::addError( ); } -Id PersistentStorage::addNodeBookmark(const NodeBookmark& bookmark) -{ - const Id categoryId = addBookmarkCategory(bookmark.getCategory().getName()); - const Id id = m_sqliteBookmarkStorage.addBookmark( - bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId); - - for (const Id& nodeId: bookmark.getNodeIds()) - { - m_sqliteBookmarkStorage.addBookmarkedNode(id, m_sqliteIndexStorage.getNodeById(nodeId).serializedName); - } - - return id; -} - -Id PersistentStorage::addEdgeBookmark(const EdgeBookmark& bookmark) -{ - const Id categoryId = addBookmarkCategory(bookmark.getCategory().getName()); - const Id id = m_sqliteBookmarkStorage.addBookmark( - bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId); - for (const Id& edgeId: bookmark.getEdgeIds()) - { - const StorageEdge storageEdge = m_sqliteIndexStorage.getEdgeById(edgeId); - - bool sourceNodeActive = storageEdge.sourceNodeId == bookmark.getActiveNodeId(); - m_sqliteBookmarkStorage.addBookmarkedEdge( - id, - // todo: optimization for multiple edges in same bookmark: use a local cache here - m_sqliteIndexStorage.getNodeById(storageEdge.sourceNodeId).serializedName, - m_sqliteIndexStorage.getNodeById(storageEdge.targetNodeId).serializedName, - storageEdge.type, - sourceNodeActive - ); - } - return id; -} - -Id PersistentStorage::addBookmarkCategory(const std::string& name) -{ - if (name.empty()) - { - return 0; - } - - Id id = m_sqliteBookmarkStorage.getBookmarkCategoryByName(name).id; - if (id == 0) - { - id = m_sqliteBookmarkStorage.addBookmarkCategory(name); - } - return id; -} - -void PersistentStorage::updateBookmark( - const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName) -{ - const Id categoryId = addBookmarkCategory(categoryName); // only creates category if id didn't exist before; - m_sqliteBookmarkStorage.updateBookmark(bookmarkId, name, comment, categoryId); -} - -void PersistentStorage::removeBookmark(const Id id) -{ - m_sqliteBookmarkStorage.removeBookmark(id); -} - -void PersistentStorage::removeBookmarkCategory(Id id) -{ - m_sqliteBookmarkStorage.removeBookmarkCategory(id); -} - -std::vector PersistentStorage::getAllNodeBookmarks() const -{ - std::unordered_map bookmarkCategories; - for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories()) - { - bookmarkCategories[bookmarkCategory.id] = bookmarkCategory; - } - - std::unordered_map> bookmarkIdToBookmarkedNodeIds; - for (const StorageBookmarkedNode& bookmarkedNode: m_sqliteBookmarkStorage.getAllBookmarkedNodes()) - { - bookmarkIdToBookmarkedNodeIds[bookmarkedNode.bookmarkId].push_back( - m_sqliteIndexStorage.getNodeBySerializedName(bookmarkedNode.serializedNodeName).id); - } - - std::vector nodeBookmarks; - - for (const StorageBookmark& storageBookmark: m_sqliteBookmarkStorage.getAllBookmarks()) - { - auto itCategories = bookmarkCategories.find(storageBookmark.categoryId); - auto itNodeIds = bookmarkIdToBookmarkedNodeIds.find(storageBookmark.id); - if (itCategories != bookmarkCategories.end() && itNodeIds != bookmarkIdToBookmarkedNodeIds.end()) - { - NodeBookmark bookmark( - storageBookmark.id, - storageBookmark.name, - storageBookmark.comment, - storageBookmark.timestamp, - BookmarkCategory(itCategories->second.id, itCategories->second.name) - ); - bookmark.setNodeIds(itNodeIds->second); - bookmark.setIsValid(); - nodeBookmarks.push_back(bookmark); - } - } - - return nodeBookmarks; -} - -std::vector PersistentStorage::getAllEdgeBookmarks() const -{ - std::unordered_map bookmarkCategories; - for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories()) - { - bookmarkCategories[bookmarkCategory.id] = bookmarkCategory; - } - - std::unordered_map> bookmarkIdToBookmarkedEdges; - for (const StorageBookmarkedEdge& bookmarkedEdge: m_sqliteBookmarkStorage.getAllBookmarkedEdges()) - { - bookmarkIdToBookmarkedEdges[bookmarkedEdge.bookmarkId].push_back(bookmarkedEdge); - } - - std::vector edgeBookmarks; - - Cache nodeIdCache([&](std::string serializedNodeName) - { - return m_sqliteIndexStorage.getNodeBySerializedName(serializedNodeName).id; - } - ); - - for (const StorageBookmark& storageBookmark: m_sqliteBookmarkStorage.getAllBookmarks()) - { - auto itCategories = bookmarkCategories.find(storageBookmark.categoryId); - auto itBookmarkedEdges = bookmarkIdToBookmarkedEdges.find(storageBookmark.id); - if (itCategories != bookmarkCategories.end() && itBookmarkedEdges != bookmarkIdToBookmarkedEdges.end()) - { - EdgeBookmark bookmark( - storageBookmark.id, - storageBookmark.name, - storageBookmark.comment, - storageBookmark.timestamp, - BookmarkCategory(itCategories->second.id, itCategories->second.name) - ); - - Id activeNodeId = 0; - for (const StorageBookmarkedEdge& bookmarkedEdge: itBookmarkedEdges->second) - { - const Id sourceNodeId = nodeIdCache.getValue(bookmarkedEdge.serializedSourceNodeName); - const Id targetNodeId = nodeIdCache.getValue(bookmarkedEdge.serializedTargetNodeName); - const Id edgeId = - m_sqliteIndexStorage.getEdgeBySourceTargetType(sourceNodeId, targetNodeId, bookmarkedEdge.edgeType).id; - bookmark.addEdgeId(edgeId); - - if (activeNodeId == 0) - { - activeNodeId = bookmarkedEdge.sourceNodeActive ? sourceNodeId : targetNodeId; - } - } - bookmark.setActiveNodeId(activeNodeId); - bookmark.setIsValid(); - edgeBookmarks.push_back(bookmark); - } - } - - return edgeBookmarks; -} - -std::vector PersistentStorage::getAllBookmarkCategories() const -{ - std::vector categories; - for (const StorageBookmarkCategory storageBookmarkCategoriy: m_sqliteBookmarkStorage.getAllBookmarkCategories()) - { - categories.push_back(BookmarkCategory(storageBookmarkCategoriy.id, storageBookmarkCategoriy.name)); - } - return categories; -} - void PersistentStorage::forEachNode(std::function callback) const { for (StorageNode& node: m_sqliteIndexStorage.getAll()) @@ -602,7 +426,7 @@ NameHierarchy PersistentStorage::getNameHierarchyForNodeId(Id nodeId) const return NameHierarchy::deserialize(m_sqliteIndexStorage.getFirstById(nodeId).serializedName); } -std::vector PersistentStorage::getNameHierarchiesForNodeIds(const std::vector nodeIds) const +std::vector PersistentStorage::getNameHierarchiesForNodeIds(const std::vector& nodeIds) const { TRACE(); @@ -1564,6 +1388,370 @@ std::shared_ptr PersistentStorage::getErrorSourceLocat return collection; } +Id PersistentStorage::addNodeBookmark(const NodeBookmark& bookmark) +{ + const Id categoryId = addBookmarkCategory(bookmark.getCategory().getName()); + const Id id = m_sqliteBookmarkStorage.addBookmark( + bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId); + + for (const Id& nodeId: bookmark.getNodeIds()) + { + m_sqliteBookmarkStorage.addBookmarkedNode(id, m_sqliteIndexStorage.getNodeById(nodeId).serializedName); + } + + return id; +} + +Id PersistentStorage::addEdgeBookmark(const EdgeBookmark& bookmark) +{ + const Id categoryId = addBookmarkCategory(bookmark.getCategory().getName()); + const Id id = m_sqliteBookmarkStorage.addBookmark( + bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId); + for (const Id& edgeId: bookmark.getEdgeIds()) + { + const StorageEdge storageEdge = m_sqliteIndexStorage.getEdgeById(edgeId); + + bool sourceNodeActive = storageEdge.sourceNodeId == bookmark.getActiveNodeId(); + m_sqliteBookmarkStorage.addBookmarkedEdge( + id, + // todo: optimization for multiple edges in same bookmark: use a local cache here + m_sqliteIndexStorage.getNodeById(storageEdge.sourceNodeId).serializedName, + m_sqliteIndexStorage.getNodeById(storageEdge.targetNodeId).serializedName, + storageEdge.type, + sourceNodeActive + ); + } + return id; +} + +Id PersistentStorage::addBookmarkCategory(const std::string& name) +{ + if (name.empty()) + { + return 0; + } + + Id id = m_sqliteBookmarkStorage.getBookmarkCategoryByName(name).id; + if (id == 0) + { + id = m_sqliteBookmarkStorage.addBookmarkCategory(name); + } + return id; +} + +void PersistentStorage::updateBookmark( + const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName) +{ + const Id categoryId = addBookmarkCategory(categoryName); // only creates category if id didn't exist before; + m_sqliteBookmarkStorage.updateBookmark(bookmarkId, name, comment, categoryId); +} + +void PersistentStorage::removeBookmark(const Id id) +{ + m_sqliteBookmarkStorage.removeBookmark(id); +} + +void PersistentStorage::removeBookmarkCategory(Id id) +{ + m_sqliteBookmarkStorage.removeBookmarkCategory(id); +} + +std::vector PersistentStorage::getAllNodeBookmarks() const +{ + std::unordered_map bookmarkCategories; + for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories()) + { + bookmarkCategories[bookmarkCategory.id] = bookmarkCategory; + } + + std::unordered_map> bookmarkIdToBookmarkedNodeIds; + for (const StorageBookmarkedNode& bookmarkedNode: m_sqliteBookmarkStorage.getAllBookmarkedNodes()) + { + bookmarkIdToBookmarkedNodeIds[bookmarkedNode.bookmarkId].push_back( + m_sqliteIndexStorage.getNodeBySerializedName(bookmarkedNode.serializedNodeName).id); + } + + std::vector nodeBookmarks; + + for (const StorageBookmark& storageBookmark: m_sqliteBookmarkStorage.getAllBookmarks()) + { + auto itCategories = bookmarkCategories.find(storageBookmark.categoryId); + auto itNodeIds = bookmarkIdToBookmarkedNodeIds.find(storageBookmark.id); + if (itCategories != bookmarkCategories.end() && itNodeIds != bookmarkIdToBookmarkedNodeIds.end()) + { + NodeBookmark bookmark( + storageBookmark.id, + storageBookmark.name, + storageBookmark.comment, + storageBookmark.timestamp, + BookmarkCategory(itCategories->second.id, itCategories->second.name) + ); + bookmark.setNodeIds(itNodeIds->second); + bookmark.setIsValid(); + nodeBookmarks.push_back(bookmark); + } + } + + return nodeBookmarks; +} + +std::vector PersistentStorage::getAllEdgeBookmarks() const +{ + std::unordered_map bookmarkCategories; + for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories()) + { + bookmarkCategories[bookmarkCategory.id] = bookmarkCategory; + } + + std::unordered_map> bookmarkIdToBookmarkedEdges; + for (const StorageBookmarkedEdge& bookmarkedEdge: m_sqliteBookmarkStorage.getAllBookmarkedEdges()) + { + bookmarkIdToBookmarkedEdges[bookmarkedEdge.bookmarkId].push_back(bookmarkedEdge); + } + + std::vector edgeBookmarks; + + Cache nodeIdCache([&](std::string serializedNodeName) + { + return m_sqliteIndexStorage.getNodeBySerializedName(serializedNodeName).id; + } + ); + + for (const StorageBookmark& storageBookmark: m_sqliteBookmarkStorage.getAllBookmarks()) + { + auto itCategories = bookmarkCategories.find(storageBookmark.categoryId); + auto itBookmarkedEdges = bookmarkIdToBookmarkedEdges.find(storageBookmark.id); + if (itCategories != bookmarkCategories.end() && itBookmarkedEdges != bookmarkIdToBookmarkedEdges.end()) + { + EdgeBookmark bookmark( + storageBookmark.id, + storageBookmark.name, + storageBookmark.comment, + storageBookmark.timestamp, + BookmarkCategory(itCategories->second.id, itCategories->second.name) + ); + + Id activeNodeId = 0; + for (const StorageBookmarkedEdge& bookmarkedEdge: itBookmarkedEdges->second) + { + const Id sourceNodeId = nodeIdCache.getValue(bookmarkedEdge.serializedSourceNodeName); + const Id targetNodeId = nodeIdCache.getValue(bookmarkedEdge.serializedTargetNodeName); + const Id edgeId = + m_sqliteIndexStorage.getEdgeBySourceTargetType(sourceNodeId, targetNodeId, bookmarkedEdge.edgeType).id; + bookmark.addEdgeId(edgeId); + + if (activeNodeId == 0) + { + activeNodeId = bookmarkedEdge.sourceNodeActive ? sourceNodeId : targetNodeId; + } + } + bookmark.setActiveNodeId(activeNodeId); + bookmark.setIsValid(); + edgeBookmarks.push_back(bookmark); + } + } + + return edgeBookmarks; +} + +std::vector PersistentStorage::getAllBookmarkCategories() const +{ + std::vector categories; + for (const StorageBookmarkCategory storageBookmarkCategoriy: m_sqliteBookmarkStorage.getAllBookmarkCategories()) + { + categories.push_back(BookmarkCategory(storageBookmarkCategoriy.id, storageBookmarkCategoriy.name)); + } + return categories; +} + +TooltipInfo PersistentStorage::getTooltipInfoForTokenIds(const std::vector& tokenIds, TooltipOrigin origin) const +{ + TRACE(); + + TooltipInfo info; + + if (!tokenIds.size()) + { + return info; + } + + StorageNode node = m_sqliteIndexStorage.getFirstById(tokenIds[0]); + if (node.id == 0 && origin == TOOLTIP_ORIGIN_CODE) + { + StorageEdge edge = m_sqliteIndexStorage.getFirstById(tokenIds[0]); + + if (edge.id > 0) + { + node = m_sqliteIndexStorage.getFirstById(edge.targetNodeId); + } + } + + if (node.id == 0) + { + return info; + } + + Node::NodeType type = Node::intToType(node.type); + info.title = Node::getReadableTypeString(type); + + DefinitionKind defKind = DEFINITION_NONE; + StorageSymbol symbol = m_sqliteIndexStorage.getFirstById(node.id); + if (symbol.id > 0) + { + defKind = intToDefinitionKind(symbol.definitionKind); + } + + if (type & Node::NODE_MEMBER_TYPE) + { + StorageComponentAccess access = m_sqliteIndexStorage.getComponentAccessByNodeId(node.id); + if (access.nodeId != 0) + { + info.title = accessKindToString(intToAccessKind(access.type)) + " " + info.title; + } + } + + if (type == Node::NODE_FILE) + { + bool complete = false; + auto it = m_fileNodeComplete.find(node.id); + if (it != m_fileNodeComplete.end()) + { + complete = it->second; + } + + if (!complete) + { + info.title = "incomplete " + info.title; + } + } + else if (defKind == DEFINITION_NONE && type != Node::NODE_NON_INDEXED) + { + info.title = "non-indexed " + info.title; + } + else if (defKind == DEFINITION_IMPLICIT) + { + info.title = "implicit " + info.title; + } + + info.count = 0; + info.countText = "reference"; + for (auto edge : m_sqliteIndexStorage.getEdgesByTargetId(node.id)) + { + if (Edge::intToType(edge.type) != Edge::EDGE_MEMBER) + { + info.count++; + } + } + + info.snippets.push_back(getTooltipSnippetForNode(node)); + + if (origin == TOOLTIP_ORIGIN_CODE) + { + info.offset = Vec2i(20, 30); + } + else + { + info.offset = Vec2i(50, 20); + } + + return info; +} + +TooltipSnippet PersistentStorage::getTooltipSnippetForNode(const StorageNode& node) const +{ + TRACE(); + + TooltipSnippet snippet; + NameHierarchy nameHierarchy = NameHierarchy::deserialize(node.serializedName); + snippet.code = nameHierarchy.getQualifiedNameWithSignature(); + snippet.locationFile = std::make_shared( + FilePath(nameHierarchy.getDelimiter() == NAME_DELIMITER_JAVA ? "main.java" : "main.cpp"), true, true); + + if (Node::intToType(node.type) & (Node::NODE_FUNCTION | Node::NODE_METHOD | Node::NODE_FIELD | Node::NODE_GLOBAL_VARIABLE)) + { + snippet.code = utility::breakSignature( + nameHierarchy.getSignature().getPrefix(), + nameHierarchy.getQualifiedName(), + nameHierarchy.getSignature().getPostfix(), + 50, + ApplicationSettings::getInstance()->getCodeTabWidth() + ); + + std::vector typeNodeIds; + for (auto edge : m_sqliteIndexStorage.getEdgesBySourceId(node.id)) + { + if (Edge::intToType(edge.type) == Edge::EDGE_TYPE_USAGE) + { + typeNodeIds.push_back(edge.targetNodeId); + } + } + + std::set, bool(*)(const std::pair&, const std::pair&)> typeNames( + [](const std::pair& a, const std::pair& b) + { + if (a.first.size() == b.first.size()) + { + return a.first < b.first; + } + + return a.first.size() > b.first.size(); + } + ); + + typeNames.insert(std::make_pair(nameHierarchy.getQualifiedName(), node.id)); + for (auto typeNode : m_sqliteIndexStorage.getAllByIds(typeNodeIds)) + { + typeNames.insert(std::make_pair( + NameHierarchy::deserialize(typeNode.serializedName).getQualifiedName(), + typeNode.id + )); + } + + Id locationId = 1; + std::vector> locationRanges; + for (auto p : typeNames) + { + size_t pos = 0; + while (pos != std::string::npos) + { + pos = snippet.code.find(p.first, pos); + if (pos == std::string::npos) + { + continue; + } + + bool inRange = false; + for (auto p : locationRanges) + { + if (pos + 1 >= p.first && pos + 1 <= p.second) + { + inRange = true; + pos = p.second + 1; + break; + } + } + + if (!inRange) + { + snippet.locationFile->addSourceLocation( + LOCATION_TOKEN, locationId, std::vector(1, p.second), 1, pos + 1, 1, pos + p.first.size()); + + locationRanges.push_back(std::make_pair(pos + 1, pos + p.first.size())); + pos += p.first.size(); + locationId++; + } + } + } + } + else + { + snippet.locationFile->addSourceLocation( + LOCATION_TOKEN, 0, std::vector(1, node.id), 1, 1, 1, snippet.code.size()); + } + + return snippet; +} + Id PersistentStorage::getFileNodeId(const FilePath& filePath) const { if (filePath.empty()) @@ -1864,17 +2052,6 @@ void PersistentStorage::addNodesToGraph(const std::vector& newNodeIds, Graph node->setExplicit(true); } - if (type == Node::NODE_FUNCTION || type == Node::NODE_METHOD) - { - std::string signatureString = nameHierarchy.getRawNameWithSignature(); - if (signatureString.size() > 0) // this should always be the case since functions and methods must have sigs. - { - node->addComponentSignature( - std::make_shared(signatureString) - ); - } - } - if (addChildCount) { node->setChildCount(m_hierarchyCache.getFirstNonImplicitChildIdsCountForNodeId(storageNode.id)); diff --git a/src/lib/data/storage/PersistentStorage.h b/src/lib/data/storage/PersistentStorage.h index a7a7a527..7b697dc7 100644 --- a/src/lib/data/storage/PersistentStorage.h +++ b/src/lib/data/storage/PersistentStorage.h @@ -30,20 +30,6 @@ public: virtual void addComponentAccess(Id nodeId , int type); virtual void addCommentLocation(Id fileNodeId, uint startLine, uint startCol, uint endLine, uint endCol); virtual void addError(const std::string& message, const FilePath& filePath, uint startLine, uint startCol, bool fatal, bool indexed); - virtual Id addNodeBookmark(const NodeBookmark& bookmark); - virtual Id addEdgeBookmark(const EdgeBookmark& bookmark); - virtual Id addBookmarkCategory(const std::string& categoryName); - - void updateBookmark(const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName); - - virtual void removeBookmark(const Id id); - virtual void removeBookmarkCategory(const Id id); - - std::vector getAllNodeBookmarks() const; - std::vector getAllEdgeBookmarks() const; - - - virtual std::vector getAllBookmarkCategories() const; virtual void forEachNode(std::function callback) const; virtual void forEachFile(std::function callback) const; @@ -89,7 +75,7 @@ public: virtual std::vector getNodeIdsForNameHierarchies(const std::vector nameHierarchies) const; virtual NameHierarchy getNameHierarchyForNodeId(Id nodeId) const; - virtual std::vector getNameHierarchiesForNodeIds(const std::vector nodeIds) const; + virtual std::vector getNameHierarchiesForNodeIds(const std::vector& nodeIds) const; virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const; @@ -138,6 +124,21 @@ public: virtual std::vector getErrorsLimited() const; virtual std::shared_ptr getErrorSourceLocationsLimited(std::vector* errors) const; + virtual Id addNodeBookmark(const NodeBookmark& bookmark); + virtual Id addEdgeBookmark(const EdgeBookmark& bookmark); + virtual Id addBookmarkCategory(const std::string& categoryName); + + virtual void updateBookmark(const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName); + virtual void removeBookmark(const Id id); + virtual void removeBookmarkCategory(const Id id); + + virtual std::vector getAllNodeBookmarks() const; + virtual std::vector getAllEdgeBookmarks() const; + virtual std::vector getAllBookmarkCategories() const; + + virtual TooltipInfo getTooltipInfoForTokenIds(const std::vector& tokenIds, TooltipOrigin origin) const; + TooltipSnippet getTooltipSnippetForNode(const StorageNode& node) const; + private: Id getFileNodeId(const FilePath& filePath) const; std::vector getFileNodeIds(const std::vector& filePaths) const; diff --git a/src/lib/data/storage/sqlite/SqliteStorage.cpp b/src/lib/data/storage/sqlite/SqliteStorage.cpp index 41242c4f..7a497c80 100644 --- a/src/lib/data/storage/sqlite/SqliteStorage.cpp +++ b/src/lib/data/storage/sqlite/SqliteStorage.cpp @@ -219,9 +219,10 @@ int SqliteStorage::executeStatementScalar(CppSQLite3Statement& statement, const if (q.eof() || q.numFields() < 1) { + char error[] = "Invalid scalar query"; throw CppSQLite3Exception( CPPSQLITE_ERROR, - "Invalid scalar query", + error, false ); } diff --git a/src/lib/data/tooltip/TooltipInfo.h b/src/lib/data/tooltip/TooltipInfo.h new file mode 100644 index 00000000..9c5047bd --- /dev/null +++ b/src/lib/data/tooltip/TooltipInfo.h @@ -0,0 +1,34 @@ +#ifndef TOOLTIP_INFO_H +#define TOOLTIP_INFO_H + +#include + +#include "utility/math/Vector2.h" +#include "utility/types.h" + +class SourceLocationFile; + +struct TooltipSnippet +{ + std::string code; + std::shared_ptr locationFile; +}; + +struct TooltipInfo +{ + bool isValid() const + { + return title.size() || snippets.size(); + } + + std::string title; + + int count = -1; + std::string countText; + + std::vector snippets; + + Vec2i offset; +}; + +#endif // TOOLTIP_INFO_H diff --git a/src/lib/data/tooltip/TooltipOrigin.h b/src/lib/data/tooltip/TooltipOrigin.h new file mode 100644 index 00000000..397e9f36 --- /dev/null +++ b/src/lib/data/tooltip/TooltipOrigin.h @@ -0,0 +1,10 @@ +#ifndef TOOLTIP_ORIGIN_H +#define TOOLTIP_ORIGIN_H + +enum TooltipOrigin +{ + TOOLTIP_ORIGIN_GRAPH, + TOOLTIP_ORIGIN_CODE +}; + +#endif // TOOLTIP_ORIGIN_H diff --git a/src/lib/utility/messaging/type/MessageFocusIn.h b/src/lib/utility/messaging/type/MessageFocusIn.h index cd5ca74e..552abc13 100644 --- a/src/lib/utility/messaging/type/MessageFocusIn.h +++ b/src/lib/utility/messaging/type/MessageFocusIn.h @@ -6,12 +6,15 @@ #include "utility/messaging/Message.h" #include "utility/types.h" +#include "data/tooltip/TooltipOrigin.h" + class MessageFocusIn : public Message { public: - MessageFocusIn(const std::vector& tokenIds) + MessageFocusIn(const std::vector& tokenIds, TooltipOrigin origin) : tokenIds(tokenIds) + , origin(origin) { setIsLogged(false); } @@ -30,6 +33,7 @@ public: } const std::vector tokenIds; + const TooltipOrigin origin; }; #endif //MESSAGE_FOCUS_IN_H diff --git a/src/lib/utility/messaging/type/MessageTooltipHide.h b/src/lib/utility/messaging/type/MessageTooltipHide.h new file mode 100644 index 00000000..7a16b4d6 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageTooltipHide.h @@ -0,0 +1,21 @@ +#ifndef MESSAGE_TOOLTIP_HIDE_H +#define MESSAGE_TOOLTIP_HIDE_H + +#include "utility/messaging/Message.h" + +class MessageTooltipHide + : public Message +{ +public: + MessageTooltipHide() + { + setSendAsTask(false); + } + + static const std::string getStaticType() + { + return "MessageTooltipHide"; + } +}; + +#endif // MESSAGE_TOOLTIP_HIDE_H diff --git a/src/lib/utility/messaging/type/MessageTooltipShow.h b/src/lib/utility/messaging/type/MessageTooltipShow.h new file mode 100644 index 00000000..01d7f057 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageTooltipShow.h @@ -0,0 +1,29 @@ +#ifndef MESSAGE_TOOLTIP_SHOW_H +#define MESSAGE_TOOLTIP_SHOW_H + +#include "utility/messaging/Message.h" + +#include "data/tooltip/TooltipOrigin.h" +#include "data/tooltip/TooltipInfo.h" + +class MessageTooltipShow + : public Message +{ +public: + MessageTooltipShow(TooltipInfo info, TooltipOrigin origin) + : tooltipInfo(info) + , origin(origin) + { + setSendAsTask(false); + } + + static const std::string getStaticType() + { + return "MessageTooltipShow"; + } + + const TooltipInfo tooltipInfo; + const TooltipOrigin origin; +}; + +#endif // MESSAGE_TOOLTIP_SHOW_H diff --git a/src/lib/utility/messaging/type/MessageWindowFocus.h b/src/lib/utility/messaging/type/MessageWindowFocus.h index 2f43c6c2..f4f913ca 100644 --- a/src/lib/utility/messaging/type/MessageWindowFocus.h +++ b/src/lib/utility/messaging/type/MessageWindowFocus.h @@ -3,10 +3,12 @@ #include "utility/messaging/Message.h" -class MessageWindowFocus: public Message +class MessageWindowFocus + : public Message { public: - MessageWindowFocus() + MessageWindowFocus(bool focusIn) + : focusIn(focusIn) { } @@ -14,6 +16,8 @@ public: { return "MessageWindowFocus"; } + + const bool focusIn; }; #endif // MESSAGE_WINDOW_FOCUS_H diff --git a/src/lib/utility/scheduling/Task.h b/src/lib/utility/scheduling/Task.h index 69e9124b..9333227b 100644 --- a/src/lib/utility/scheduling/Task.h +++ b/src/lib/utility/scheduling/Task.h @@ -11,6 +11,7 @@ public: enum TaskState { STATE_RUNNING, + STATE_HOLD, STATE_SUCCESS, STATE_FAILURE }; diff --git a/src/lib/utility/scheduling/TaskDecorator.cpp b/src/lib/utility/scheduling/TaskDecorator.cpp index f6070741..4878bf51 100644 --- a/src/lib/utility/scheduling/TaskDecorator.cpp +++ b/src/lib/utility/scheduling/TaskDecorator.cpp @@ -1,5 +1,7 @@ #include "utility/scheduling/TaskDecorator.h" +#include "utility/scheduling/TaskRunner.h" + TaskDecorator::TaskDecorator() { } @@ -14,7 +16,20 @@ std::shared_ptr TaskDecorator::addChildTask(std::shared_ptr return shared_from_this(); } +void TaskDecorator::setTask(std::shared_ptr task) +{ + if (task) + { + m_taskRunner = std::make_shared(task); + } +} + void TaskDecorator::terminate() { doTerminate(); } + +void TaskDecorator::doTerminate() +{ + m_taskRunner->terminate(); +} diff --git a/src/lib/utility/scheduling/TaskDecorator.h b/src/lib/utility/scheduling/TaskDecorator.h index c8b010cb..a267a1f1 100644 --- a/src/lib/utility/scheduling/TaskDecorator.h +++ b/src/lib/utility/scheduling/TaskDecorator.h @@ -5,6 +5,8 @@ #include "utility/scheduling/Task.h" +class TaskRunner; + class TaskDecorator : public Task , public std::enable_shared_from_this @@ -14,11 +16,14 @@ public: virtual ~TaskDecorator(); std::shared_ptr addChildTask(std::shared_ptr child); - virtual void setTask(std::shared_ptr task) = 0; + virtual void setTask(std::shared_ptr task); virtual void terminate(); +protected: + std::shared_ptr m_taskRunner; + private: - virtual void doTerminate() = 0; + virtual void doTerminate(); }; #endif // TASK_DECORATOR_H diff --git a/src/lib/utility/scheduling/TaskDecoratorDelay.cpp b/src/lib/utility/scheduling/TaskDecoratorDelay.cpp new file mode 100644 index 00000000..d18949bd --- /dev/null +++ b/src/lib/utility/scheduling/TaskDecoratorDelay.cpp @@ -0,0 +1,49 @@ +#include "utility/scheduling/TaskDecoratorDelay.h" + +#include + +TaskDecoratorDelay::TaskDecoratorDelay(size_t delayMS) + : m_delayMS(delayMS) + , m_delayComplete(delayMS == 0) +{ +} + +void TaskDecoratorDelay::doEnter(std::shared_ptr blackboard) +{ + m_start = TimePoint::now(); +} + +Task::TaskState TaskDecoratorDelay::doUpdate(std::shared_ptr blackboard) +{ + if (m_delayComplete) + { + return m_taskRunner->update(blackboard); + } + + const int SLEEP_TIME_MS = 25; + std::this_thread::sleep_for(std::chrono::microseconds(SLEEP_TIME_MS)); + + m_delayComplete = (TimePoint::now().deltaMS(m_start) >= m_delayMS); + + return Task::STATE_HOLD; +} + +void TaskDecoratorDelay::doExit(std::shared_ptr blackboard) +{ +} + +void TaskDecoratorDelay::doReset(std::shared_ptr blackboard) +{ + if (m_delayComplete) + { + m_taskRunner->reset(); + } +} + +void TaskDecoratorDelay::doTerminate() +{ + if (m_delayComplete) + { + m_taskRunner->terminate(); + } +} diff --git a/src/lib/utility/scheduling/TaskDecoratorDelay.h b/src/lib/utility/scheduling/TaskDecoratorDelay.h new file mode 100644 index 00000000..b1c2a7d2 --- /dev/null +++ b/src/lib/utility/scheduling/TaskDecoratorDelay.h @@ -0,0 +1,29 @@ +#ifndef TASK_DECORATOR_DELAY_H +#define TASK_DECORATOR_DELAY_H + +#include + +#include "utility/scheduling/TaskDecorator.h" +#include "utility/scheduling/TaskRunner.h" +#include "utility/TimePoint.h" + +class TaskDecoratorDelay + : public TaskDecorator +{ +public: + TaskDecoratorDelay(size_t delayMS); + +private: + virtual void doEnter(std::shared_ptr blackboard); + virtual TaskState doUpdate(std::shared_ptr blackboard); + virtual void doExit(std::shared_ptr blackboard); + virtual void doReset(std::shared_ptr blackboard); + virtual void doTerminate(); + + const size_t m_delayMS; + + TimePoint m_start; + bool m_delayComplete; +}; + +#endif // TASK_DECORATOR_DELAY_H diff --git a/src/lib/utility/scheduling/TaskDecoratorRepeat.cpp b/src/lib/utility/scheduling/TaskDecoratorRepeat.cpp index b165be62..80fb3866 100644 --- a/src/lib/utility/scheduling/TaskDecoratorRepeat.cpp +++ b/src/lib/utility/scheduling/TaskDecoratorRepeat.cpp @@ -6,14 +6,6 @@ TaskDecoratorRepeat::TaskDecoratorRepeat(ConditionType condition, TaskState exit { } -void TaskDecoratorRepeat::setTask(std::shared_ptr task) -{ - if (task) - { - m_taskRunner = std::make_shared(task); - } -} - void TaskDecoratorRepeat::doEnter(std::shared_ptr blackboard) { } @@ -48,8 +40,3 @@ void TaskDecoratorRepeat::doReset(std::shared_ptr blackboard) { m_taskRunner->reset(); } - -void TaskDecoratorRepeat::doTerminate() -{ - m_taskRunner->terminate(); -} diff --git a/src/lib/utility/scheduling/TaskDecoratorRepeat.h b/src/lib/utility/scheduling/TaskDecoratorRepeat.h index 7fdc7ba8..bda0668c 100644 --- a/src/lib/utility/scheduling/TaskDecoratorRepeat.h +++ b/src/lib/utility/scheduling/TaskDecoratorRepeat.h @@ -17,16 +17,12 @@ public: TaskDecoratorRepeat(ConditionType condition, TaskState exitState); - virtual void setTask(std::shared_ptr task); - private: virtual void doEnter(std::shared_ptr blackboard); virtual TaskState doUpdate(std::shared_ptr blackboard); virtual void doExit(std::shared_ptr blackboard); virtual void doReset(std::shared_ptr blackboard); - virtual void doTerminate(); - std::shared_ptr m_taskRunner; const ConditionType m_condition; const TaskState m_exitState; }; diff --git a/src/lib/utility/scheduling/TaskGroupParallel.cpp b/src/lib/utility/scheduling/TaskGroupParallel.cpp index e07fc553..0c0fb9d1 100644 --- a/src/lib/utility/scheduling/TaskGroupParallel.cpp +++ b/src/lib/utility/scheduling/TaskGroupParallel.cpp @@ -105,7 +105,7 @@ void TaskGroupParallel::processTaskThreaded( { TaskState state = taskInfo->taskRunner->update(blackboard); - if (state != STATE_RUNNING) + if (state == STATE_SUCCESS || state == STATE_FAILURE) { if (state == STATE_FAILURE) { diff --git a/src/lib/utility/scheduling/TaskGroupSelector.cpp b/src/lib/utility/scheduling/TaskGroupSelector.cpp index 8fdd292f..3ee5537e 100644 --- a/src/lib/utility/scheduling/TaskGroupSelector.cpp +++ b/src/lib/utility/scheduling/TaskGroupSelector.cpp @@ -39,6 +39,10 @@ Task::TaskState TaskGroupSelector::doUpdate(std::shared_ptr blackboa { m_taskIndex = -1; } + else if (state == STATE_HOLD) + { + return STATE_HOLD; + } return STATE_RUNNING; } diff --git a/src/lib/utility/scheduling/TaskGroupSequence.cpp b/src/lib/utility/scheduling/TaskGroupSequence.cpp index f406e49c..7d255678 100644 --- a/src/lib/utility/scheduling/TaskGroupSequence.cpp +++ b/src/lib/utility/scheduling/TaskGroupSequence.cpp @@ -39,6 +39,10 @@ Task::TaskState TaskGroupSequence::doUpdate(std::shared_ptr blackboa { m_taskIndex = -1; } + else if (state == STATE_HOLD) + { + return STATE_HOLD; + } return STATE_RUNNING; } diff --git a/src/lib/utility/scheduling/TaskScheduler.cpp b/src/lib/utility/scheduling/TaskScheduler.cpp index 6b7cb335..5b45f7a4 100644 --- a/src/lib/utility/scheduling/TaskScheduler.cpp +++ b/src/lib/utility/scheduling/TaskScheduler.cpp @@ -146,6 +146,7 @@ void TaskScheduler::processTasks() while (m_taskRunners.size()) { std::shared_ptr runner = m_taskRunners.front(); + Task::TaskState state = Task::STATE_RUNNING; { m_tasksMutex.unlock(); @@ -166,7 +167,8 @@ void TaskScheduler::processTasks() } } - if (runner->update(blackboard) != Task::STATE_RUNNING) + state = runner->update(blackboard); + if (state != Task::STATE_RUNNING) { break; } @@ -174,6 +176,11 @@ void TaskScheduler::processTasks() } m_taskRunners.pop_front(); + + if (state == Task::STATE_HOLD) + { + m_taskRunners.push_back(runner); + } } m_terminateRunningTasks = false; diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index 7e7be9de..ab6833d0 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -256,6 +256,112 @@ namespace utility return ret; } + std::string breakSignature( + std::string returnPart, std::string namePart, std::string paramPart, + size_t maxLineLength, size_t tabWidth) + { + namePart = ' ' + namePart; + + size_t totalSize = returnPart.size() + namePart.size() + paramPart.size(); + if (totalSize <= maxLineLength) + { + return returnPart + namePart + paramPart; + } + + if (paramPart.size()) + { + namePart += paramPart[0]; + paramPart.erase(0, 1); + } + + size_t parenPos = paramPart.rfind(')'); + std::string endPart; + if (parenPos == 0) + { + namePart += paramPart; + paramPart = ""; + } + else if (parenPos != std::string::npos) + { + endPart = paramPart.substr(parenPos); + paramPart = paramPart.substr(0, parenPos); + } + + if (paramPart.size() && paramPart.size() + tabWidth - endPart.size() > maxLineLength) + { + std::vector paramLines; + while (true) + { + size_t parenCount = 0; + bool split = false; + for (size_t i = 0; i < paramPart.size(); i++) + { + char c = paramPart[i]; + if (parenCount == 0 && c == ',') + { + paramLines.push_back(paramPart.substr(0, i + 1)); + paramPart = paramPart.substr(i + 2); + split = true; + break; + } + else if (c == '<' || c == '(') + { + parenCount++; + } + else if (c == '>' || c == ')') + { + parenCount--; + } + } + + if (!split) + { + paramLines.push_back(paramPart); + break; + } + } + + paramPart = ""; + for (std::string str : paramLines) + { + paramPart += "\n\t" + str; + size_t length = tabWidth + str.size(); + maxLineLength = std::max(length, maxLineLength); + } + } + else if (paramPart.size()) + { + paramPart = "\n\t" + paramPart; + } + + if (returnPart.size() + namePart.size() <= maxLineLength) + { + namePart = returnPart + namePart; + returnPart = ""; + } + + std::string sig; + + if (returnPart.size()) + { + sig += returnPart + '\n'; + } + + sig += namePart; + + if (paramPart.size()) + { + sig += paramPart; + } + + if (endPart.size()) + { + sig += '\n' + endPart; + } + + return sig; + } + std::string trim(const std::string &str) { auto wsfront = std::find_if_not(str.begin(), str.end(), [](int c){ return std::isspace(c); }); diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 8c22598a..f948705f 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -47,6 +47,9 @@ namespace utility std::string replace(std::string str, const std::string& from, const std::string& to); std::string insertLineBreaksAtBlankSpaces(const std::string& s, size_t maxLineLength); + std::string breakSignature( + std::string returnPart, std::string namePart, std::string paramPart, + size_t maxLineLength, size_t tabWidth); std::string trim(const std::string &str); diff --git a/src/lib_cxx/data/indexer/IndexerCommandCxx.cpp b/src/lib_cxx/data/indexer/IndexerCommandCxx.cpp index c90e034a..a4c69b5e 100644 --- a/src/lib_cxx/data/indexer/IndexerCommandCxx.cpp +++ b/src/lib_cxx/data/indexer/IndexerCommandCxx.cpp @@ -13,8 +13,8 @@ IndexerCommandCxx::IndexerCommandCxx( , m_systemHeaderSearchPaths(systemHeaderSearchPaths) , m_frameworkSearchPaths(frameworkSearchPaths) , m_compilerFlags(compilerFlags) - , m_preprocessorOnly(false) , m_shouldApplyAnonymousTypedefTransformation(shouldApplyAnonymousTypedefTransformation) + , m_preprocessorOnly(false) { } diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp b/src/lib_cxx/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp index 4489cb06..b73c2e17 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp @@ -54,7 +54,6 @@ std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang case clang::TemplateArgument::Pack: { std::string typeName = "<"; - argument.getPackAsArray(); llvm::ArrayRef pack = argument.getPackAsArray(); for (size_t i = 0; i < pack.size(); i++) { diff --git a/src/lib_gui/CMakeLists.txt b/src/lib_gui/CMakeLists.txt index 9f829755..34d22df6 100644 --- a/src/lib_gui/CMakeLists.txt +++ b/src/lib_gui/CMakeLists.txt @@ -14,6 +14,8 @@ add_files( qt/element/QtBookmarkCategory.h qt/element/QtCodeArea.cpp qt/element/QtCodeArea.h + qt/element/QtCodeField.cpp + qt/element/QtCodeField.h qt/element/QtCodeFile.cpp qt/element/QtCodeFile.h qt/element/QtCodeFileList.cpp @@ -54,6 +56,8 @@ add_files( qt/element/QtStatusBar.h qt/element/QtTable.cpp qt/element/QtTable.h + qt/element/QtTooltip.cpp + qt/element/QtTooltip.h qt/element/QtUndoRedo.cpp qt/element/QtUndoRedo.h @@ -143,6 +147,8 @@ add_files( qt/view/QtStatusView.h qt/view/QtTabbedView.cpp qt/view/QtTabbedView.h + qt/view/QtTooltipView.cpp + qt/view/QtTooltipView.h qt/view/QtUndoRedoView.cpp qt/view/QtUndoRedoView.h qt/view/QtViewFactory.cpp diff --git a/src/lib_gui/qt/element/QtCodeArea.cpp b/src/lib_gui/qt/element/QtCodeArea.cpp index d0be046f..f6c478dd 100644 --- a/src/lib_gui/qt/element/QtCodeArea.cpp +++ b/src/lib_gui/qt/element/QtCodeArea.cpp @@ -12,6 +12,7 @@ #include #include +#include "data/location/SourceLocationFile.h" #include "utility/messaging/type/MessageActivateLocalSymbols.h" #include "utility/messaging/type/MessageActivateSourceLocations.h" #include "utility/messaging/type/MessageActivateTokenIds.h" @@ -21,16 +22,10 @@ #include "utility/messaging/type/MessageShowErrors.h" #include "utility/utility.h" -#include "data/location/SourceLocation.h" -#include "data/location/SourceLocationFile.h" #include "qt/element/QtCodeNavigator.h" #include "qt/utility/QtContextMenu.h" -#include "qt/utility/QtHighlighter.h" -#include "settings/ApplicationSettings.h" #include "settings/ColorScheme.h" -std::vector QtCodeArea::s_annotationColors; - MouseWheelOverScrollbarFilter::MouseWheelOverScrollbarFilter() { } @@ -76,11 +71,6 @@ void QtCodeArea::LineNumberArea::paintEvent(QPaintEvent *event) m_codeArea->lineNumberAreaPaintEvent(event); } -void QtCodeArea::clearAnnotationColors() -{ - s_annotationColors.clear(); -} - QtCodeArea::QtCodeArea( uint startLineNumber, const std::string& code, @@ -88,11 +78,8 @@ QtCodeArea::QtCodeArea( QtCodeNavigator* navigator, QWidget* parent ) - : QPlainTextEdit(parent) + : QtCodeField(startLineNumber, code, locationFile, parent) , m_navigator(navigator) - , m_startLineNumber(startLineNumber) - , m_code(code) - , m_locationFile(locationFile) , m_digits(0) , m_isSelecting(false) , m_isPanning(false) @@ -100,53 +87,22 @@ QtCodeArea::QtCodeArea( , m_eventPosition(0, 0) , m_isActiveFile(false) , m_lineNumbersHidden(false) - , m_wasAnnotated(false) - , m_endTextEditPosition(0) { - setObjectName("code_area"); - setReadOnly(true); - setFrameStyle(QFrame::NoFrame); - setLineWrapMode(QPlainTextEdit::NoWrap); setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - viewport()->setCursor(Qt::ArrowCursor); - m_lineNumberArea = new LineNumberArea(this); - std::string displayCode = m_code; - if (!displayCode.empty() && *displayCode.rbegin() == '\n') - { - displayCode.pop_back(); - } - - setPlainText(QString::fromUtf8(displayCode.c_str())); - createLineLengthCache(); - m_digits = lineNumberDigits(); updateLineNumberAreaWidth(); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - this->setMouseTracking(true); - // MouseWheelOverScrollbarFilter is deleted by parent. horizontalScrollBar()->installEventFilter(new MouseWheelOverScrollbarFilter()); m_scrollSpeedChangeListener.setScrollBar(horizontalScrollBar()); createActions(); - createAnnotations(locationFile); - - - FilePath path = m_locationFile->getFilePath(); - LanguageType language = LANGUAGE_UNKNOWN; - if (!path.empty()) - { - language = (path.extension() == ".java" ? LANGUAGE_JAVA : LANGUAGE_CPP); - } - - m_highlighter = new QtHighlighter(document(), language); - m_highlighter->highlightDocument(); } QtCodeArea::~QtCodeArea() @@ -160,39 +116,23 @@ QtCodeArea::~QtCodeArea() QSize QtCodeArea::sizeHint() const { - QTextBlock block = document()->firstBlock(); - double height = 0; - double width = lineNumberAreaWidth() + blockBoundingGeometry(block).translated(contentOffset()).left(); + double width = 0; - while (block.isValid()) + for (QTextBlock block = document()->firstBlock(); block.isValid(); block = block.next()) { - height += blockBoundingRect(block).height(); - width = std::max(blockBoundingRect(block).width(), width); - block = block.next(); + QRectF rect = blockBoundingGeometry(block); + height += rect.height(); + width = std::max(rect.width(), width); } + int scrollHeight = 0; if (horizontalScrollBar()->minimum() != horizontalScrollBar()->maximum()) { - height += horizontalScrollBar()->height(); + scrollHeight = horizontalScrollBar()->height(); } - return QSize(width + 1, height + 5); -} - -uint QtCodeArea::getStartLineNumber() const -{ - return m_startLineNumber; -} - -uint QtCodeArea::getEndLineNumber() const -{ - return m_startLineNumber + blockCount() - 1; -} - -std::shared_ptr QtCodeArea::getSourceLocationFile() const -{ - return m_locationFile; + return QSize(width + lineNumberAreaWidth() + 1, height + scrollHeight + 5); } void QtCodeArea::lineNumberAreaPaintEvent(QPaintEvent *event) @@ -218,7 +158,7 @@ void QtCodeArea::lineNumberAreaPaintEvent(QPaintEvent *event) { if (block.isVisible() && bottom >= event->rect().top()) { - int number = blockNumber + m_startLineNumber; + int number = blockNumber + getStartLineNumber(); p.setColor(textColor); @@ -232,7 +172,8 @@ void QtCodeArea::lineNumberAreaPaintEvent(QPaintEvent *event) } painter.setPen(p); - painter.drawText(0, top, m_lineNumberArea->width() - 16, fontMetrics().height(), Qt::AlignRight, QString::number(number)); + painter.drawText( + 0, top, m_lineNumberArea->width() - 16, fontMetrics().height(), Qt::AlignRight, QString::number(number)); } block = block.next(); @@ -244,7 +185,7 @@ void QtCodeArea::lineNumberAreaPaintEvent(QPaintEvent *event) int QtCodeArea::lineNumberDigits() const { - int max = qMax(1, int(m_startLineNumber) + blockCount()); + int max = qMax(1, int(getStartLineNumber()) + blockCount()); return utility::digits(max); } @@ -354,15 +295,10 @@ QRectF QtCodeArea::getLineRectForLineNumber(uint lineNumber) const lineNumber = getEndLineNumber(); } - QTextBlock block = document()->findBlockByLineNumber(lineNumber - m_startLineNumber); + QTextBlock block = document()->findBlockByLineNumber(lineNumber - getStartLineNumber()); return blockBoundingGeometry(block); } -std::string QtCodeArea::getCode() const -{ - return m_code; -} - void QtCodeArea::hideLineNumbers() { m_lineNumberArea->hide(); @@ -377,101 +313,6 @@ void QtCodeArea::resizeEvent(QResizeEvent *e) m_lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); } -void QtCodeArea::showEvent(QShowEvent* event) -{ - int tabWidth = ApplicationSettings::getInstance()->getCodeTabWidth(); - setTabStopWidth(tabWidth * fontMetrics().width('9')); -} - -void QtCodeArea::paintEvent(QPaintEvent* event) -{ - QPainter painter(viewport()); - - QTextBlock block = firstVisibleBlock(); - int top = blockBoundingGeometry(block).translated(contentOffset()).top(); - int bottom = top + blockBoundingRect(block).height(); - int blockHeight = blockBoundingRect(block).height(); - - int firstVisibleLine = -1; - int lastVisibleLine = -1; - while (block.isValid() && top <= event->rect().bottom()) - { - if (block.isVisible()) - { - if (firstVisibleLine < 0 && bottom >= event->rect().top()) - { - firstVisibleLine = block.blockNumber(); - } - lastVisibleLine = block.blockNumber(); - } - - block = block.next(); - top = bottom; - bottom = top + static_cast(blockBoundingRect(block).height()); - } - - std::vector> ranges; - for (size_t i : m_colorChangedAnnotationIndices) - { - Annotation& annotation = m_annotations[i]; - ranges.push_back(std::pair(annotation.start, annotation.end)); - } - - m_highlighter->highlightRange(firstVisibleLine, lastVisibleLine, ranges); - - firstVisibleLine += m_startLineNumber; - lastVisibleLine += m_startLineNumber; - - int borderRadius = 3; - - for (const Annotation& annotation : m_annotations) - { - if (annotation.startLine > lastVisibleLine || annotation.endLine < firstVisibleLine) - { - continue; - } - - const AnnotationColor& color = getAnnotationColorForAnnotation(annotation); - - if (color.border == "transparent" && color.fill == "transparent") - { - continue; - } - - painter.setPen(QPen(color.border.c_str())); - painter.setBrush(QBrush(color.fill.c_str())); - - if (annotation.locationType == LOCATION_SCOPE) - { - painter.drawRoundedRect( - 0, top + (annotation.startLine - m_startLineNumber) * blockHeight, - width(), (annotation.endLine - annotation.startLine + 1) * blockHeight, - borderRadius, borderRadius - ); - } - else - { - std::vector rects = getCursorRectsForAnnotation(annotation); - for (QRect rect : rects) - { - rect.adjust(-1, 0, 1, 1); - painter.drawRoundedRect(rect, borderRadius, borderRadius); - } - } - } - - QPlainTextEdit::paintEvent(event); -} - -void QtCodeArea::enterEvent(QEvent* event) -{ -} - -void QtCodeArea::leaveEvent(QEvent* event) -{ - setHoveredAnnotations(std::vector()); -} - void QtCodeArea::mousePressEvent(QMouseEvent* event) { clearSelection(); @@ -612,10 +453,10 @@ void QtCodeArea::contextMenuEvent(QContextMenuEvent* event) m_eventPosition = event->pos(); QtContextMenu menu(event, this); - if (!m_locationFile->getFilePath().empty()) + if (!getSourceLocationFile()->getFilePath().empty()) { menu.addSeparator(); - menu.addFileActions(m_locationFile->getFilePath()); + menu.addFileActions(getSourceLocationFile()->getFilePath()); menu.addSeparator(); menu.addAction(m_setIDECursorPositionAction); } @@ -623,6 +464,16 @@ void QtCodeArea::contextMenuEvent(QContextMenuEvent* event) } } +void QtCodeArea::focusTokenIds(const std::vector& tokenIds) +{ + MessageFocusIn(tokenIds, TOOLTIP_ORIGIN_CODE).dispatch(); +} + +void QtCodeArea::defocusTokenIds(const std::vector& tokenIds) +{ + MessageFocusOut(tokenIds).dispatch(); +} + void QtCodeArea::updateLineNumberAreaWidth(int /* newBlockCount */) { setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); @@ -668,24 +519,7 @@ void QtCodeArea::setIDECursorPosition() { std::pair lineColumn = toLineColumn(this->cursorForPosition(m_eventPosition).position()); - MessageMoveIDECursor(m_locationFile->getFilePath().str(), lineColumn.first, lineColumn.second).dispatch(); -} - -std::vector QtCodeArea::getInteractiveAnnotationsForPosition(int pos) const -{ - std::vector annotations; - - for (const Annotation& annotation : m_annotations) - { - const LocationType& type = annotation.locationType; - if ((type == LOCATION_TOKEN || type == LOCATION_LOCAL_SYMBOL || type == LOCATION_ERROR) - && pos >= annotation.start && pos <= annotation.end) - { - annotations.push_back(&annotation); - } - } - - return annotations; + MessageMoveIDECursor(getSourceLocationFile()->getFilePath().str(), lineColumn.first, lineColumn.second).dispatch(); } void QtCodeArea::activateSourceLocations(const std::vector& annotations) @@ -772,215 +606,21 @@ void QtCodeArea::activateErrors(const std::vector& annotation } } -void QtCodeArea::createAnnotations(std::shared_ptr locationFile) -{ - uint endLineNumber = getEndLineNumber(); - std::set locationIds; - - locationFile->forEachSourceLocation( - [&](const SourceLocation* location) - { - if (locationIds.find(location->getLocationId()) != locationIds.end()) - { - return; - } - locationIds.insert(location->getLocationId()); - - Annotation annotation; - - const SourceLocation* startLocation = location->getStartLocation(); - if (!startLocation || startLocation->getLineNumber() < m_startLineNumber) - { - annotation.start = startTextEditPosition(); - annotation.startLine = m_startLineNumber; - annotation.startCol = 0; - } - else if (startLocation->getLineNumber() <= endLineNumber) - { - annotation.start = toTextEditPosition(startLocation->getLineNumber(), startLocation->getColumnNumber() - 1); - annotation.startLine = startLocation->getLineNumber(); - annotation.startCol = startLocation->getColumnNumber() - 1; - } - else - { - return; - } - - const SourceLocation* endLocation = location->getEndLocation(); - if (!endLocation || endLocation->getLineNumber() > endLineNumber) - { - annotation.end = endTextEditPosition(); - annotation.endLine = endLineNumber; - annotation.endCol = m_lineLengths[document()->blockCount() - 1]; - } - else if (endLocation->getLineNumber() >= m_startLineNumber) - { - annotation.end = toTextEditPosition(endLocation->getLineNumber(), endLocation->getColumnNumber()); - annotation.endLine = endLocation->getLineNumber(); - annotation.endCol = endLocation->getColumnNumber(); - } - else - { - return; - } - - annotation.tokenIds.insert(location->getTokenIds().begin(), location->getTokenIds().end()); - annotation.locationId = location->getLocationId(); - annotation.locationType = location->getType(); - - annotation.isActive = false; - annotation.isFocused = false; - - m_annotations.push_back(annotation); - } - ); -} - void QtCodeArea::annotateText() { - const std::set& currentActiveTokenIds = m_navigator->getCurrentActiveTokenIds(); - const std::set& currentActiveLocationIds = m_navigator->getCurrentActiveLocationIds(); + std::set activeSymbolIds = m_navigator->getCurrentActiveTokenIds(); + utility::append(activeSymbolIds, m_navigator->getActiveLocalSymbolIds()); - const std::set& activeTokenIds = m_navigator->getActiveTokenIds(); - const std::set& activeLocalSymbolIds = m_navigator->getActiveLocalSymbolIds(); - const std::set& focusIds = m_navigator->getFocusedTokenIds(); + const std::set& activeLocationIds = m_navigator->getCurrentActiveLocationIds(); - std::vector linesToRehighlight; + std::set focusedSymbolIds = m_navigator->getActiveTokenIds(); + utility::append(focusedSymbolIds, m_navigator->getFocusedTokenIds()); - bool needsUpdate = false; - for (size_t i = 0; i < m_annotations.size(); i++) - { - Annotation& annotation = m_annotations[i]; - - bool wasActive = annotation.isActive; - bool wasFocused = annotation.isFocused; - const AnnotationColor& oldColor = getAnnotationColorForAnnotation(annotation); - - annotation.isActive = ( - utility::shareElement(currentActiveTokenIds, annotation.tokenIds) || - utility::shareElement(activeLocalSymbolIds, annotation.tokenIds) || - currentActiveLocationIds.find(annotation.locationId) != currentActiveLocationIds.end() - ); - - if (!annotation.isActive) - { - annotation.isFocused = ( - utility::shareElement(focusIds, annotation.tokenIds) || - utility::shareElement(activeTokenIds, annotation.tokenIds) - ); - } - - const AnnotationColor& newColor = getAnnotationColorForAnnotation(annotation); - if (newColor.text != oldColor.text || (!m_wasAnnotated && newColor.text != "transparent")) - { - if (newColor.text.size() > 0 && newColor.text != "transparent") - { - if (!annotation.oldTextColor.isValid()) - { - annotation.oldTextColor = m_highlighter->getFormat(annotation.start, annotation.end).foreground().color(); - } - - setTextColorForAnnotation(annotation, QColor(newColor.text.c_str())); - m_colorChangedAnnotationIndices.insert(i); - } - else if (annotation.oldTextColor.isValid()) - { - setTextColorForAnnotation(annotation, annotation.oldTextColor); - annotation.oldTextColor = QColor(); - - m_colorChangedAnnotationIndices.erase(i); - linesToRehighlight.push_back(annotation.startLine - 1); - } - } - - if (wasFocused != annotation.isFocused || wasActive != annotation.isActive) - { - needsUpdate = true; - } - } - - if (linesToRehighlight.size()) - { - m_highlighter->rehighlightLines(linesToRehighlight); - } - - if (m_wasAnnotated && needsUpdate) + bool needsUpdate = QtCodeField::annotateText(activeSymbolIds, activeLocationIds, focusedSymbolIds); + if (needsUpdate) { m_lineNumberArea->update(); - viewport()->update(); } - - m_wasAnnotated = true; -} - -void QtCodeArea::setHoveredAnnotations(const std::vector& annotations) -{ - if (m_hoveredAnnotations.size()) - { - std::vector tokenIds; - for (const Annotation* annotation : m_hoveredAnnotations) - { - tokenIds.insert(tokenIds.end(), annotation->tokenIds.begin(), annotation->tokenIds.end()); - } - - MessageFocusOut(tokenIds).dispatch(); - } - - m_hoveredAnnotations = annotations; - - if (annotations.size()) - { - std::vector tokenIds; - for (const Annotation* annotation : annotations) - { - tokenIds.insert(tokenIds.end(), annotation->tokenIds.begin(), annotation->tokenIds.end()); - } - - MessageFocusIn(tokenIds).dispatch(); - } -} - -int QtCodeArea::toTextEditPosition(int lineNumber, int columnNumber) const -{ - lineNumber -= m_startLineNumber - 1; - int position = 0; - - for (int i = 0; i < lineNumber - 1; i++) - { - position += m_lineLengths[i]; - } - - position += columnNumber; - return position; -} - -std::pair QtCodeArea::toLineColumn(int textEditPosition) const -{ - int lineNumber = m_startLineNumber; - for (int i = 0; i < document()->lineCount(); i++) - { - int nextTextEditPosition = textEditPosition - m_lineLengths[i]; - if (nextTextEditPosition >= 0) - { - textEditPosition = nextTextEditPosition; - lineNumber++; - } - else - { - break; - } - } - return std::make_pair(lineNumber, textEditPosition); -} - -int QtCodeArea::startTextEditPosition() const -{ - return 0; -} - -int QtCodeArea::endTextEditPosition() const -{ - return m_endTextEditPosition; } std::set QtCodeArea::getActiveLineNumbers() const @@ -1001,111 +641,6 @@ std::set QtCodeArea::getActiveLineNumbers() const return activeLineNumbers; } -std::vector QtCodeArea::getCursorRectsForAnnotation(const Annotation& annotation) const -{ - std::vector rects; - - QTextCursor cursor = QTextCursor(document()); - cursor.setPosition(annotation.start); - QRect rectStart = cursorRect(cursor); - QRect rectEnd; - - int line = annotation.startLine; - while (line <= annotation.endLine) - { - if (line == annotation.endLine) - { - // Avoid that annotations at line end span down to first column of the next line. - if (annotation.startLine != annotation.endLine || - m_lineLengths[line - m_startLineNumber] != annotation.endCol) - { - cursor.setPosition(annotation.end); - } - } - else - { - cursor.setPosition(toTextEditPosition(line, m_lineLengths[line - m_startLineNumber] - 1)); - } - - rectEnd = cursorRect(cursor); - rects.push_back(QRect( - rectStart.left(), - rectStart.top(), - rectEnd.right() - rectStart.left(), - rectEnd.bottom() - rectStart.top() - )); - - line++; - - if (int(line - m_startLineNumber) < document()->blockCount()) - { - cursor.setPosition(toTextEditPosition(line, 0)); - rectStart = cursorRect(cursor); - } - } - - return rects; -} - -const QtCodeArea::AnnotationColor& QtCodeArea::getAnnotationColorForAnnotation(const Annotation& annotation) -{ - if (!s_annotationColors.size()) - { - ColorScheme* scheme = ColorScheme::getInstance().get(); - std::vector types = { "token", "local_symbol", "scope", "error", "fulltext" }; - std::vector states = { ColorScheme::NORMAL, ColorScheme::FOCUS, ColorScheme::ACTIVE }; - - for (const std::string& type : types) - { - for (const ColorScheme::ColorState& state : states) - { - AnnotationColor color; - color.border = scheme->getCodeAnnotationTypeColor(type, "border", state); - color.fill = scheme->getCodeAnnotationTypeColor(type, "fill", state); - color.text = scheme->getCodeAnnotationTypeColor(type, "text", state); - s_annotationColors.push_back(color); - } - } - } - - size_t i = 0; - - if (annotation.locationType == LOCATION_LOCAL_SYMBOL) - { - i = 3; - } - else if (annotation.locationType == LOCATION_SCOPE) - { - i = 6; - } - else if (annotation.locationType == LOCATION_ERROR) - { - i = 9; - } - else if (annotation.locationType == LOCATION_FULLTEXT) - { - i = 12; - } - - if (annotation.isActive) - { - i += 2; - } - else if (annotation.isFocused) - { - i += 1; - } - - return s_annotationColors[i]; -} - -void QtCodeArea::setTextColorForAnnotation(Annotation& annotation, QColor color) const -{ - QTextCharFormat format; - format.setForeground(color); - m_highlighter->applyFormat(annotation.start, annotation.end, format); -} - void QtCodeArea::createActions() { m_setIDECursorPositionAction = new QAction(tr("Set IDE Cursor"), this); @@ -1113,16 +648,3 @@ void QtCodeArea::createActions() m_setIDECursorPositionAction->setToolTip(tr("Set the IDE Cursor to this code position")); connect(m_setIDECursorPositionAction, SIGNAL(triggered()), this, SLOT(setIDECursorPosition())); } - -void QtCodeArea::createLineLengthCache() -{ - m_endTextEditPosition = -1; - - m_lineLengths.clear(); - - for (QTextBlock it = document()->begin(); it != document()->end(); it = it.next()) - { - m_lineLengths.push_back(it.length()); - m_endTextEditPosition += it.length(); - } -} diff --git a/src/lib_gui/qt/element/QtCodeArea.h b/src/lib_gui/qt/element/QtCodeArea.h index 8ce21c64..a26266bb 100644 --- a/src/lib_gui/qt/element/QtCodeArea.h +++ b/src/lib_gui/qt/element/QtCodeArea.h @@ -2,25 +2,17 @@ #define QT_CODE_AREA_H #include -#include #include -#include - -#include "data/location/LocationType.h" +#include "qt/element/QtCodeField.h" #include "qt/utility/QtScrollSpeedChangeListener.h" -#include "utility/types.h" class QDragMoveEvent; class QPaintEvent; class QResizeEvent; class QSize; class QtCodeNavigator; -class QtHighlighter; class QWidget; -class SourceLocation; -class SourceLocationFile; - class MouseWheelOverScrollbarFilter : public QObject @@ -36,7 +28,7 @@ protected: class QtCodeArea - : public QPlainTextEdit + : public QtCodeField { Q_OBJECT @@ -57,8 +49,6 @@ public: QtCodeArea* m_codeArea; }; - static void clearAnnotationColors(); - QtCodeArea( uint startLineNumber, const std::string& code, @@ -70,11 +60,6 @@ public: virtual QSize sizeHint() const Q_DECL_OVERRIDE; - uint getStartLineNumber() const; - uint getEndLineNumber() const; - - std::shared_ptr getSourceLocationFile() const; - void lineNumberAreaPaintEvent(QPaintEvent* event); int lineNumberDigits() const; int lineNumberAreaWidth() const; @@ -94,16 +79,10 @@ public: QRectF getLineRectForLineNumber(uint lineNumber) const; - std::string getCode() const; - void hideLineNumbers(); protected: virtual void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE; - virtual void showEvent(QShowEvent* event) Q_DECL_OVERRIDE; - virtual void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE; - virtual void enterEvent(QEvent* event) Q_DECL_OVERRIDE; - virtual void leaveEvent(QEvent* event) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE; virtual void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE; @@ -111,6 +90,9 @@ protected: virtual void contextMenuEvent(QContextMenuEvent* event) Q_DECL_OVERRIDE; + virtual void focusTokenIds(const std::vector& tokenIds) override; + virtual void defocusTokenIds(const std::vector& tokenIds) override; + private slots: void updateLineNumberAreaWidth(int newBlockCount = 0); void updateLineNumberArea(const QRect&, int); @@ -119,76 +101,18 @@ private slots: void setIDECursorPosition(); private: - struct Annotation - { - int startLine; - int endLine; - - int startCol; - int endCol; - - int start; - int end; - - std::set tokenIds; - Id locationId; - - LocationType locationType; - - bool isActive; - bool isFocused; - - QColor oldTextColor; - }; - - struct AnnotationColor - { - std::string border; - std::string fill; - std::string text; - }; - - std::vector getInteractiveAnnotationsForPosition(int pos) const; void activateSourceLocations(const std::vector& annotations); void activateLocalSymbols(const std::vector& annotations); void activateErrors(const std::vector& annotations); - void createAnnotations(std::shared_ptr locationFile); void annotateText(); - void setHoveredAnnotations(const std::vector& annotations); - - int toTextEditPosition(int lineNumber, int columnNumber) const; - std::pair toLineColumn(int textEditPosition) const; - int startTextEditPosition() const; - int endTextEditPosition() const; - std::set getActiveLineNumbers() const; - std::vector getCursorRectsForAnnotation(const Annotation& annotation) const; - const AnnotationColor& getAnnotationColorForAnnotation(const Annotation& annotation); - void setTextColorForAnnotation(Annotation& annotation, QColor color) const; - void createActions(); - void createLineLengthCache(); - - static std::vector s_annotationColors; - QtCodeNavigator* m_navigator; - QWidget* m_lineNumberArea; - QtHighlighter* m_highlighter; - - const uint m_startLineNumber; - const std::string m_code; - - std::shared_ptr m_locationFile; - - std::vector m_annotations; - std::vector m_hoveredAnnotations; - - std::set m_colorChangedAnnotationIndices; int m_digits; @@ -203,10 +127,6 @@ private: bool m_isActiveFile; bool m_lineNumbersHidden; - bool m_wasAnnotated; - - std::vector m_lineLengths; - int m_endTextEditPosition; QtScrollSpeedChangeListener m_scrollSpeedChangeListener; }; diff --git a/src/lib_gui/qt/element/QtCodeField.cpp b/src/lib_gui/qt/element/QtCodeField.cpp new file mode 100644 index 00000000..89b49a99 --- /dev/null +++ b/src/lib_gui/qt/element/QtCodeField.cpp @@ -0,0 +1,613 @@ +#include "QtCodeField.h" + +#include +#include + +#include "data/location/SourceLocation.h" +#include "data/location/SourceLocationFile.h" +#include "qt/utility/QtHighlighter.h" +#include "settings/ApplicationSettings.h" +#include "settings/ColorScheme.h" +#include "utility/messaging/type/MessageActivateTokenIds.h" +#include "utility/utility.h" + +std::vector QtCodeField::s_annotationColors; + +void QtCodeField::clearAnnotationColors() +{ + s_annotationColors.clear(); +} + +QtCodeField::QtCodeField( + uint startLineNumber, + const std::string& code, + std::shared_ptr locationFile, + QWidget* parent +) + : QPlainTextEdit(parent) + , m_startLineNumber(startLineNumber) + , m_code(code) + , m_locationFile(locationFile) + , m_endTextEditPosition(0) + , m_wasAnnotated(false) +{ + setObjectName("code_area"); + setReadOnly(true); + setFrameStyle(QFrame::NoFrame); + setLineWrapMode(QPlainTextEdit::NoWrap); + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + + viewport()->setCursor(Qt::ArrowCursor); + + std::string displayCode = m_code; + if (!displayCode.empty() && *displayCode.rbegin() == '\n') + { + displayCode.pop_back(); + } + + setPlainText(QString::fromUtf8(displayCode.c_str())); + createLineLengthCache(); + + this->setMouseTracking(true); + + createAnnotations(locationFile); + + FilePath path = m_locationFile->getFilePath(); + LanguageType language = LANGUAGE_UNKNOWN; + if (!path.empty()) + { + language = (path.extension() == ".java" ? LANGUAGE_JAVA : LANGUAGE_CPP); + } + + m_highlighter = new QtHighlighter(document(), language); + m_highlighter->highlightDocument(); + + ApplicationSettings* appSettings = ApplicationSettings::getInstance().get(); + setFont(QFont(appSettings->getFontName().c_str(), appSettings->getFontSize())); + setTabStopWidth(appSettings->getCodeTabWidth() * fontMetrics().width('9')); +} + +QtCodeField::~QtCodeField() +{ +} + +QSize QtCodeField::sizeHint() const +{ + double height = 0; + int width = 0; + + QFontMetrics fm = fontMetrics(); + int maxTextSize = 0; + for (QTextBlock block = document()->firstBlock(); block.isValid(); block = block.next()) + { + QRectF rect = blockBoundingGeometry(block); + height += rect.height(); + + { + int blockWidth = fm.boundingRect( + 0, 0, 1000000, 1000000, + Qt::AlignLeft | Qt::AlignTop | Qt::TextExpandTabs, block.text(), tabStopWidth()).width(); + + width = std::max(blockWidth, width); + maxTextSize = block.text().size(); + } + } + + return QSize(width + 1, height + 5); +} + +uint QtCodeField::getStartLineNumber() const +{ + return m_startLineNumber; +} + +uint QtCodeField::getEndLineNumber() const +{ + return m_startLineNumber + blockCount() - 1; +} + +std::string QtCodeField::getCode() const +{ + return m_code; +} + +std::shared_ptr QtCodeField::getSourceLocationFile() const +{ + return m_locationFile; +} + +void QtCodeField::annotateText() +{ + annotateText(std::set(), std::set(), std::set()); +} + +void QtCodeField::paintEvent(QPaintEvent* event) +{ + QPainter painter(viewport()); + + QTextBlock block = firstVisibleBlock(); + int top = blockBoundingGeometry(block).translated(contentOffset()).top(); + int bottom = top + blockBoundingRect(block).height(); + int blockHeight = blockBoundingRect(block).height(); + + int firstVisibleLine = -1; + int lastVisibleLine = -1; + while (block.isValid() && top <= event->rect().bottom()) + { + if (block.isVisible()) + { + if (firstVisibleLine < 0 && bottom >= event->rect().top()) + { + firstVisibleLine = block.blockNumber(); + } + lastVisibleLine = block.blockNumber(); + } + + block = block.next(); + top = bottom; + bottom = top + static_cast(blockBoundingRect(block).height()); + } + + std::vector> ranges; + for (size_t i : m_colorChangedAnnotationIndices) + { + Annotation& annotation = m_annotations[i]; + ranges.push_back(std::pair(annotation.start, annotation.end)); + } + + m_highlighter->highlightRange(firstVisibleLine, lastVisibleLine, ranges); + + firstVisibleLine += m_startLineNumber; + lastVisibleLine += m_startLineNumber; + + int borderRadius = 3; + + for (const Annotation& annotation : m_annotations) + { + if (annotation.startLine > lastVisibleLine || annotation.endLine < firstVisibleLine) + { + continue; + } + + const AnnotationColor& color = getAnnotationColorForAnnotation(annotation); + + if (color.border == "transparent" && color.fill == "transparent") + { + continue; + } + + painter.setPen(QPen(color.border.c_str())); + painter.setBrush(QBrush(color.fill.c_str())); + + if (annotation.locationType == LOCATION_SCOPE) + { + painter.drawRoundedRect( + 0, top + (annotation.startLine - m_startLineNumber) * blockHeight, + width(), (annotation.endLine - annotation.startLine + 1) * blockHeight, + borderRadius, borderRadius + ); + } + else + { + std::vector rects = getCursorRectsForAnnotation(annotation); + for (QRect rect : rects) + { + rect.adjust(-1, 0, 1, 1); + painter.drawRoundedRect(rect, borderRadius, borderRadius); + } + } + } + + QPlainTextEdit::paintEvent(event); +} + +void QtCodeField::enterEvent(QEvent* event) +{ +} + +void QtCodeField::leaveEvent(QEvent* event) +{ + setHoveredAnnotations(std::vector()); +} + +void QtCodeField::mouseMoveEvent(QMouseEvent* event) +{ + QTextCursor cursor = this->cursorForPosition(event->pos()); + std::vector annotations = getInteractiveAnnotationsForPosition(cursor.position()); + + bool same = annotations.size() == m_hoveredAnnotations.size(); + if (same) + { + for (size_t i = 0; i < annotations.size(); i++) + { + if (annotations[i] != m_hoveredAnnotations[i]) + { + same = false; + break; + } + } + } + + if (!same) + { + setHoveredAnnotations(annotations); + } +} + +void QtCodeField::mouseReleaseEvent(QMouseEvent* event) +{ + if (event->button() != Qt::LeftButton) + { + return; + } + + viewport()->setCursor(Qt::ArrowCursor); + + QTextCursor cursor = this->cursorForPosition(event->pos()); + std::vector annotations = getInteractiveAnnotationsForPosition(cursor.position()); + + if (!annotations.size()) + { + return; + } + + std::set tokenIds; + for (const Annotation* annotation : annotations) + { + tokenIds.insert(annotation->tokenIds.begin(), annotation->tokenIds.end()); + } + + if (tokenIds.size()) + { + MessageActivateTokenIds(utility::toVector(tokenIds)).dispatch(); + } +} + +void QtCodeField::focusTokenIds(const std::vector& tokenIds) +{ + annotateText(std::set(), std::set(), std::set(tokenIds.begin(), tokenIds.end())); +} + +void QtCodeField::defocusTokenIds(const std::vector& tokenIds) +{ + annotateText(std::set(), std::set(), std::set()); +} + +bool QtCodeField::annotateText( + const std::set& activeSymbolIds, const std::set& activeLocationIds, const std::set& focusedSymbolIds) +{ + std::vector linesToRehighlight; + + bool needsUpdate = false; + for (size_t i = 0; i < m_annotations.size(); i++) + { + Annotation& annotation = m_annotations[i]; + + bool wasActive = annotation.isActive; + bool wasFocused = annotation.isFocused; + const AnnotationColor& oldColor = getAnnotationColorForAnnotation(annotation); + + annotation.isActive = ( + utility::shareElement(activeSymbolIds, annotation.tokenIds) || + activeLocationIds.find(annotation.locationId) != activeLocationIds.end() + ); + + if (!annotation.isActive) + { + annotation.isFocused = utility::shareElement(focusedSymbolIds, annotation.tokenIds); + } + + const AnnotationColor& newColor = getAnnotationColorForAnnotation(annotation); + if (newColor.text != oldColor.text || (!m_wasAnnotated && newColor.text != "transparent")) + { + if (newColor.text.size() > 0 && newColor.text != "transparent") + { + if (!annotation.oldTextColor.isValid()) + { + annotation.oldTextColor = + m_highlighter->getFormat(annotation.start, annotation.end).foreground().color(); + } + + setTextColorForAnnotation(annotation, QColor(newColor.text.c_str())); + m_colorChangedAnnotationIndices.insert(i); + } + else if (annotation.oldTextColor.isValid()) + { + setTextColorForAnnotation(annotation, annotation.oldTextColor); + annotation.oldTextColor = QColor(); + + m_colorChangedAnnotationIndices.erase(i); + linesToRehighlight.push_back(annotation.startLine - 1); + } + } + + if (wasFocused != annotation.isFocused || wasActive != annotation.isActive) + { + needsUpdate = true; + } + } + + if (linesToRehighlight.size()) + { + m_highlighter->rehighlightLines(linesToRehighlight); + } + + needsUpdate = (needsUpdate && m_wasAnnotated); + if (needsUpdate) + { + viewport()->update(); + } + + m_wasAnnotated = true; + + return needsUpdate; +} + +void QtCodeField::createAnnotations(std::shared_ptr locationFile) +{ + uint endLineNumber = getEndLineNumber(); + std::set locationIds; + + locationFile->forEachSourceLocation( + [&](const SourceLocation* location) + { + if (locationIds.find(location->getLocationId()) != locationIds.end()) + { + return; + } + locationIds.insert(location->getLocationId()); + + Annotation annotation; + + const SourceLocation* startLocation = location->getStartLocation(); + if (!startLocation || startLocation->getLineNumber() < m_startLineNumber) + { + annotation.start = startTextEditPosition(); + annotation.startLine = m_startLineNumber; + annotation.startCol = 0; + } + else if (startLocation->getLineNumber() <= endLineNumber) + { + annotation.start = toTextEditPosition(startLocation->getLineNumber(), startLocation->getColumnNumber() - 1); + annotation.startLine = startLocation->getLineNumber(); + annotation.startCol = startLocation->getColumnNumber() - 1; + } + else + { + return; + } + + const SourceLocation* endLocation = location->getEndLocation(); + if (!endLocation || endLocation->getLineNumber() > endLineNumber) + { + annotation.end = endTextEditPosition(); + annotation.endLine = endLineNumber; + annotation.endCol = m_lineLengths[document()->blockCount() - 1]; + } + else if (endLocation->getLineNumber() >= m_startLineNumber) + { + annotation.end = toTextEditPosition(endLocation->getLineNumber(), endLocation->getColumnNumber()); + annotation.endLine = endLocation->getLineNumber(); + annotation.endCol = endLocation->getColumnNumber(); + } + else + { + return; + } + + annotation.tokenIds.insert(location->getTokenIds().begin(), location->getTokenIds().end()); + annotation.locationId = location->getLocationId(); + annotation.locationType = location->getType(); + + annotation.isActive = false; + annotation.isFocused = false; + + m_annotations.push_back(annotation); + } + ); +} + +int QtCodeField::toTextEditPosition(int lineNumber, int columnNumber) const +{ + lineNumber -= m_startLineNumber - 1; + int position = 0; + + for (int i = 0; i < lineNumber - 1; i++) + { + position += m_lineLengths[i]; + } + + position += columnNumber; + return position; +} + +std::pair QtCodeField::toLineColumn(int textEditPosition) const +{ + int lineNumber = m_startLineNumber; + for (int i = 0; i < document()->lineCount(); i++) + { + int nextTextEditPosition = textEditPosition - m_lineLengths[i]; + if (nextTextEditPosition >= 0) + { + textEditPosition = nextTextEditPosition; + lineNumber++; + } + else + { + break; + } + } + return std::make_pair(lineNumber, textEditPosition); +} + +int QtCodeField::startTextEditPosition() const +{ + return 0; +} + +int QtCodeField::endTextEditPosition() const +{ + return m_endTextEditPosition; +} + +void QtCodeField::setHoveredAnnotations(const std::vector& annotations) +{ + if (m_hoveredAnnotations.size()) + { + std::vector tokenIds; + for (const Annotation* annotation : m_hoveredAnnotations) + { + tokenIds.insert(tokenIds.end(), annotation->tokenIds.begin(), annotation->tokenIds.end()); + } + + defocusTokenIds(tokenIds); + } + + m_hoveredAnnotations = annotations; + + if (annotations.size()) + { + std::vector tokenIds; + for (const Annotation* annotation : annotations) + { + tokenIds.insert(tokenIds.end(), annotation->tokenIds.begin(), annotation->tokenIds.end()); + } + + focusTokenIds(tokenIds); + } +} + +std::vector QtCodeField::getCursorRectsForAnnotation(const Annotation& annotation) const +{ + std::vector rects; + + QTextCursor cursor = QTextCursor(document()); + cursor.setPosition(annotation.start); + QRect rectStart = cursorRect(cursor); + QRect rectEnd; + + int line = annotation.startLine; + while (line <= annotation.endLine) + { + if (line == annotation.endLine) + { + // Avoid that annotations at line end span down to first column of the next line. + if (annotation.startLine != annotation.endLine || + m_lineLengths[line - m_startLineNumber] != annotation.endCol) + { + cursor.setPosition(annotation.end); + } + } + else + { + cursor.setPosition(toTextEditPosition(line, m_lineLengths[line - m_startLineNumber] - 1)); + } + + rectEnd = cursorRect(cursor); + rects.push_back(QRect( + rectStart.left(), + rectStart.top(), + rectEnd.right() - rectStart.left(), + rectEnd.bottom() - rectStart.top() + )); + + line++; + + if (int(line - m_startLineNumber) < document()->blockCount()) + { + cursor.setPosition(toTextEditPosition(line, 0)); + rectStart = cursorRect(cursor); + } + } + + return rects; +} + +const QtCodeField::AnnotationColor& QtCodeField::getAnnotationColorForAnnotation(const Annotation& annotation) +{ + if (!s_annotationColors.size()) + { + ColorScheme* scheme = ColorScheme::getInstance().get(); + std::vector types = { "token", "local_symbol", "scope", "error", "fulltext" }; + std::vector states = { ColorScheme::NORMAL, ColorScheme::FOCUS, ColorScheme::ACTIVE }; + + for (const std::string& type : types) + { + for (const ColorScheme::ColorState& state : states) + { + AnnotationColor color; + color.border = scheme->getCodeAnnotationTypeColor(type, "border", state); + color.fill = scheme->getCodeAnnotationTypeColor(type, "fill", state); + color.text = scheme->getCodeAnnotationTypeColor(type, "text", state); + s_annotationColors.push_back(color); + } + } + } + + size_t i = 0; + + if (annotation.locationType == LOCATION_LOCAL_SYMBOL) + { + i = 3; + } + else if (annotation.locationType == LOCATION_SCOPE) + { + i = 6; + } + else if (annotation.locationType == LOCATION_ERROR) + { + i = 9; + } + else if (annotation.locationType == LOCATION_FULLTEXT) + { + i = 12; + } + + if (annotation.isActive) + { + i += 2; + } + else if (annotation.isFocused) + { + i += 1; + } + + return s_annotationColors[i]; +} + +void QtCodeField::setTextColorForAnnotation(Annotation& annotation, QColor color) const +{ + QTextCharFormat format; + format.setForeground(color); + m_highlighter->applyFormat(annotation.start, annotation.end, format); +} + +std::vector QtCodeField::getInteractiveAnnotationsForPosition(int pos) const +{ + std::vector annotations; + + for (const Annotation& annotation : m_annotations) + { + const LocationType& type = annotation.locationType; + if ((type == LOCATION_TOKEN || type == LOCATION_LOCAL_SYMBOL || type == LOCATION_ERROR) + && pos >= annotation.start && pos <= annotation.end) + { + annotations.push_back(&annotation); + } + } + + return annotations; +} + +void QtCodeField::createLineLengthCache() +{ + m_endTextEditPosition = -1; + + m_lineLengths.clear(); + + for (QTextBlock it = document()->begin(); it != document()->end(); it = it.next()) + { + m_lineLengths.push_back(it.length()); + m_endTextEditPosition += it.length(); + } +} diff --git a/src/lib_gui/qt/element/QtCodeField.h b/src/lib_gui/qt/element/QtCodeField.h new file mode 100644 index 00000000..d9142a30 --- /dev/null +++ b/src/lib_gui/qt/element/QtCodeField.h @@ -0,0 +1,122 @@ +#ifndef QT_CODE_FIELD_H +#define QT_CODE_FIELD_H + +#include + +#include + +#include "data/location/LocationType.h" +#include "utility/types.h" + +class QtHighlighter; +class SourceLocation; +class SourceLocationFile; + +class QtCodeField + : public QPlainTextEdit +{ + Q_OBJECT + +public: + static void clearAnnotationColors(); + + QtCodeField( + uint startLineNumber, + const std::string& code, + std::shared_ptr locationFile, + QWidget* parent = nullptr); + ~QtCodeField(); + + virtual QSize sizeHint() const Q_DECL_OVERRIDE; + + uint getStartLineNumber() const; + uint getEndLineNumber() const; + + std::string getCode() const; + + std::shared_ptr getSourceLocationFile() const; + + void annotateText(); + +protected: + virtual void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE; + virtual void enterEvent(QEvent* event) Q_DECL_OVERRIDE; + virtual void leaveEvent(QEvent* event) Q_DECL_OVERRIDE; + + virtual void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE; + virtual void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE; + + virtual void focusTokenIds(const std::vector& tokenIds); + virtual void defocusTokenIds(const std::vector& tokenIds); + + struct Annotation + { + int startLine; + int endLine; + + int startCol; + int endCol; + + int start; + int end; + + std::set tokenIds; + Id locationId; + + LocationType locationType; + + bool isActive; + bool isFocused; + + QColor oldTextColor; + }; + + struct AnnotationColor + { + std::string border; + std::string fill; + std::string text; + }; + + bool annotateText( + const std::set& activeSymbolIds, const std::set& activeLocationIds, const std::set& focusedSymbolIds); + + void createAnnotations(std::shared_ptr locationFile); + + int toTextEditPosition(int lineNumber, int columnNumber) const; + std::pair toLineColumn(int textEditPosition) const; + + int startTextEditPosition() const; + int endTextEditPosition() const; + + void setHoveredAnnotations(const std::vector& annotations); + std::vector getCursorRectsForAnnotation(const Annotation& annotation) const; + + const AnnotationColor& getAnnotationColorForAnnotation(const Annotation& annotation); + void setTextColorForAnnotation(Annotation& annotation, QColor color) const; + + std::vector getInteractiveAnnotationsForPosition(int pos) const; + + std::vector m_annotations; + std::vector m_hoveredAnnotations; + +private: + static std::vector s_annotationColors; + + void createLineLengthCache(); + + const uint m_startLineNumber; + const std::string m_code; + + std::shared_ptr m_locationFile; + + QtHighlighter* m_highlighter; + + std::vector m_lineLengths; + std::set m_colorChangedAnnotationIndices; + + int m_endTextEditPosition; + bool m_wasAnnotated; +}; + +#endif // QT_CODE_FIELD_H diff --git a/src/lib_gui/qt/element/QtCodeNavigator.cpp b/src/lib_gui/qt/element/QtCodeNavigator.cpp index 39ce2799..e30a84fd 100644 --- a/src/lib_gui/qt/element/QtCodeNavigator.cpp +++ b/src/lib_gui/qt/element/QtCodeNavigator.cpp @@ -876,10 +876,13 @@ void QtCodeNavigator::handleMessage(MessageSwitchColorScheme* message) void QtCodeNavigator::handleMessage(MessageWindowFocus* message) { - m_onQtThread( - [=]() - { - m_current->onWindowFocus(); - } - ); + if (message->focusIn) + { + m_onQtThread( + [=]() + { + m_current->onWindowFocus(); + } + ); + } } diff --git a/src/lib_gui/qt/element/QtTooltip.cpp b/src/lib_gui/qt/element/QtTooltip.cpp new file mode 100644 index 00000000..cd47fb1e --- /dev/null +++ b/src/lib_gui/qt/element/QtTooltip.cpp @@ -0,0 +1,179 @@ +#include "qt/element/QtTooltip.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "data/location/SourceLocationFile.h" +#include "data/tooltip/TooltipInfo.h" +#include "qt/element/QtCodeField.h" + +QtTooltip::QtTooltip(QWidget* parent) + : QFrame(parent) + , m_parentView(nullptr) + , m_isHovered(false) +{ + QWidget::setWindowFlags(Qt::ToolTip); + setObjectName("tooltip"); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + setLayout(layout); +} + +QtTooltip::~QtTooltip() +{ +} + +void QtTooltip::setTooltipInfo(TooltipInfo info) +{ + if (info.title.size()) + { + addTitle(info.title.c_str(), info.count, info.countText.c_str()); + } + + for (TooltipSnippet snippet : info.snippets) + { + QtCodeField* field = new QtCodeField(1, snippet.code, snippet.locationFile); + + QSize size = field->sizeHint() + QSize(15, 5); + if (size.width() > 600) + { + field->setMinimumSize(QSize(600, size.height() + QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent))); + } + else + { + field->setMinimumSize(size); + field->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + } + + field->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + field->annotateText(); + + addWidget(field); + } + + m_offset = QPoint(info.offset.x(), info.offset.y()); +} + +void QtTooltip::setParentView(QWidget* parentView) +{ + m_parentView = parentView; +} + +bool QtTooltip::isHovered() const +{ + return m_isHovered; +} + +void QtTooltip::show() +{ + QWidget* parent = m_parentView ? m_parentView : parentWidget(); + if (!parent) + { + return; + } + + QWidget::show(); + + QPoint pos = QCursor::pos() + m_offset; + + if (pos.x() + width() > parent->pos().x() + parent->width()) + { + pos.setX(pos.x() - width() - m_offset.x() * 2); + } + + if (pos.x() < parent->pos().x()) + { + pos.setX(parent->pos().x() + 10); + } + + + if (pos.y() + height() > parent->pos().y() + parent->height()) + { + pos.setY(pos.y() - height() - m_offset.y() * 2); + } + + if (pos.y() < parent->pos().y()) + { + pos.setY(parent->pos().y() + 10); + } + + move(pos); +} + +void QtTooltip::hide(bool force) +{ + if (!m_isHovered || force) + { + QWidget::hide(); + + clearLayout(layout()); + m_parentView = nullptr; + m_offset = QPoint(); + } +} + +void QtTooltip::leaveEvent(QEvent *event) +{ + m_isHovered = false; + + QTimer::singleShot(500, this, SLOT(hide())); +} + +void QtTooltip::enterEvent(QEvent *event) +{ + m_isHovered = true; +} + +void QtTooltip::addTitle(QString title, int count, QString countText) +{ + QHBoxLayout* titleLayout = new QHBoxLayout(); + titleLayout->setContentsMargins(0, 0, 0, 0); + titleLayout->setSpacing(0); + + QLabel* titleLabel = new QLabel(title); + titleLabel->setObjectName("tooltip_title"); + titleLayout->addWidget(titleLabel); + + if (count >= 0) + { + QLabel* referenceLabel = new QLabel(QString::number(count) + " " + countText + (count != 1 ? "s" : "")); + referenceLabel->setObjectName("tooltip_references"); + + titleLayout->addWidget(referenceLabel, 0, Qt::AlignRight); + } + + QWidget* titleWidget = new QWidget(); + titleWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + titleWidget->setLayout(titleLayout); + + layout()->addWidget(titleWidget); +} + +void QtTooltip::addWidget(QWidget *widget) +{ + widget->setObjectName("tooltip_widget"); + layout()->addWidget(widget); +} + +void QtTooltip::clearLayout(QLayout* layout) +{ + while (QLayoutItem* item = layout->takeAt(0)) + { + if (QWidget* widget = item->widget()) + { + widget->deleteLater(); + } + if (QLayout* childLayout = item->layout()) + { + clearLayout(childLayout); + } + delete item; + } +} diff --git a/src/lib_gui/qt/element/QtTooltip.h b/src/lib_gui/qt/element/QtTooltip.h new file mode 100644 index 00000000..09efbd66 --- /dev/null +++ b/src/lib_gui/qt/element/QtTooltip.h @@ -0,0 +1,43 @@ +#ifndef QT_TOOLTIP_H +#define QT_TOOLTIP_H + +#include + +struct TooltipInfo; + +class QtTooltip + : public QFrame +{ + Q_OBJECT + +public: + QtTooltip(QWidget* parent = nullptr); + virtual ~QtTooltip(); + + void setTooltipInfo(TooltipInfo info); + + void setParentView(QWidget* parentView); + + bool isHovered() const; + +public slots: + virtual void show(); + virtual void hide(bool force = false); + +protected: + virtual void leaveEvent(QEvent* event); + virtual void enterEvent(QEvent* event); + +private: + void addTitle(QString title, int count, QString countText); + void addWidget(QWidget* widget); + + void clearLayout(QLayout* layout); + + QWidget* m_parentView; + QPoint m_offset; + + bool m_isHovered; +}; + +#endif // QT_TOOLTIP_H diff --git a/src/lib_gui/qt/view/QtMainView.cpp b/src/lib_gui/qt/view/QtMainView.cpp index 2f803a5e..178a2f5a 100644 --- a/src/lib_gui/qt/view/QtMainView.cpp +++ b/src/lib_gui/qt/view/QtMainView.cpp @@ -55,6 +55,11 @@ void QtMainView::hideView(View* view) ); } +View* QtMainView::findFloatingView(const std::string& name) const +{ + return m_window->findFloatingView(name); +} + void QtMainView::loadLayout() { m_window->loadLayout(); diff --git a/src/lib_gui/qt/view/QtMainView.h b/src/lib_gui/qt/view/QtMainView.h index 9dddec8b..12872fd3 100644 --- a/src/lib_gui/qt/view/QtMainView.h +++ b/src/lib_gui/qt/view/QtMainView.h @@ -38,6 +38,8 @@ public: virtual void showView(View* view); virtual void hideView(View* view); + virtual View* findFloatingView(const std::string& name) const; + virtual QStatusBar* getStatusBar(); virtual void setStatusBar(QStatusBar* statusBar); diff --git a/src/lib_gui/qt/view/QtTooltipView.cpp b/src/lib_gui/qt/view/QtTooltipView.cpp new file mode 100644 index 00000000..90d9efd4 --- /dev/null +++ b/src/lib_gui/qt/view/QtTooltipView.cpp @@ -0,0 +1,77 @@ +#include "qt/view/QtTooltipView.h" + +#include "qt/element/QtTooltip.h" +#include "qt/utility/utilityQt.h" +#include "qt/view/QtMainView.h" +#include "qt/view/QtViewWidgetWrapper.h" +#include "qt/window/QtMainWindow.h" +#include "settings/ColorScheme.h" +#include "utility/ResourcePaths.h" + +QtTooltipView::QtTooltipView(ViewLayout* viewLayout) + : TooltipView(viewLayout) +{ + m_widget = new QtTooltip(dynamic_cast(getViewLayout())->getMainWindow()); +} + +QtTooltipView::~QtTooltipView() +{ +} + +void QtTooltipView::createWidgetWrapper() +{ + setWidgetWrapper(std::make_shared(m_widget)); +} + +void QtTooltipView::initView() +{ +} + +void QtTooltipView::refreshView() +{ + m_onQtThread([=]() + { + setStyleSheet(); + }); +} + +void QtTooltipView::showTooltip(TooltipInfo info, const View* parent) +{ + m_onQtThread([=]() + { + if (m_widget->isHovered()) + { + return; + } + + m_widget->hide(); + m_widget->setTooltipInfo(info); + + if (parent) + { + m_widget->setParentView(QtViewWidgetWrapper::getWidgetOfView(parent)->parentWidget()); + } + + m_widget->show(); + }); +} + +void QtTooltipView::hideTooltip(bool force) +{ + m_onQtThread([=]() + { + m_widget->hide(force); + }); +} + +bool QtTooltipView::tooltipVisible() const +{ + return m_widget->isVisible(); +} + +void QtTooltipView::setStyleSheet() +{ + m_widget->setStyleSheet( + utility::getStyleSheet(ResourcePaths::getGuiPath().concat(FilePath("tooltip_view/tooltip.css"))).c_str() + ); +} diff --git a/src/lib_gui/qt/view/QtTooltipView.h b/src/lib_gui/qt/view/QtTooltipView.h new file mode 100644 index 00000000..a324ed70 --- /dev/null +++ b/src/lib_gui/qt/view/QtTooltipView.h @@ -0,0 +1,36 @@ +#ifndef QT_TOOLTIP_VIEW +#define QT_TOOLTIP_VIEW + +#include "component/view/TooltipView.h" +#include "qt/utility/QtThreadedFunctor.h" + +class QTimer; +class QtTooltip; + +class QtTooltipView + : public TooltipView +{ +public: + QtTooltipView(ViewLayout* viewLayout); + ~QtTooltipView(); + + // View implementation + virtual void createWidgetWrapper(); + virtual void initView(); + virtual void refreshView(); + + virtual void showTooltip(TooltipInfo info, const View* parent); + virtual void hideTooltip(bool force); + + virtual bool tooltipVisible() const; + +private: + void setStyleSheet(); + void doRefreshView(); + + QtThreadedLambdaFunctor m_onQtThread; + + QtTooltip* m_widget; +}; + +#endif // QT_TOOLTIP_VIEW diff --git a/src/lib_gui/qt/view/QtViewFactory.cpp b/src/lib_gui/qt/view/QtViewFactory.cpp index cb84a37e..958a70aa 100644 --- a/src/lib_gui/qt/view/QtViewFactory.cpp +++ b/src/lib_gui/qt/view/QtViewFactory.cpp @@ -15,6 +15,7 @@ #include "qt/view/QtStatusBarView.h" #include "qt/view/QtStatusView.h" #include "qt/view/QtTabbedView.h" +#include "qt/view/QtTooltipView.h" #include "qt/view/QtUndoRedoView.h" QtViewFactory::QtViewFactory() @@ -93,6 +94,11 @@ std::shared_ptr QtViewFactory::createStatusBarView(ViewLayout* vi return View::createAndInit(viewLayout); } +std::shared_ptr QtViewFactory::createTooltipView(ViewLayout* viewLayout) const +{ + return View::createAndInit(viewLayout); +} + std::shared_ptr QtViewFactory::createUndoRedoView(ViewLayout* viewLayout) const { return View::createInitAndAddToLayout(viewLayout); diff --git a/src/lib_gui/qt/view/QtViewFactory.h b/src/lib_gui/qt/view/QtViewFactory.h index 343d35c1..d1f13777 100644 --- a/src/lib_gui/qt/view/QtViewFactory.h +++ b/src/lib_gui/qt/view/QtViewFactory.h @@ -23,6 +23,7 @@ public: virtual std::shared_ptr createSearchView(ViewLayout* viewLayout) const; virtual std::shared_ptr createStatusBarView(ViewLayout* viewLayout) const; virtual std::shared_ptr createStatusView(ViewLayout* viewLayout) const; + virtual std::shared_ptr createTooltipView(ViewLayout* viewLayout) const; virtual std::shared_ptr createUndoRedoView(ViewLayout* viewLayout) const; virtual std::shared_ptr createDialogView(ViewLayout* viewLayout, StorageAccess* storageAccess) const; diff --git a/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp b/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp index e181bfb9..0561a09a 100644 --- a/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp +++ b/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp @@ -16,8 +16,11 @@ #include "utility/messaging/type/MessageFocusIn.h" #include "utility/messaging/type/MessageFocusOut.h" #include "utility/messaging/type/MessageGraphNodeBundleSplit.h" +#include "utility/messaging/type/MessageTooltipShow.h" +#include "utility/messaging/type/MessageTooltipHide.h" #include "utility/utility.h" +QtGraphEdge* QtGraphEdge::s_focusedEdge = nullptr; QtGraphEdge* QtGraphEdge::s_focusedBezierEdge = nullptr; QtGraphEdge::QtGraphEdge( @@ -52,6 +55,7 @@ QtGraphEdge::QtGraphEdge( m_fromActive = m_owner.lock()->getIsActive(); m_toActive = m_target.lock()->getIsActive(); + s_focusedEdge = nullptr; s_focusedBezierEdge = nullptr; } @@ -85,26 +89,7 @@ void QtGraphEdge::updateLine() return; } - Edge::EdgeType type; - if (getData()) - { - type = getData()->getType(); - } - else - { - type = Edge::EDGE_AGGREGATION; - } - - QString toolTip = Edge::getReadableTypeString(type).c_str(); - if (type == Edge::EDGE_AGGREGATION) - { - toolTip += ": " + QString::number(m_weight) + " edge"; - if (m_weight != 1) - { - toolTip += "s"; - } - } - + Edge::EdgeType type = (getData() ? getData()->getType() : Edge::EDGE_AGGREGATION); GraphViewStyle::EdgeStyle style = GraphViewStyle::getStyleForEdgeType(type, m_isActive | m_isFocused, false, m_isTrailEdge); if (m_useBezier) @@ -130,10 +115,8 @@ void QtGraphEdge::updateLine() bezier->updateLine(ownerRect, rect, ownerParentRect, rect, style, m_weight, false); bezier->setRoute(route); bezier->setPivot(QtLineItemBase::PIVOT_MIDDLE); - bezier->setToolTip(toolTip); QtLineItemStraight* line = new QtLineItemStraight(this); - line->setToolTip(toolTip); if (route == QtLineItemBase::ROUTE_HORIZONTAL) { line->updateLine(Vec2i(rect.x(), (rect.y() + rect.w()) / 2), Vec2i(rect.z(), (rect.y() + rect.w()) / 2), style); @@ -155,7 +138,6 @@ void QtGraphEdge::updateLine() style, m_weight, showArrow); bezier->setRoute(route); bezier->setPivot(QtLineItemBase::PIVOT_MIDDLE); - bezier->setToolTip(toolTip); if (owner->getLastParent() == target->getLastParent()) { @@ -221,8 +203,6 @@ void QtGraphEdge::updateLine() owner->getBoundingRect(), target->getBoundingRect(), owner->getParentBoundingRect(), target->getParentBoundingRect(), style, m_weight, showArrow); - - child->setToolTip(toolTip); } this->setZValue(style.zValue); @@ -301,6 +281,22 @@ void QtGraphEdge::focusIn() { m_isFocused = true; updateLine(); + + if (s_focusedEdge == this) + { + Edge::EdgeType type = (getData() ? getData()->getType() : Edge::EDGE_AGGREGATION); + + TooltipInfo info; + info.title = Edge::getReadableTypeString(type); + if (type == Edge::EDGE_AGGREGATION) + { + info.count = m_weight; + info.countText = "edge"; + } + info.offset = Vec2i(10, 20); + + MessageTooltipShow(info, TOOLTIP_ORIGIN_GRAPH).dispatch(); + } } } @@ -310,6 +306,11 @@ void QtGraphEdge::focusOut() { m_isFocused = false; updateLine(); + + if (s_focusedEdge == this) + { + MessageTooltipHide().dispatch(); + } } } @@ -349,9 +350,11 @@ void QtGraphEdge::hoverEnterEvent(QGraphicsSceneHoverEvent* event) s_focusedBezierEdge = this; } + s_focusedEdge = this; + if (getData() && !m_useBezier) { - MessageFocusIn(std::vector(1, getData()->getId())).dispatch(); + MessageFocusIn(std::vector(1, getData()->getId()), TOOLTIP_ORIGIN_GRAPH).dispatch(); } else { @@ -371,6 +374,8 @@ void QtGraphEdge::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { focusOut(); } + + s_focusedEdge = nullptr; } void QtGraphEdge::setDirection(TokenComponentAggregation::Direction direction) diff --git a/src/lib_gui/qt/view/graphElements/QtGraphEdge.h b/src/lib_gui/qt/view/graphElements/QtGraphEdge.h index 0b0de5e8..92a52687 100644 --- a/src/lib_gui/qt/view/graphElements/QtGraphEdge.h +++ b/src/lib_gui/qt/view/graphElements/QtGraphEdge.h @@ -64,6 +64,9 @@ protected: virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); private: + // used to send tooltip message on focusIn(), because both focus messages are filtered out if sent close together + static QtGraphEdge* s_focusedEdge; + // used to unfocus recent edge, because hover leave event is not always received for bezier edges static QtGraphEdge* s_focusedBezierEdge; diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp b/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp index 1dada754..07d7fb21 100644 --- a/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp +++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp @@ -8,7 +8,6 @@ #include "utility/messaging/type/MessageGraphNodeMove.h" #include "data/graph/token_component/TokenComponentFilePath.h" -#include "data/graph/token_component/TokenComponentSignature.h" QtGraphNodeData::QtGraphNodeData(const Node* data, const std::string& name, bool hasParent, bool childVisible, bool hasQualifier) : m_data(data) @@ -18,39 +17,6 @@ QtGraphNodeData::QtGraphNodeData(const Node* data, const std::string& name, bool this->setAcceptHoverEvents(true); this->setName(name); - - std::string toolTip = data->getReadableTypeString(); - if (!data->isDefined() && data->isType(Node::NODE_FILE)) - { - toolTip = "incomplete " + toolTip; - } - else if (!data->isDefined() && !data->isType(Node::NODE_NON_INDEXED)) - { - toolTip = "non-indexed " + toolTip; - } - else if (data->isImplicit()) - { - toolTip = "implicit " + toolTip; - } - - if (data->isType(Node::NODE_FUNCTION | Node::NODE_METHOD)) - { - TokenComponentSignature* sig = data->getComponent(); - if (sig) - { - toolTip += ": " + sig->getSignature(); - } - } - else - { - FilePath path = getFilePath(); - if (!path.empty()) - { - toolTip += ": " + path.str(); - } - } - - this->setToolTip(QString::fromStdString(toolTip)); } QtGraphNodeData::~QtGraphNodeData() @@ -113,7 +79,7 @@ void QtGraphNodeData::updateStyle() void QtGraphNodeData::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { - MessageFocusIn(std::vector(1, m_data->getId())).dispatch(); + MessageFocusIn(std::vector(1, m_data->getId()), TOOLTIP_ORIGIN_GRAPH).dispatch(); } void QtGraphNodeData::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) diff --git a/src/lib_gui/qt/window/QtMainWindow.cpp b/src/lib_gui/qt/window/QtMainWindow.cpp index d3a2f6ce..eb277e65 100644 --- a/src/lib_gui/qt/window/QtMainWindow.cpp +++ b/src/lib_gui/qt/window/QtMainWindow.cpp @@ -200,6 +200,19 @@ void QtMainWindow::hideView(View* view) getDockWidgetForView(view)->widget->setHidden(true); } +View* QtMainWindow::findFloatingView(const std::string& name) const +{ + for (size_t i = 0; i < m_dockWidgets.size(); i++) + { + if (std::string(m_dockWidgets[i].view->getName()) == name && m_dockWidgets[i].widget->isFloating()) + { + return m_dockWidgets[i].view; + } + } + + return nullptr; +} + void QtMainWindow::loadLayout() { QSettings settings(UserPaths::getWindowSettingsPath().str().c_str(), QSettings::IniFormat); @@ -337,7 +350,11 @@ bool QtMainWindow::event(QEvent* event) { if (event->type() == QEvent::WindowActivate) { - MessageWindowFocus().dispatch(); + MessageWindowFocus(true).dispatch(); + } + else if (event->type() == QEvent::WindowDeactivate) + { + MessageWindowFocus(false).dispatch(); } return QMainWindow::event(event); diff --git a/src/lib_gui/qt/window/QtMainWindow.h b/src/lib_gui/qt/window/QtMainWindow.h index 53fb55f4..a7c8e867 100644 --- a/src/lib_gui/qt/window/QtMainWindow.h +++ b/src/lib_gui/qt/window/QtMainWindow.h @@ -63,6 +63,8 @@ public: void showView(View* view); void hideView(View* view); + View* findFloatingView(const std::string& name) const; + void loadLayout(); void saveLayout(); diff --git a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.h b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.h index 51158307..5ff0da1d 100644 --- a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.h +++ b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.h @@ -107,7 +107,7 @@ public: std::shared_ptr settings, QtProjectWizzardWindow* window, bool isCDB = false); // QtProjectWizzardContent implementation - virtual void populate(QGridLayout* layout, int& row); + virtual void populate(QGridLayout* layout, int& row) override; virtual void load() override; virtual void save() override; virtual bool isScrollAble() const override;