diff --git a/src/app/qt/element/QtCodeFile.cpp b/src/app/qt/element/QtCodeFile.cpp index e8c73400..ae867ea2 100644 --- a/src/app/qt/element/QtCodeFile.cpp +++ b/src/app/qt/element/QtCodeFile.cpp @@ -36,10 +36,13 @@ const std::string& QtCodeFile::getFileName() const } void QtCodeFile::addCodeSnippet( - const std::string& str, const TokenLocationFile& locationFile, int startLineNumber, Id activeTokenId + int startLineNumber, + const std::string& code, + const TokenLocationFile& locationFile, + const std::vector& activeTokenIds ){ std::shared_ptr snippet( - new QtCodeSnippet(m_parentView, str, locationFile, startLineNumber, activeTokenId, this) + new QtCodeSnippet(m_parentView, startLineNumber, code, locationFile, activeTokenIds, this) ); layout()->addWidget(snippet.get()); m_snippets.push_back(snippet); diff --git a/src/app/qt/element/QtCodeFile.h b/src/app/qt/element/QtCodeFile.h index 26936a84..8a632e18 100644 --- a/src/app/qt/element/QtCodeFile.h +++ b/src/app/qt/element/QtCodeFile.h @@ -22,7 +22,10 @@ public: const std::string& getFileName() const; void addCodeSnippet( - const std::string& str, const TokenLocationFile& locationFile, int startLineNumber, Id activeTokenId + int startLineNumber, + const std::string& code, + const TokenLocationFile& locationFile, + const std::vector& activeTokenIds ); private: diff --git a/src/app/qt/element/QtCodeSnippet.cpp b/src/app/qt/element/QtCodeSnippet.cpp index ec15e793..2e866dde 100644 --- a/src/app/qt/element/QtCodeSnippet.cpp +++ b/src/app/qt/element/QtCodeSnippet.cpp @@ -34,16 +34,16 @@ void QtCodeSnippet::LineNumberArea::paintEvent(QPaintEvent *event) QtCodeSnippet::QtCodeSnippet( QtCodeView* parentView, + int startLineNumber, const std::string& code, const TokenLocationFile& locationFile, - int startLineNumber, - Id activeTokenId, + const std::vector& activeTokenIds, QWidget *parent ) : QPlainTextEdit(parent) , m_parentView(parentView) , m_startLineNumber(startLineNumber) - , m_activeTokenId(activeTokenId) + , m_activeTokenIds(activeTokenIds) , m_digits(0) { setObjectName("code_snippet"); @@ -171,7 +171,9 @@ void QtCodeSnippet::annotateText(const TokenLocationFile& locationFile) m_annotations.push_back(annotation); Colori color; - if (location->getTokenId() == m_activeTokenId) + const std::vector& ids = m_activeTokenIds; + bool isActive = std::find(ids.begin(), ids.end(), location->getTokenId()) != ids.end(); + if (isActive) { color = ApplicationSettings::getInstance()->getCodeActiveLinkColor(); } diff --git a/src/app/qt/element/QtCodeSnippet.h b/src/app/qt/element/QtCodeSnippet.h index 4d8346c9..a0e6c1ed 100644 --- a/src/app/qt/element/QtCodeSnippet.h +++ b/src/app/qt/element/QtCodeSnippet.h @@ -37,10 +37,10 @@ public: QtCodeSnippet( QtCodeView* parentView, + int startLineNumber, const std::string& code, const TokenLocationFile& locationFile, - int startLineNumber, - Id activeTokenId, + const std::vector& activeTokenIds, QWidget *parent = 0 ); virtual ~QtCodeSnippet(); @@ -81,7 +81,7 @@ private: QWidget *m_lineNumberArea; const int m_startLineNumber; - const Id m_activeTokenId; + const std::vector m_activeTokenIds; int m_digits; std::vector m_annotations; diff --git a/src/app/qt/view/QtCodeView.cpp b/src/app/qt/view/QtCodeView.cpp index 8597e752..0d6c4970 100644 --- a/src/app/qt/view/QtCodeView.cpp +++ b/src/app/qt/view/QtCodeView.cpp @@ -99,7 +99,7 @@ void QtCodeView::doAddCodeSnippet(const CodeSnippetParams params) m_frame->layout()->addWidget(file); } - file->addCodeSnippet(params.code, params.locationFile, params.startLineNumber, params.activeTokenId); + file->addCodeSnippet(params.startLineNumber, params.code, params.locationFile, params.activeTokenIds); } void QtCodeView::doClearCodeSnippets() diff --git a/src/lib/component/ComponentFactory.cpp b/src/lib/component/ComponentFactory.cpp index 3c0ed65e..21282940 100644 --- a/src/lib/component/ComponentFactory.cpp +++ b/src/lib/component/ComponentFactory.cpp @@ -28,7 +28,7 @@ ComponentFactory::~ComponentFactory() std::shared_ptr ComponentFactory::createCodeComponent() { std::shared_ptr view = m_viewFactory->createCodeView(m_viewLayout); - std::shared_ptr controller = std::make_shared(m_locationAccess); + std::shared_ptr controller = std::make_shared(m_graphAccess, m_locationAccess); std::shared_ptr component = std::make_shared(view, controller); return component; diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index b10c6540..6b16c4f5 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -1,15 +1,16 @@ #include "component/controller/CodeController.h" #include "component/view/CodeView.h" +#include "data/access/GraphAccess.h" #include "data/access/LocationAccess.h" #include "data/location/TokenLocation.h" #include "data/location/TokenLocationCollection.h" #include "data/location/TokenLocationFile.h" -#include "utility/logging/logging.h" #include "utility/text/TextAccess.h" -CodeController::CodeController(LocationAccess* locationAccess) - : m_locationAccess(locationAccess) +CodeController::CodeController(GraphAccess* graphAccess, LocationAccess* locationAccess) + : m_graphAccess(graphAccess) + , m_locationAccess(locationAccess) { } @@ -19,23 +20,25 @@ CodeController::~CodeController() void CodeController::setActiveTokenId(Id id) { - const unsigned int lineRadius = 2; + const uint lineRadius = 2; getView()->clearCodeSnippets(); - TokenLocationCollection collection = m_locationAccess->getTokenLocationsForTokenId(id); - collection.forEachTokenLocation( - [&](TokenLocation* tokenLocation) -> void - { - if (tokenLocation->isStartTokenLocation()) - { - const std::string filePath = tokenLocation->getFilePath(); - std::shared_ptr textAccess = TextAccess::createFromFile(filePath); + std::vector activeTokenIds = m_graphAccess->getActiveTokenIdsForId(id); + std::vector locationIds = m_graphAccess->getLocationIdsForTokenIds(activeTokenIds); - unsigned int firstLineNumber = std::max(1, tokenLocation->getLineNumber() - lineRadius); - unsigned int lastLineNumber = std::min( - textAccess->getLineCount(), tokenLocation->getEndTokenLocation()->getLineNumber() + lineRadius - ); + TokenLocationCollection collection = m_locationAccess->getTokenLocationsForLocationIds(locationIds); + collection.forEachTokenLocationFile( + [&](TokenLocationFile* file) -> void + { + const std::string filePath = file->getFilePath(); + std::shared_ptr textAccess = TextAccess::createFromFile(filePath); + + std::vector> ranges = getSnippetRangesForFile(file, lineRadius); + for (const std::pair& range: ranges) + { + unsigned int firstLineNumber = std::max(1, range.first - lineRadius); + unsigned int lastLineNumber = std::min(textAccess->getLineCount(), range.second + lineRadius); CodeView::CodeSnippetParams params; for (const std::string& line: textAccess->getLines(firstLineNumber, lastLineNumber)) @@ -46,7 +49,7 @@ void CodeController::setActiveTokenId(Id id) params.startLineNumber = firstLineNumber; params.locationFile = m_locationAccess->getTokenLocationsForLinesInFile(filePath, firstLineNumber, lastLineNumber); - params.activeTokenId = id; + params.activeTokenIds = activeTokenIds; getView()->addCodeSnippet(params); } @@ -68,3 +71,40 @@ CodeView* CodeController::getView() { return Controller::getView(); } + +std::vector> CodeController::getSnippetRangesForFile( + TokenLocationFile* file, const uint lineRadius +) const +{ + std::vector> ranges; + uint start = 0; + uint end = 0; + + file->forEachTokenLocation( + [&](TokenLocation* location) -> void + { + uint lineNumber = location->getLineNumber(); + + if (location->isStartTokenLocation()) + { + if (!start) + { + start = lineNumber; + } + else if (end && lineNumber > end + 2 * lineRadius + 1) + { + ranges.push_back(std::make_pair(uint(start), uint(end))); + start = lineNumber; + end = 0; + } + } + else + { + end = lineNumber; + } + } + ); + + ranges.push_back(std::make_pair(uint(start), uint(end))); + return ranges; +} diff --git a/src/lib/component/controller/CodeController.h b/src/lib/component/controller/CodeController.h index 6e363f86..fac025c1 100644 --- a/src/lib/component/controller/CodeController.h +++ b/src/lib/component/controller/CodeController.h @@ -10,7 +10,9 @@ #include "utility/types.h" class CodeView; +class GraphAccess; class LocationAccess; +class TokenLocationFile; struct AnnotatedText { @@ -24,7 +26,7 @@ class CodeController , public MessageListener { public: - CodeController(LocationAccess* locationAccess); + CodeController(GraphAccess* graphAccess, LocationAccess* locationAccess); ~CodeController(); void setActiveTokenId(Id id); @@ -32,8 +34,12 @@ public: private: virtual void handleMessage(MessageActivateToken* message); virtual void handleMessage(MessageRefresh* message); + CodeView* getView(); + std::vector> getSnippetRangesForFile(TokenLocationFile* file, const uint lineRadius) const; + + GraphAccess* m_graphAccess; LocationAccess* m_locationAccess; }; diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h index 97ee9d77..c97b6eae 100644 --- a/src/lib/component/view/CodeView.h +++ b/src/lib/component/view/CodeView.h @@ -14,10 +14,10 @@ public: { CodeSnippetParams(); + int startLineNumber; std::string code; TokenLocationFile locationFile; - int startLineNumber; - Id activeTokenId; + std::vector activeTokenIds; }; CodeView(ViewLayout* viewLayout); diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index c22f382c..cea7d49f 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -387,17 +387,62 @@ bool Storage::checkTokenIsNode(const Id id) const return false; } -TokenLocationCollection Storage::getTokenLocationsForTokenId(Id id) const +std::vector Storage::getActiveTokenIdsForId(Id tokenId) const { - TokenLocationCollection ret; - - Token* token = m_graph.getTokenById(id); + std::vector ret; + Token* token = m_graph.getTokenById(tokenId); if (!token) { return ret; } - std::vector locationIds = token->getLocationIds(); + Node* node; + if (token->isEdge()) + { + node = dynamic_cast(token)->getTo(); + } + else + { + node = dynamic_cast(token); + } + + ret.push_back(node->getId()); + + node->forEachEdge( + [&node, &ret](Edge* e) + { + if (e->getTo() == node) + { + ret.push_back(e->getId()); + } + } + ); + + return ret; +} + +std::vector Storage::getLocationIdsForTokenIds(const std::vector& tokenIds) const +{ + std::vector ret; + + for (Id tokenId : tokenIds) + { + Token* token = m_graph.getTokenById(tokenId); + if (!token) + { + continue; + } + + ret.insert(ret.end(), token->getLocationIds().begin(), token->getLocationIds().end()); + } + + return ret; +} + +TokenLocationCollection Storage::getTokenLocationsForLocationIds(const std::vector& locationIds) const +{ + TokenLocationCollection ret; + for (Id locationId: locationIds) { TokenLocation* location = m_locationCollection.findTokenLocationById(locationId); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 681ee4ea..55e93be2 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -81,8 +81,11 @@ public: virtual bool checkTokenIsNode(const Id id) const; + virtual std::vector getActiveTokenIdsForId(Id tokenId) const; + virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const; + // LocationAccess implementation - virtual TokenLocationCollection getTokenLocationsForTokenId(Id locationId) const; + virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const; virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& fileName, unsigned int firstLineNumber, unsigned int lastLineNumber ) const; diff --git a/src/lib/data/access/GraphAccess.h b/src/lib/data/access/GraphAccess.h index 73bc394e..04f27c01 100644 --- a/src/lib/data/access/GraphAccess.h +++ b/src/lib/data/access/GraphAccess.h @@ -30,6 +30,9 @@ public: virtual std::pair getNodesOfEdge(const Id id) const = 0; virtual bool checkTokenIsNode(const Id id) const = 0; + + virtual std::vector getActiveTokenIdsForId(Id tokenId) const = 0; + virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const = 0; }; #endif // GRAPH_ACCESS_H diff --git a/src/lib/data/access/GraphAccessProxy.cpp b/src/lib/data/access/GraphAccessProxy.cpp index 79d6fd08..e005c634 100644 --- a/src/lib/data/access/GraphAccessProxy.cpp +++ b/src/lib/data/access/GraphAccessProxy.cpp @@ -166,3 +166,23 @@ bool GraphAccessProxy::checkTokenIsNode(const Id id) const return false; } + +std::vector GraphAccessProxy::getActiveTokenIdsForId(Id tokenId) const +{ + if (hasSubject()) + { + return m_subject->getActiveTokenIdsForId(tokenId); + } + + return std::vector(); +} + +std::vector GraphAccessProxy::getLocationIdsForTokenIds(const std::vector& tokenIds) const +{ + if (hasSubject()) + { + return m_subject->getLocationIdsForTokenIds(tokenIds); + } + + return std::vector(); +} diff --git a/src/lib/data/access/GraphAccessProxy.h b/src/lib/data/access/GraphAccessProxy.h index 91b84271..48a32d53 100644 --- a/src/lib/data/access/GraphAccessProxy.h +++ b/src/lib/data/access/GraphAccessProxy.h @@ -30,6 +30,9 @@ public: virtual bool checkTokenIsNode(const Id id) const; + virtual std::vector getActiveTokenIdsForId(Id tokenId) const; + virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const; + private: GraphAccess* m_subject; }; diff --git a/src/lib/data/access/LocationAccess.h b/src/lib/data/access/LocationAccess.h index c7f2f736..ab3284e3 100644 --- a/src/lib/data/access/LocationAccess.h +++ b/src/lib/data/access/LocationAccess.h @@ -2,6 +2,7 @@ #define LOCATION_ACCESS_H #include +#include #include "utility/types.h" @@ -12,7 +13,7 @@ class LocationAccess { public: virtual ~LocationAccess(); - virtual TokenLocationCollection getTokenLocationsForTokenId(Id id) const = 0; + virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const = 0; virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& fileName, unsigned int firstLineNumber, unsigned int lastLineNumber ) const = 0; diff --git a/src/lib/data/access/LocationAccessProxy.cpp b/src/lib/data/access/LocationAccessProxy.cpp index 33c7f51a..40fffe21 100644 --- a/src/lib/data/access/LocationAccessProxy.cpp +++ b/src/lib/data/access/LocationAccessProxy.cpp @@ -29,11 +29,11 @@ void LocationAccessProxy::setSubject(LocationAccess* subject) m_subject = subject; } -TokenLocationCollection LocationAccessProxy::getTokenLocationsForTokenId(Id id) const +TokenLocationCollection LocationAccessProxy::getTokenLocationsForLocationIds(const std::vector& locationIds) const { if (hasSubject()) { - return m_subject->getTokenLocationsForTokenId(id); + return m_subject->getTokenLocationsForLocationIds(locationIds); } return TokenLocationCollection(); diff --git a/src/lib/data/access/LocationAccessProxy.h b/src/lib/data/access/LocationAccessProxy.h index 098b4f15..fe8c1ce9 100644 --- a/src/lib/data/access/LocationAccessProxy.h +++ b/src/lib/data/access/LocationAccessProxy.h @@ -13,7 +13,7 @@ public: void setSubject(LocationAccess* subject); // LocationAccess implementation - virtual TokenLocationCollection getTokenLocationsForTokenId(Id id) const; + virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const; virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& fileName, unsigned int firstLineNumber, unsigned int lastLineNumber ) const; diff --git a/src/lib/utility/types.h b/src/lib/utility/types.h index c322e8a5..9633087e 100644 --- a/src/lib/utility/types.h +++ b/src/lib/utility/types.h @@ -3,4 +3,6 @@ typedef unsigned long Id; +typedef unsigned int uint; + #endif // TYPES_H