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
This commit is contained in:
+1
-1
@@ -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 ---------------------------------------------------------------------
|
||||
|
||||
@@ -172,8 +172,6 @@
|
||||
#code_area {
|
||||
background-color: transparent;
|
||||
color: <color:code/snippet/syntax/normal>;
|
||||
font-family: "<setting:font_name>";
|
||||
font-size: <setting:font_size>px;
|
||||
selection-color: <color:code/snippet/selection/text>;
|
||||
selection-background-color: <color:code/snippet/selection/background>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#tooltip {
|
||||
background-color: <color:code/file/background>;
|
||||
border: 1px solid <color:code/file/background>;
|
||||
}
|
||||
|
||||
#tooltip_title {
|
||||
color: <color:code/file/title/text>;
|
||||
padding: 3px;
|
||||
font-size: <setting:font_size>px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#tooltip_references {
|
||||
background-color: <color:code/file/ref_count/background>;
|
||||
color: <color:code/file/ref_count/text>;
|
||||
margin: 4px;
|
||||
padding: 3px 5px;
|
||||
border-radius: 8px;
|
||||
font-size: <setting:font_size-2>px;
|
||||
}
|
||||
|
||||
#tooltip_widget {
|
||||
background-color: <color:code/snippet/background>;
|
||||
padding: 3px;
|
||||
color: <color:code/snippet/syntax/normal>;
|
||||
}
|
||||
+8
-2
@@ -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"
|
||||
|
||||
+14
-5
@@ -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
|
||||
|
||||
@@ -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<Component> ComponentFactory::createActivationComponent()
|
||||
return std::make_shared<Component>(nullptr, controller);
|
||||
}
|
||||
|
||||
std::shared_ptr<Component> ComponentFactory::createTooltipComponent(ViewLayout* viewLayout)
|
||||
{
|
||||
std::shared_ptr<TooltipView> view = m_viewFactory->createTooltipView(viewLayout);
|
||||
std::shared_ptr<Controller> controller = std::make_shared<TooltipController>(m_storageAccess);
|
||||
|
||||
return std::make_shared<Component>(view, controller);
|
||||
}
|
||||
|
||||
std::shared_ptr<Component> ComponentFactory::createBookmarkComponent(ViewLayout* viewLayout)
|
||||
{
|
||||
std::shared_ptr<BookmarkView> view = m_viewFactory->createBookmarkView(viewLayout);
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
std::shared_ptr<Component> createSearchComponent(ViewLayout* viewLayout);
|
||||
std::shared_ptr<Component> createStatusBarComponent(ViewLayout* viewLayout);
|
||||
std::shared_ptr<Component> createStatusComponent(ViewLayout* viewLayout);
|
||||
std::shared_ptr<Component> createTooltipComponent(ViewLayout* viewLayout);
|
||||
std::shared_ptr<Component> createUndoRedoComponent(ViewLayout* viewLayout);
|
||||
|
||||
private:
|
||||
|
||||
@@ -51,6 +51,9 @@ void ComponentManager::setup(ViewLayout* viewLayout)
|
||||
std::shared_ptr<Component> activationComponent = m_componentFactory->createActivationComponent();
|
||||
m_components.push_back(activationComponent);
|
||||
|
||||
std::shared_ptr<Component> tooltipComponent = m_componentFactory->createTooltipComponent(viewLayout);
|
||||
m_components.push_back(tooltipComponent);
|
||||
|
||||
m_dialogView = m_componentFactory->getViewFactory()->createDialogView(viewLayout, m_componentFactory->getStorageAccess());
|
||||
|
||||
std::shared_ptr<TabbedView> tabbedView =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Id>(), message->tooltipInfo, message->origin);
|
||||
}
|
||||
|
||||
void TooltipController::handleMessage(MessageWindowFocus* message)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
TooltipView* TooltipController::getView() const
|
||||
{
|
||||
return Controller::getView<TooltipView>();
|
||||
}
|
||||
|
||||
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<Id> tokenIds, TooltipInfo info, TooltipOrigin origin)
|
||||
{
|
||||
Id requestId = TooltipRequest::s_requestId++;
|
||||
|
||||
m_showRequest = std::make_unique<TooltipRequest>();
|
||||
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<TaskDecoratorDelay>(delayMS)->addChildTask(
|
||||
std::make_shared<TaskLambda>(
|
||||
[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<TaskDecoratorDelay>(500)->addChildTask(
|
||||
std::make_shared<TaskLambda>(
|
||||
[this]()
|
||||
{
|
||||
if (m_hideRequest)
|
||||
{
|
||||
m_hideRequest = false;
|
||||
|
||||
getView()->hideTooltip(false);
|
||||
}
|
||||
}
|
||||
)
|
||||
));
|
||||
}
|
||||
@@ -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<MessageActivateTokens>
|
||||
, public MessageListener<MessageFocusIn>
|
||||
, public MessageListener<MessageFocusOut>
|
||||
, public MessageListener<MessageGraphNodeExpand>
|
||||
, public MessageListener<MessageTooltipHide>
|
||||
, public MessageListener<MessageTooltipShow>
|
||||
, public MessageListener<MessageWindowFocus>
|
||||
{
|
||||
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<Id> tokenIds;
|
||||
|
||||
TooltipInfo info;
|
||||
TooltipOrigin origin;
|
||||
};
|
||||
|
||||
TooltipView* getView() const;
|
||||
View* getViewForOrigin(TooltipOrigin origin) const;
|
||||
|
||||
void requestTooltipShow(const std::vector<Id> tokenIds, TooltipInfo info, TooltipOrigin origin);
|
||||
void requestTooltipHide();
|
||||
|
||||
StorageAccess* m_storageAccess;
|
||||
|
||||
std::unique_ptr<TooltipRequest> m_showRequest;
|
||||
bool m_hideRequest;
|
||||
};
|
||||
|
||||
#endif // TOOLTIP_CONTROLLER_H
|
||||
@@ -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()
|
||||
|
||||
@@ -16,6 +16,8 @@ class CodeView
|
||||
: public View
|
||||
{
|
||||
public:
|
||||
static const char* VIEW_NAME;
|
||||
|
||||
enum FileState
|
||||
{
|
||||
FILE_MINIMIZED,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ class GraphView
|
||||
: public View
|
||||
{
|
||||
public:
|
||||
static const char* VIEW_NAME;
|
||||
|
||||
struct GraphParams
|
||||
{
|
||||
bool animatedTransition;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "component/view/TooltipView.h"
|
||||
|
||||
TooltipView::TooltipView(ViewLayout* viewLayout)
|
||||
: View(viewLayout)
|
||||
{
|
||||
}
|
||||
|
||||
TooltipView::~TooltipView()
|
||||
{
|
||||
}
|
||||
|
||||
std::string TooltipView::getName() const
|
||||
{
|
||||
return "TooltipView";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef TOOLTIP_VIEW_H
|
||||
#define TOOLTIP_VIEW_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
@@ -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<SearchView> createSearchView(ViewLayout* viewLayout) const = 0;
|
||||
virtual std::shared_ptr<StatusBarView> createStatusBarView(ViewLayout* viewLayout) const = 0;
|
||||
virtual std::shared_ptr<StatusView> createStatusView(ViewLayout* viewLayout) const = 0;
|
||||
virtual std::shared_ptr<TooltipView> createTooltipView(ViewLayout* viewLayout) const = 0;
|
||||
virtual std::shared_ptr<UndoRedoView> createUndoRedoView(ViewLayout* viewLayout) const = 0;
|
||||
|
||||
virtual std::shared_ptr<DialogView> createDialogView(ViewLayout* viewLayout, StorageAccess* storageAccess) const = 0;
|
||||
|
||||
@@ -7,3 +7,8 @@ ViewLayout::ViewLayout()
|
||||
ViewLayout::~ViewLayout()
|
||||
{
|
||||
}
|
||||
|
||||
View* ViewLayout::findFloatingView(const std::string& name) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef VIEW_LAYOUT_H
|
||||
#define VIEW_LAYOUT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
||||
|
||||
@@ -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<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const = 0;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id id) const = 0;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const = 0;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id>& 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<NodeBookmark> getAllNodeBookmarks() const = 0;
|
||||
virtual std::vector<EdgeBookmark> getAllEdgeBookmarks() const = 0;
|
||||
|
||||
virtual std::vector<BookmarkCategory> getAllBookmarkCategories() const = 0;
|
||||
|
||||
virtual TooltipInfo getTooltipInfoForTokenIds(const std::vector<Id>& tokenIds, TooltipOrigin origin) const = 0;
|
||||
|
||||
protected:
|
||||
ErrorFilter m_errorFilter;
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ NameHierarchy StorageAccessProxy::getNameHierarchyForNodeId(Id id) const
|
||||
return NameHierarchy(NAME_DELIMITER_UNKNOWN);
|
||||
}
|
||||
|
||||
std::vector<NameHierarchy> StorageAccessProxy::getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const
|
||||
std::vector<NameHierarchy> StorageAccessProxy::getNameHierarchiesForNodeIds(const std::vector<Id>& nodeIds) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
@@ -415,6 +415,16 @@ std::vector<BookmarkCategory> StorageAccessProxy::getAllBookmarkCategories() con
|
||||
return std::vector<BookmarkCategory>();
|
||||
}
|
||||
|
||||
TooltipInfo StorageAccessProxy::getTooltipInfoForTokenIds(const std::vector<Id>& tokenIds, TooltipOrigin origin) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getTooltipInfoForTokenIds(tokenIds, origin);
|
||||
}
|
||||
|
||||
return TooltipInfo();
|
||||
}
|
||||
|
||||
void StorageAccessProxy::setErrorFilter(const ErrorFilter& filter)
|
||||
{
|
||||
StorageAccess::setErrorFilter(filter);
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id id) const;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id>& 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<NodeBookmark> getAllNodeBookmarks() const;
|
||||
virtual std::vector<EdgeBookmark> getAllEdgeBookmarks() const;
|
||||
|
||||
virtual std::vector<BookmarkCategory> getAllBookmarkCategories() const;
|
||||
|
||||
virtual TooltipInfo getTooltipInfoForTokenIds(const std::vector<Id>& tokenIds, TooltipOrigin origin) const;
|
||||
|
||||
protected:
|
||||
virtual void setErrorFilter(const ErrorFilter& filter);
|
||||
|
||||
|
||||
@@ -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<TokenComponentFilePath> componen
|
||||
}
|
||||
}
|
||||
|
||||
void Node::addComponentSignature(std::shared_ptr<TokenComponentSignature> component)
|
||||
{
|
||||
if (getComponent<TokenComponentSignature>())
|
||||
{
|
||||
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<TokenComponentAccess> component)
|
||||
{
|
||||
if (getComponent<TokenComponentAccess>())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<TokenComponent> TokenComponentSignature::copy() const
|
||||
{
|
||||
return std::make_shared<TokenComponentSignature>(*this);
|
||||
}
|
||||
|
||||
const std::string& TokenComponentSignature::getSignature() const
|
||||
{
|
||||
return m_signature;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef TOKEN_COMPONENT_SIGNATURE_H
|
||||
#define TOKEN_COMPONENT_SIGNATURE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "data/graph/token_component/TokenComponent.h"
|
||||
|
||||
class TokenComponentSignature
|
||||
: public TokenComponent
|
||||
{
|
||||
public:
|
||||
TokenComponentSignature(const std::string& signature);
|
||||
virtual ~TokenComponentSignature();
|
||||
|
||||
virtual std::shared_ptr<TokenComponent> copy() const;
|
||||
|
||||
const std::string& getSignature() const;
|
||||
|
||||
private:
|
||||
const std::string m_signature;
|
||||
};
|
||||
|
||||
#endif // TOKEN_COMPONENT_SIGNATURE_H
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
std::string getRawName() const;
|
||||
std::string getRawNameWithSignature() const;
|
||||
|
||||
NameElement::Signature getSignature() const;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<NameElement>> m_elements;
|
||||
NameDelimiterType m_delimiter;
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ACCESS_KIND_H
|
||||
#define ACCESS_KIND_H
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
||||
|
||||
@@ -15,14 +15,6 @@ TaskParseWrapper::~TaskParseWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskParseWrapper::setTask(std::shared_ptr<Task> task)
|
||||
{
|
||||
if (task)
|
||||
{
|
||||
m_taskRunner = std::make_shared<TaskRunner>(task);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskParseWrapper::doEnter(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
int sourceFileCount = 0;
|
||||
@@ -54,8 +46,3 @@ void TaskParseWrapper::doReset(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
m_taskRunner->reset();
|
||||
}
|
||||
|
||||
void TaskParseWrapper::doTerminate()
|
||||
{
|
||||
m_taskRunner->terminate();
|
||||
}
|
||||
|
||||
@@ -19,19 +19,15 @@ public:
|
||||
TaskParseWrapper(PersistentStorage* storage);
|
||||
virtual ~TaskParseWrapper();
|
||||
|
||||
virtual void setTask(std::shared_ptr<Task> task);
|
||||
|
||||
private:
|
||||
virtual void doEnter(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual TaskState doUpdate(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doExit(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doReset(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doTerminate();
|
||||
|
||||
PersistentStorage* m_storage;
|
||||
|
||||
TimePoint m_start;
|
||||
std::shared_ptr<TaskRunner> m_taskRunner;
|
||||
};
|
||||
|
||||
#endif // TASK_PARSE_WRAPPER_H
|
||||
|
||||
@@ -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<NodeBookmark> PersistentStorage::getAllNodeBookmarks() const
|
||||
{
|
||||
std::unordered_map<Id, StorageBookmarkCategory> bookmarkCategories;
|
||||
for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories())
|
||||
{
|
||||
bookmarkCategories[bookmarkCategory.id] = bookmarkCategory;
|
||||
}
|
||||
|
||||
std::unordered_map<Id, std::vector<Id>> bookmarkIdToBookmarkedNodeIds;
|
||||
for (const StorageBookmarkedNode& bookmarkedNode: m_sqliteBookmarkStorage.getAllBookmarkedNodes())
|
||||
{
|
||||
bookmarkIdToBookmarkedNodeIds[bookmarkedNode.bookmarkId].push_back(
|
||||
m_sqliteIndexStorage.getNodeBySerializedName(bookmarkedNode.serializedNodeName).id);
|
||||
}
|
||||
|
||||
std::vector<NodeBookmark> 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<EdgeBookmark> PersistentStorage::getAllEdgeBookmarks() const
|
||||
{
|
||||
std::unordered_map<Id, StorageBookmarkCategory> bookmarkCategories;
|
||||
for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories())
|
||||
{
|
||||
bookmarkCategories[bookmarkCategory.id] = bookmarkCategory;
|
||||
}
|
||||
|
||||
std::unordered_map<Id, std::vector<StorageBookmarkedEdge>> bookmarkIdToBookmarkedEdges;
|
||||
for (const StorageBookmarkedEdge& bookmarkedEdge: m_sqliteBookmarkStorage.getAllBookmarkedEdges())
|
||||
{
|
||||
bookmarkIdToBookmarkedEdges[bookmarkedEdge.bookmarkId].push_back(bookmarkedEdge);
|
||||
}
|
||||
|
||||
std::vector<EdgeBookmark> edgeBookmarks;
|
||||
|
||||
Cache<std::string, Id> 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<BookmarkCategory> PersistentStorage::getAllBookmarkCategories() const
|
||||
{
|
||||
std::vector<BookmarkCategory> categories;
|
||||
for (const StorageBookmarkCategory storageBookmarkCategoriy: m_sqliteBookmarkStorage.getAllBookmarkCategories())
|
||||
{
|
||||
categories.push_back(BookmarkCategory(storageBookmarkCategoriy.id, storageBookmarkCategoriy.name));
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
void PersistentStorage::forEachNode(std::function<void(const StorageNode& /*data*/)> callback) const
|
||||
{
|
||||
for (StorageNode& node: m_sqliteIndexStorage.getAll<StorageNode>())
|
||||
@@ -602,7 +426,7 @@ NameHierarchy PersistentStorage::getNameHierarchyForNodeId(Id nodeId) const
|
||||
return NameHierarchy::deserialize(m_sqliteIndexStorage.getFirstById<StorageNode>(nodeId).serializedName);
|
||||
}
|
||||
|
||||
std::vector<NameHierarchy> PersistentStorage::getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const
|
||||
std::vector<NameHierarchy> PersistentStorage::getNameHierarchiesForNodeIds(const std::vector<Id>& nodeIds) const
|
||||
{
|
||||
TRACE();
|
||||
|
||||
@@ -1564,6 +1388,370 @@ std::shared_ptr<SourceLocationCollection> 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<NodeBookmark> PersistentStorage::getAllNodeBookmarks() const
|
||||
{
|
||||
std::unordered_map<Id, StorageBookmarkCategory> bookmarkCategories;
|
||||
for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories())
|
||||
{
|
||||
bookmarkCategories[bookmarkCategory.id] = bookmarkCategory;
|
||||
}
|
||||
|
||||
std::unordered_map<Id, std::vector<Id>> bookmarkIdToBookmarkedNodeIds;
|
||||
for (const StorageBookmarkedNode& bookmarkedNode: m_sqliteBookmarkStorage.getAllBookmarkedNodes())
|
||||
{
|
||||
bookmarkIdToBookmarkedNodeIds[bookmarkedNode.bookmarkId].push_back(
|
||||
m_sqliteIndexStorage.getNodeBySerializedName(bookmarkedNode.serializedNodeName).id);
|
||||
}
|
||||
|
||||
std::vector<NodeBookmark> 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<EdgeBookmark> PersistentStorage::getAllEdgeBookmarks() const
|
||||
{
|
||||
std::unordered_map<Id, StorageBookmarkCategory> bookmarkCategories;
|
||||
for (const StorageBookmarkCategory& bookmarkCategory: m_sqliteBookmarkStorage.getAllBookmarkCategories())
|
||||
{
|
||||
bookmarkCategories[bookmarkCategory.id] = bookmarkCategory;
|
||||
}
|
||||
|
||||
std::unordered_map<Id, std::vector<StorageBookmarkedEdge>> bookmarkIdToBookmarkedEdges;
|
||||
for (const StorageBookmarkedEdge& bookmarkedEdge: m_sqliteBookmarkStorage.getAllBookmarkedEdges())
|
||||
{
|
||||
bookmarkIdToBookmarkedEdges[bookmarkedEdge.bookmarkId].push_back(bookmarkedEdge);
|
||||
}
|
||||
|
||||
std::vector<EdgeBookmark> edgeBookmarks;
|
||||
|
||||
Cache<std::string, Id> 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<BookmarkCategory> PersistentStorage::getAllBookmarkCategories() const
|
||||
{
|
||||
std::vector<BookmarkCategory> categories;
|
||||
for (const StorageBookmarkCategory storageBookmarkCategoriy: m_sqliteBookmarkStorage.getAllBookmarkCategories())
|
||||
{
|
||||
categories.push_back(BookmarkCategory(storageBookmarkCategoriy.id, storageBookmarkCategoriy.name));
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
TooltipInfo PersistentStorage::getTooltipInfoForTokenIds(const std::vector<Id>& tokenIds, TooltipOrigin origin) const
|
||||
{
|
||||
TRACE();
|
||||
|
||||
TooltipInfo info;
|
||||
|
||||
if (!tokenIds.size())
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
StorageNode node = m_sqliteIndexStorage.getFirstById<StorageNode>(tokenIds[0]);
|
||||
if (node.id == 0 && origin == TOOLTIP_ORIGIN_CODE)
|
||||
{
|
||||
StorageEdge edge = m_sqliteIndexStorage.getFirstById<StorageEdge>(tokenIds[0]);
|
||||
|
||||
if (edge.id > 0)
|
||||
{
|
||||
node = m_sqliteIndexStorage.getFirstById<StorageNode>(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<StorageSymbol>(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<SourceLocationFile>(
|
||||
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<Id> 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<std::pair<std::string, Id>, bool(*)(const std::pair<std::string, Id>&, const std::pair<std::string, Id>&)> typeNames(
|
||||
[](const std::pair<std::string, Id>& a, const std::pair<std::string, Id>& 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<StorageNode>(typeNodeIds))
|
||||
{
|
||||
typeNames.insert(std::make_pair(
|
||||
NameHierarchy::deserialize(typeNode.serializedName).getQualifiedName(),
|
||||
typeNode.id
|
||||
));
|
||||
}
|
||||
|
||||
Id locationId = 1;
|
||||
std::vector<std::pair<size_t, size_t>> 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<Id>(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<Id>(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<Id>& 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<TokenComponentSignature>(signatureString)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (addChildCount)
|
||||
{
|
||||
node->setChildCount(m_hierarchyCache.getFirstNonImplicitChildIdsCountForNodeId(storageNode.id));
|
||||
|
||||
@@ -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<NodeBookmark> getAllNodeBookmarks() const;
|
||||
std::vector<EdgeBookmark> getAllEdgeBookmarks() const;
|
||||
|
||||
|
||||
virtual std::vector<BookmarkCategory> getAllBookmarkCategories() const;
|
||||
|
||||
virtual void forEachNode(std::function<void(const StorageNode& /*data*/)> callback) const;
|
||||
virtual void forEachFile(std::function<void(const StorageFile& /*data*/)> callback) const;
|
||||
@@ -89,7 +75,7 @@ public:
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id nodeId) const;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id>& nodeIds) const;
|
||||
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
||||
|
||||
@@ -138,6 +124,21 @@ public:
|
||||
virtual std::vector<ErrorInfo> getErrorsLimited() const;
|
||||
virtual std::shared_ptr<SourceLocationCollection> getErrorSourceLocationsLimited(std::vector<ErrorInfo>* 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<NodeBookmark> getAllNodeBookmarks() const;
|
||||
virtual std::vector<EdgeBookmark> getAllEdgeBookmarks() const;
|
||||
virtual std::vector<BookmarkCategory> getAllBookmarkCategories() const;
|
||||
|
||||
virtual TooltipInfo getTooltipInfoForTokenIds(const std::vector<Id>& tokenIds, TooltipOrigin origin) const;
|
||||
TooltipSnippet getTooltipSnippetForNode(const StorageNode& node) const;
|
||||
|
||||
private:
|
||||
Id getFileNodeId(const FilePath& filePath) const;
|
||||
std::vector<Id> getFileNodeIds(const std::vector<FilePath>& filePaths) const;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef TOOLTIP_INFO_H
|
||||
#define TOOLTIP_INFO_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "utility/math/Vector2.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class SourceLocationFile;
|
||||
|
||||
struct TooltipSnippet
|
||||
{
|
||||
std::string code;
|
||||
std::shared_ptr<SourceLocationFile> locationFile;
|
||||
};
|
||||
|
||||
struct TooltipInfo
|
||||
{
|
||||
bool isValid() const
|
||||
{
|
||||
return title.size() || snippets.size();
|
||||
}
|
||||
|
||||
std::string title;
|
||||
|
||||
int count = -1;
|
||||
std::string countText;
|
||||
|
||||
std::vector<TooltipSnippet> snippets;
|
||||
|
||||
Vec2i offset;
|
||||
};
|
||||
|
||||
#endif // TOOLTIP_INFO_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
|
||||
@@ -6,12 +6,15 @@
|
||||
#include "utility/messaging/Message.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
#include "data/tooltip/TooltipOrigin.h"
|
||||
|
||||
class MessageFocusIn
|
||||
: public Message<MessageFocusIn>
|
||||
{
|
||||
public:
|
||||
MessageFocusIn(const std::vector<Id>& tokenIds)
|
||||
MessageFocusIn(const std::vector<Id>& tokenIds, TooltipOrigin origin)
|
||||
: tokenIds(tokenIds)
|
||||
, origin(origin)
|
||||
{
|
||||
setIsLogged(false);
|
||||
}
|
||||
@@ -30,6 +33,7 @@ public:
|
||||
}
|
||||
|
||||
const std::vector<Id> tokenIds;
|
||||
const TooltipOrigin origin;
|
||||
};
|
||||
|
||||
#endif //MESSAGE_FOCUS_IN_H
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef MESSAGE_TOOLTIP_HIDE_H
|
||||
#define MESSAGE_TOOLTIP_HIDE_H
|
||||
|
||||
#include "utility/messaging/Message.h"
|
||||
|
||||
class MessageTooltipHide
|
||||
: public Message<MessageTooltipHide>
|
||||
{
|
||||
public:
|
||||
MessageTooltipHide()
|
||||
{
|
||||
setSendAsTask(false);
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageTooltipHide";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MESSAGE_TOOLTIP_HIDE_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<MessageTooltipShow>
|
||||
{
|
||||
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
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
#include "utility/messaging/Message.h"
|
||||
|
||||
class MessageWindowFocus: public Message<MessageWindowFocus>
|
||||
class MessageWindowFocus
|
||||
: public Message<MessageWindowFocus>
|
||||
{
|
||||
public:
|
||||
MessageWindowFocus()
|
||||
MessageWindowFocus(bool focusIn)
|
||||
: focusIn(focusIn)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -14,6 +16,8 @@ public:
|
||||
{
|
||||
return "MessageWindowFocus";
|
||||
}
|
||||
|
||||
const bool focusIn;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_WINDOW_FOCUS_H
|
||||
|
||||
@@ -11,6 +11,7 @@ public:
|
||||
enum TaskState
|
||||
{
|
||||
STATE_RUNNING,
|
||||
STATE_HOLD,
|
||||
STATE_SUCCESS,
|
||||
STATE_FAILURE
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "utility/scheduling/TaskDecorator.h"
|
||||
|
||||
#include "utility/scheduling/TaskRunner.h"
|
||||
|
||||
TaskDecorator::TaskDecorator()
|
||||
{
|
||||
}
|
||||
@@ -14,7 +16,20 @@ std::shared_ptr<TaskDecorator> TaskDecorator::addChildTask(std::shared_ptr<Task>
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
void TaskDecorator::setTask(std::shared_ptr<Task> task)
|
||||
{
|
||||
if (task)
|
||||
{
|
||||
m_taskRunner = std::make_shared<TaskRunner>(task);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskDecorator::terminate()
|
||||
{
|
||||
doTerminate();
|
||||
}
|
||||
|
||||
void TaskDecorator::doTerminate()
|
||||
{
|
||||
m_taskRunner->terminate();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "utility/scheduling/Task.h"
|
||||
|
||||
class TaskRunner;
|
||||
|
||||
class TaskDecorator
|
||||
: public Task
|
||||
, public std::enable_shared_from_this<TaskDecorator>
|
||||
@@ -14,11 +16,14 @@ public:
|
||||
virtual ~TaskDecorator();
|
||||
std::shared_ptr<TaskDecorator> addChildTask(std::shared_ptr<Task> child);
|
||||
|
||||
virtual void setTask(std::shared_ptr<Task> task) = 0;
|
||||
virtual void setTask(std::shared_ptr<Task> task);
|
||||
virtual void terminate();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<TaskRunner> m_taskRunner;
|
||||
|
||||
private:
|
||||
virtual void doTerminate() = 0;
|
||||
virtual void doTerminate();
|
||||
};
|
||||
|
||||
#endif // TASK_DECORATOR_H
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "utility/scheduling/TaskDecoratorDelay.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
TaskDecoratorDelay::TaskDecoratorDelay(size_t delayMS)
|
||||
: m_delayMS(delayMS)
|
||||
, m_delayComplete(delayMS == 0)
|
||||
{
|
||||
}
|
||||
|
||||
void TaskDecoratorDelay::doEnter(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
m_start = TimePoint::now();
|
||||
}
|
||||
|
||||
Task::TaskState TaskDecoratorDelay::doUpdate(std::shared_ptr<Blackboard> 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> blackboard)
|
||||
{
|
||||
}
|
||||
|
||||
void TaskDecoratorDelay::doReset(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
if (m_delayComplete)
|
||||
{
|
||||
m_taskRunner->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskDecoratorDelay::doTerminate()
|
||||
{
|
||||
if (m_delayComplete)
|
||||
{
|
||||
m_taskRunner->terminate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef TASK_DECORATOR_DELAY_H
|
||||
#define TASK_DECORATOR_DELAY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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> blackboard);
|
||||
virtual TaskState doUpdate(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doExit(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doReset(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doTerminate();
|
||||
|
||||
const size_t m_delayMS;
|
||||
|
||||
TimePoint m_start;
|
||||
bool m_delayComplete;
|
||||
};
|
||||
|
||||
#endif // TASK_DECORATOR_DELAY_H
|
||||
@@ -6,14 +6,6 @@ TaskDecoratorRepeat::TaskDecoratorRepeat(ConditionType condition, TaskState exit
|
||||
{
|
||||
}
|
||||
|
||||
void TaskDecoratorRepeat::setTask(std::shared_ptr<Task> task)
|
||||
{
|
||||
if (task)
|
||||
{
|
||||
m_taskRunner = std::make_shared<TaskRunner>(task);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskDecoratorRepeat::doEnter(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
}
|
||||
@@ -48,8 +40,3 @@ void TaskDecoratorRepeat::doReset(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
m_taskRunner->reset();
|
||||
}
|
||||
|
||||
void TaskDecoratorRepeat::doTerminate()
|
||||
{
|
||||
m_taskRunner->terminate();
|
||||
}
|
||||
|
||||
@@ -17,16 +17,12 @@ public:
|
||||
|
||||
TaskDecoratorRepeat(ConditionType condition, TaskState exitState);
|
||||
|
||||
virtual void setTask(std::shared_ptr<Task> task);
|
||||
|
||||
private:
|
||||
virtual void doEnter(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual TaskState doUpdate(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doExit(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doReset(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doTerminate();
|
||||
|
||||
std::shared_ptr<TaskRunner> m_taskRunner;
|
||||
const ConditionType m_condition;
|
||||
const TaskState m_exitState;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,10 @@ Task::TaskState TaskGroupSelector::doUpdate(std::shared_ptr<Blackboard> blackboa
|
||||
{
|
||||
m_taskIndex = -1;
|
||||
}
|
||||
else if (state == STATE_HOLD)
|
||||
{
|
||||
return STATE_HOLD;
|
||||
}
|
||||
|
||||
return STATE_RUNNING;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ Task::TaskState TaskGroupSequence::doUpdate(std::shared_ptr<Blackboard> blackboa
|
||||
{
|
||||
m_taskIndex = -1;
|
||||
}
|
||||
else if (state == STATE_HOLD)
|
||||
{
|
||||
return STATE_HOLD;
|
||||
}
|
||||
|
||||
return STATE_RUNNING;
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ void TaskScheduler::processTasks()
|
||||
while (m_taskRunners.size())
|
||||
{
|
||||
std::shared_ptr<TaskRunner> 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;
|
||||
|
||||
@@ -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<std::string> 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); });
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ IndexerCommandCxx::IndexerCommandCxx(
|
||||
, m_systemHeaderSearchPaths(systemHeaderSearchPaths)
|
||||
, m_frameworkSearchPaths(frameworkSearchPaths)
|
||||
, m_compilerFlags(compilerFlags)
|
||||
, m_preprocessorOnly(false)
|
||||
, m_shouldApplyAnonymousTypedefTransformation(shouldApplyAnonymousTypedefTransformation)
|
||||
, m_preprocessorOnly(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang
|
||||
case clang::TemplateArgument::Pack:
|
||||
{
|
||||
std::string typeName = "<";
|
||||
argument.getPackAsArray();
|
||||
llvm::ArrayRef<clang::TemplateArgument> pack = argument.getPackAsArray();
|
||||
for (size_t i = 0; i < pack.size(); i++)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <QTextBlock>
|
||||
#include <QToolTip>
|
||||
|
||||
#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::AnnotationColor> 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<SourceLocationFile> 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<int>(blockBoundingRect(block).height());
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> ranges;
|
||||
for (size_t i : m_colorChangedAnnotationIndices)
|
||||
{
|
||||
Annotation& annotation = m_annotations[i];
|
||||
ranges.push_back(std::pair<int, int>(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<QRect> 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<const Annotation*>());
|
||||
}
|
||||
|
||||
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<Id>& tokenIds)
|
||||
{
|
||||
MessageFocusIn(tokenIds, TOOLTIP_ORIGIN_CODE).dispatch();
|
||||
}
|
||||
|
||||
void QtCodeArea::defocusTokenIds(const std::vector<Id>& tokenIds)
|
||||
{
|
||||
MessageFocusOut(tokenIds).dispatch();
|
||||
}
|
||||
|
||||
void QtCodeArea::updateLineNumberAreaWidth(int /* newBlockCount */)
|
||||
{
|
||||
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
|
||||
@@ -668,24 +519,7 @@ void QtCodeArea::setIDECursorPosition()
|
||||
{
|
||||
std::pair<int, int> lineColumn = toLineColumn(this->cursorForPosition(m_eventPosition).position());
|
||||
|
||||
MessageMoveIDECursor(m_locationFile->getFilePath().str(), lineColumn.first, lineColumn.second).dispatch();
|
||||
}
|
||||
|
||||
std::vector<const QtCodeArea::Annotation*> QtCodeArea::getInteractiveAnnotationsForPosition(int pos) const
|
||||
{
|
||||
std::vector<const QtCodeArea::Annotation*> 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<const Annotation*>& annotations)
|
||||
@@ -772,215 +606,21 @@ void QtCodeArea::activateErrors(const std::vector<const Annotation*>& annotation
|
||||
}
|
||||
}
|
||||
|
||||
void QtCodeArea::createAnnotations(std::shared_ptr<SourceLocationFile> locationFile)
|
||||
{
|
||||
uint endLineNumber = getEndLineNumber();
|
||||
std::set<Id> 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<Id>& currentActiveTokenIds = m_navigator->getCurrentActiveTokenIds();
|
||||
const std::set<Id>& currentActiveLocationIds = m_navigator->getCurrentActiveLocationIds();
|
||||
std::set<Id> activeSymbolIds = m_navigator->getCurrentActiveTokenIds();
|
||||
utility::append(activeSymbolIds, m_navigator->getActiveLocalSymbolIds());
|
||||
|
||||
const std::set<Id>& activeTokenIds = m_navigator->getActiveTokenIds();
|
||||
const std::set<Id>& activeLocalSymbolIds = m_navigator->getActiveLocalSymbolIds();
|
||||
const std::set<Id>& focusIds = m_navigator->getFocusedTokenIds();
|
||||
const std::set<Id>& activeLocationIds = m_navigator->getCurrentActiveLocationIds();
|
||||
|
||||
std::vector<int> linesToRehighlight;
|
||||
std::set<Id> 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<const Annotation*>& annotations)
|
||||
{
|
||||
if (m_hoveredAnnotations.size())
|
||||
{
|
||||
std::vector<Id> 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<Id> 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<int, int> 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<int> QtCodeArea::getActiveLineNumbers() const
|
||||
@@ -1001,111 +641,6 @@ std::set<int> QtCodeArea::getActiveLineNumbers() const
|
||||
return activeLineNumbers;
|
||||
}
|
||||
|
||||
std::vector<QRect> QtCodeArea::getCursorRectsForAnnotation(const Annotation& annotation) const
|
||||
{
|
||||
std::vector<QRect> 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<std::string> types = { "token", "local_symbol", "scope", "error", "fulltext" };
|
||||
std::vector<ColorScheme::ColorState> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,17 @@
|
||||
#define QT_CODE_AREA_H
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#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<SourceLocationFile> 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<Id>& tokenIds) override;
|
||||
virtual void defocusTokenIds(const std::vector<Id>& 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<Id> tokenIds;
|
||||
Id locationId;
|
||||
|
||||
LocationType locationType;
|
||||
|
||||
bool isActive;
|
||||
bool isFocused;
|
||||
|
||||
QColor oldTextColor;
|
||||
};
|
||||
|
||||
struct AnnotationColor
|
||||
{
|
||||
std::string border;
|
||||
std::string fill;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
std::vector<const Annotation*> getInteractiveAnnotationsForPosition(int pos) const;
|
||||
void activateSourceLocations(const std::vector<const Annotation*>& annotations);
|
||||
void activateLocalSymbols(const std::vector<const Annotation*>& annotations);
|
||||
void activateErrors(const std::vector<const Annotation*>& annotations);
|
||||
|
||||
void createAnnotations(std::shared_ptr<SourceLocationFile> locationFile);
|
||||
void annotateText();
|
||||
|
||||
void setHoveredAnnotations(const std::vector<const Annotation*>& annotations);
|
||||
|
||||
int toTextEditPosition(int lineNumber, int columnNumber) const;
|
||||
std::pair<int, int> toLineColumn(int textEditPosition) const;
|
||||
int startTextEditPosition() const;
|
||||
int endTextEditPosition() const;
|
||||
|
||||
std::set<int> getActiveLineNumbers() const;
|
||||
|
||||
std::vector<QRect> 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<AnnotationColor> s_annotationColors;
|
||||
|
||||
QtCodeNavigator* m_navigator;
|
||||
|
||||
QWidget* m_lineNumberArea;
|
||||
QtHighlighter* m_highlighter;
|
||||
|
||||
const uint m_startLineNumber;
|
||||
const std::string m_code;
|
||||
|
||||
std::shared_ptr<SourceLocationFile> m_locationFile;
|
||||
|
||||
std::vector<Annotation> m_annotations;
|
||||
std::vector<const Annotation*> m_hoveredAnnotations;
|
||||
|
||||
std::set<size_t> m_colorChangedAnnotationIndices;
|
||||
|
||||
int m_digits;
|
||||
|
||||
@@ -203,10 +127,6 @@ private:
|
||||
|
||||
bool m_isActiveFile;
|
||||
bool m_lineNumbersHidden;
|
||||
bool m_wasAnnotated;
|
||||
|
||||
std::vector<int> m_lineLengths;
|
||||
int m_endTextEditPosition;
|
||||
|
||||
QtScrollSpeedChangeListener m_scrollSpeedChangeListener;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,613 @@
|
||||
#include "QtCodeField.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QTextBlock>
|
||||
|
||||
#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::AnnotationColor> QtCodeField::s_annotationColors;
|
||||
|
||||
void QtCodeField::clearAnnotationColors()
|
||||
{
|
||||
s_annotationColors.clear();
|
||||
}
|
||||
|
||||
QtCodeField::QtCodeField(
|
||||
uint startLineNumber,
|
||||
const std::string& code,
|
||||
std::shared_ptr<SourceLocationFile> 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<SourceLocationFile> QtCodeField::getSourceLocationFile() const
|
||||
{
|
||||
return m_locationFile;
|
||||
}
|
||||
|
||||
void QtCodeField::annotateText()
|
||||
{
|
||||
annotateText(std::set<Id>(), std::set<Id>(), std::set<Id>());
|
||||
}
|
||||
|
||||
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<int>(blockBoundingRect(block).height());
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> ranges;
|
||||
for (size_t i : m_colorChangedAnnotationIndices)
|
||||
{
|
||||
Annotation& annotation = m_annotations[i];
|
||||
ranges.push_back(std::pair<int, int>(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<QRect> 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<const Annotation*>());
|
||||
}
|
||||
|
||||
void QtCodeField::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
QTextCursor cursor = this->cursorForPosition(event->pos());
|
||||
std::vector<const Annotation*> 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<const Annotation*> annotations = getInteractiveAnnotationsForPosition(cursor.position());
|
||||
|
||||
if (!annotations.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<Id> 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<Id>& tokenIds)
|
||||
{
|
||||
annotateText(std::set<Id>(), std::set<Id>(), std::set<Id>(tokenIds.begin(), tokenIds.end()));
|
||||
}
|
||||
|
||||
void QtCodeField::defocusTokenIds(const std::vector<Id>& tokenIds)
|
||||
{
|
||||
annotateText(std::set<Id>(), std::set<Id>(), std::set<Id>());
|
||||
}
|
||||
|
||||
bool QtCodeField::annotateText(
|
||||
const std::set<Id>& activeSymbolIds, const std::set<Id>& activeLocationIds, const std::set<Id>& focusedSymbolIds)
|
||||
{
|
||||
std::vector<int> 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<SourceLocationFile> locationFile)
|
||||
{
|
||||
uint endLineNumber = getEndLineNumber();
|
||||
std::set<Id> 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<int, int> 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<const Annotation*>& annotations)
|
||||
{
|
||||
if (m_hoveredAnnotations.size())
|
||||
{
|
||||
std::vector<Id> 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<Id> tokenIds;
|
||||
for (const Annotation* annotation : annotations)
|
||||
{
|
||||
tokenIds.insert(tokenIds.end(), annotation->tokenIds.begin(), annotation->tokenIds.end());
|
||||
}
|
||||
|
||||
focusTokenIds(tokenIds);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QRect> QtCodeField::getCursorRectsForAnnotation(const Annotation& annotation) const
|
||||
{
|
||||
std::vector<QRect> 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<std::string> types = { "token", "local_symbol", "scope", "error", "fulltext" };
|
||||
std::vector<ColorScheme::ColorState> 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<const QtCodeField::Annotation*> QtCodeField::getInteractiveAnnotationsForPosition(int pos) const
|
||||
{
|
||||
std::vector<const QtCodeField::Annotation*> 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef QT_CODE_FIELD_H
|
||||
#define QT_CODE_FIELD_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#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<SourceLocationFile> 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<SourceLocationFile> 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<Id>& tokenIds);
|
||||
virtual void defocusTokenIds(const std::vector<Id>& tokenIds);
|
||||
|
||||
struct Annotation
|
||||
{
|
||||
int startLine;
|
||||
int endLine;
|
||||
|
||||
int startCol;
|
||||
int endCol;
|
||||
|
||||
int start;
|
||||
int end;
|
||||
|
||||
std::set<Id> 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<Id>& activeSymbolIds, const std::set<Id>& activeLocationIds, const std::set<Id>& focusedSymbolIds);
|
||||
|
||||
void createAnnotations(std::shared_ptr<SourceLocationFile> locationFile);
|
||||
|
||||
int toTextEditPosition(int lineNumber, int columnNumber) const;
|
||||
std::pair<int, int> toLineColumn(int textEditPosition) const;
|
||||
|
||||
int startTextEditPosition() const;
|
||||
int endTextEditPosition() const;
|
||||
|
||||
void setHoveredAnnotations(const std::vector<const Annotation*>& annotations);
|
||||
std::vector<QRect> getCursorRectsForAnnotation(const Annotation& annotation) const;
|
||||
|
||||
const AnnotationColor& getAnnotationColorForAnnotation(const Annotation& annotation);
|
||||
void setTextColorForAnnotation(Annotation& annotation, QColor color) const;
|
||||
|
||||
std::vector<const Annotation*> getInteractiveAnnotationsForPosition(int pos) const;
|
||||
|
||||
std::vector<Annotation> m_annotations;
|
||||
std::vector<const Annotation*> m_hoveredAnnotations;
|
||||
|
||||
private:
|
||||
static std::vector<AnnotationColor> s_annotationColors;
|
||||
|
||||
void createLineLengthCache();
|
||||
|
||||
const uint m_startLineNumber;
|
||||
const std::string m_code;
|
||||
|
||||
std::shared_ptr<SourceLocationFile> m_locationFile;
|
||||
|
||||
QtHighlighter* m_highlighter;
|
||||
|
||||
std::vector<int> m_lineLengths;
|
||||
std::set<size_t> m_colorChangedAnnotationIndices;
|
||||
|
||||
int m_endTextEditPosition;
|
||||
bool m_wasAnnotated;
|
||||
};
|
||||
|
||||
#endif // QT_CODE_FIELD_H
|
||||
@@ -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();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
#include "qt/element/QtTooltip.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCursor>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPoint>
|
||||
#include <QStyle>
|
||||
#include <QTimer>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef QT_TOOLTIP_H
|
||||
#define QT_TOOLTIP_H
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
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
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<QtMainView*>(getViewLayout())->getMainWindow());
|
||||
}
|
||||
|
||||
QtTooltipView::~QtTooltipView()
|
||||
{
|
||||
}
|
||||
|
||||
void QtTooltipView::createWidgetWrapper()
|
||||
{
|
||||
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(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()
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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<StatusBarView> QtViewFactory::createStatusBarView(ViewLayout* vi
|
||||
return View::createAndInit<QtStatusBarView>(viewLayout);
|
||||
}
|
||||
|
||||
std::shared_ptr<TooltipView> QtViewFactory::createTooltipView(ViewLayout* viewLayout) const
|
||||
{
|
||||
return View::createAndInit<QtTooltipView>(viewLayout);
|
||||
}
|
||||
|
||||
std::shared_ptr<UndoRedoView> QtViewFactory::createUndoRedoView(ViewLayout* viewLayout) const
|
||||
{
|
||||
return View::createInitAndAddToLayout<QtUndoRedoView>(viewLayout);
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
virtual std::shared_ptr<SearchView> createSearchView(ViewLayout* viewLayout) const;
|
||||
virtual std::shared_ptr<StatusBarView> createStatusBarView(ViewLayout* viewLayout) const;
|
||||
virtual std::shared_ptr<StatusView> createStatusView(ViewLayout* viewLayout) const;
|
||||
virtual std::shared_ptr<TooltipView> createTooltipView(ViewLayout* viewLayout) const;
|
||||
virtual std::shared_ptr<UndoRedoView> createUndoRedoView(ViewLayout* viewLayout) const;
|
||||
|
||||
virtual std::shared_ptr<DialogView> createDialogView(ViewLayout* viewLayout, StorageAccess* storageAccess) const;
|
||||
|
||||
@@ -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<Id>(1, getData()->getId())).dispatch();
|
||||
MessageFocusIn(std::vector<Id>(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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<TokenComponentSignature>();
|
||||
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<Id>(1, m_data->getId())).dispatch();
|
||||
MessageFocusIn(std::vector<Id>(1, m_data->getId()), TOOLTIP_ORIGIN_GRAPH).dispatch();
|
||||
}
|
||||
|
||||
void QtGraphNodeData::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -63,6 +63,8 @@ public:
|
||||
void showView(View* view);
|
||||
void hideView(View* view);
|
||||
|
||||
View* findFloatingView(const std::string& name) const;
|
||||
|
||||
void loadLayout();
|
||||
void saveLayout();
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
std::shared_ptr<SourceGroupSettings> 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;
|
||||
|
||||
Reference in New Issue
Block a user