diff --git a/bin/app/data/ProjectSettings_template.xml b/bin/app/data/ProjectSettings_template.xml index 000c7c5d..84867338 100644 --- a/bin/app/data/ProjectSettings_template.xml +++ b/bin/app/data/ProjectSettings_template.xml @@ -7,6 +7,10 @@ + + + + diff --git a/bin/app/data/projects/tutorial/tutorial.coatiproject b/bin/app/data/projects/tutorial/tutorial.coatiproject index ff5af2b5..6198af82 100644 --- a/bin/app/data/projects/tutorial/tutorial.coatiproject +++ b/bin/app/data/projects/tutorial/tutorial.coatiproject @@ -1,12 +1,17 @@ - - - .h - .cpp - - - ./src - - - \ No newline at end of file + + + This is the tutorial project of Coati.\nIt will introduce you to Coati's user interface.\nPlease click on the function [main] below to start the tutorial\n\n[main](); // <- start here\n\n + + + + + .h + .cpp + + + ./src + + + diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index 3426afe8..833bf2ab 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -3,7 +3,6 @@ #include "utility/logging/logging.h" #include "utility/messaging/MessageQueue.h" #include "utility/messaging/type/MessageActivateNodes.h" -#include "utility/messaging/type/MessageShowErrors.h" #include "utility/messaging/type/MessageStatus.h" #include "utility/scheduling/TaskScheduler.h" #include "utility/Version.h" @@ -130,14 +129,7 @@ void Application::handleMessage(MessageFinishedParsing* message) { m_project->logStats(); - if (message->errorCount == 0) - { - MessageRefresh().refreshUiOnly().dispatch(); - } - else - { - MessageShowErrors().dispatch(); - } + MessageRefresh().refreshUiOnly().dispatch(); } void Application::handleMessage(MessageLoadProject* message) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ad21fe62..2e45a4f4 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -165,6 +165,7 @@ add_files( data/StorageCache.cpp data/StorageCache.h data/StorageTypes.h + data/StorageStats.h data/TaskCleanStorage.cpp data/TaskCleanStorage.h @@ -210,10 +211,12 @@ add_files( utility/math/Vector4.h utility/math/VectorBase.h + utility/messaging/type/MessageActivateAll.h utility/messaging/type/MessageActivateEdge.h utility/messaging/type/MessageActivateFile.h utility/messaging/type/MessageActivateNodes.h utility/messaging/type/MessageActivateTokenLocations.h + utility/messaging/type/MessageActivateTokenIds.h utility/messaging/type/MessageActivateTokens.h utility/messaging/type/MessageActivateWindow.h utility/messaging/type/MessageAutoRefreshChanged.h diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index c928a826..924daba9 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -5,6 +5,7 @@ #include "utility/messaging/type/MessageStatus.h" #include "utility/text/TextAccess.h" #include "utility/utility.h" +#include "utility/utilityString.h" #include "data/access/StorageAccess.h" #include "data/location/TokenLocation.h" @@ -12,6 +13,7 @@ #include "data/location/TokenLocationFile.h" #include "data/location/TokenLocationLine.h" #include "settings/ApplicationSettings.h" +#include "settings/ProjectSettings.h" CodeController::CodeController(StorageAccess* storageAccess) : m_storageAccess(storageAccess) @@ -24,6 +26,63 @@ CodeController::~CodeController() const uint CodeController::s_lineRadius = 2; +void CodeController::handleMessage(MessageActivateAll* message) +{ + std::vector errorMessages; + std::vector snippets = getSnippetsForErrorLocations(&errorMessages); + + StorageStats stats = m_storageAccess->getStorageStats(); + CodeView::CodeSnippetParams statsSnippet; + + statsSnippet.startLineNumber = 1; + statsSnippet.endLineNumber = 1; + + statsSnippet.locationFile = std::make_shared(FilePath()); + statsSnippet.locationFile->isWholeCopy = true; + + std::vector description = getProjectDescription(statsSnippet.locationFile.get()); + + std::stringstream ss; + + ss << "\n"; + ss << "\t" + ProjectSettings::getInstance()->getFilePath().withoutExtension().fileName() + "\n"; + + if (description.size()) + { + ss << "\n"; + for (const std::string& line : description) + { + ss << line + "\n"; + } + } + + ss << "\n"; + ss << "\t" + std::to_string(stats.fileCount) + " files\n"; + ss << "\t" + std::to_string(stats.fileLOCCount) + " lines of code\n"; + ss << "\n"; + ss << "\t" + std::to_string(stats.nodeCount) + " symbols\n"; + ss << "\t" + std::to_string(stats.edgeCount) + " relations\n"; + ss << "\n"; + ss << "\t" + std::to_string(stats.errorCount) + " errors\n"; + ss << "\n"; + + if (stats.errorCount > 0) + { + ss << "\tWarning: The analysis may be incomplete as long as it yields errors.\n"; + ss << "\tTry resolving them and refresh the project.\n"; + ss << "\n"; + } + + statsSnippet.code = ss.str(); + + snippets.insert(snippets.begin(), statsSnippet); + + CodeView* view = getView(); + view->setActiveTokenIds(std::vector()); + view->setErrorMessages(errorMessages); + view->showCodeSnippets(snippets); +} + void CodeController::handleMessage(MessageActivateTokens* message) { if (message->keepContent() && message->isIgnorable()) @@ -92,17 +151,7 @@ void CodeController::handleMessage(MessageFocusOut* message) void CodeController::handleMessage(MessageShowErrors* message) { std::vector errorMessages; - TokenLocationCollection errorCollection = m_storageAccess->getErrorTokenLocations(&errorMessages); - - std::vector snippets; - - errorCollection.forEachTokenLocationFile( - [&](std::shared_ptr file) -> void - { - std::vector fileSnippets = getSnippetsForFile(file); - snippets.insert(snippets.end(), fileSnippets.begin(), fileSnippets.end()); - } - ); + std::vector snippets = getSnippetsForErrorLocations(&errorMessages); CodeView* view = getView(); view->setActiveTokenIds(std::vector()); @@ -357,3 +406,72 @@ std::shared_ptr CodeController::buildMergerHierarchy( nextMerger->addChild(currentMerger); return currentMerger; } + +std::vector CodeController::getSnippetsForErrorLocations( + std::vector* errorMessages) +const { + TokenLocationCollection errorCollection = m_storageAccess->getErrorTokenLocations(errorMessages); + + std::vector snippets; + + errorCollection.forEachTokenLocationFile( + [&](std::shared_ptr file) -> void + { + std::vector fileSnippets = getSnippetsForFile(file); + snippets.insert(snippets.end(), fileSnippets.begin(), fileSnippets.end()); + } + ); + + return snippets; +} + +std::vector CodeController::getProjectDescription(TokenLocationFile* locationFile) const +{ + std::string description = ProjectSettings::getInstance()->getDescription(); + + if (!description.size()) + { + return std::vector(); + } + + std::vector lines = utility::splitToVector(description, "\\n"); + size_t startLineNumber = 4; + + for (size_t i = 0; i < lines.size(); i++) + { + std::string line = "\t" + lines[i]; + + size_t pos = 0; + + while (pos != std::string::npos) + { + size_t posA = line.find('[', pos); + size_t posB = line.find(']', posA); + + if (posA == std::string::npos || posB == std::string::npos) + { + break; + } + + std::string tokenName = line.substr(posA + 1, posB - posA - 1); + + Id tokenId = m_storageAccess->getIdForNodeWithSearchNameHierarchy(NameHierarchy(tokenName)); + + if (tokenId > 0) + { + line.replace(posA, posB - posA + 1, tokenName); + locationFile->addTokenLocation( + 0, tokenId, + startLineNumber + i, posA + 1, + startLineNumber + i, posA + tokenName.size() + ); + } + + pos = posA + tokenName.size(); + } + + lines[i] = line; + } + + return lines; +} diff --git a/src/lib/component/controller/CodeController.h b/src/lib/component/controller/CodeController.h index f4cf3191..fcb464d2 100644 --- a/src/lib/component/controller/CodeController.h +++ b/src/lib/component/controller/CodeController.h @@ -5,6 +5,7 @@ #include #include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageActivateAll.h" #include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageFocusIn.h" #include "utility/messaging/type/MessageFocusOut.h" @@ -24,6 +25,7 @@ class TokenLocationFile; class CodeController : public Controller + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -39,6 +41,7 @@ public: private: static const uint s_lineRadius; + virtual void handleMessage(MessageActivateAll* message); virtual void handleMessage(MessageActivateTokens* message); virtual void handleMessage(MessageFocusIn* message); virtual void handleMessage(MessageFocusOut* message); @@ -57,6 +60,10 @@ private: std::shared_ptr buildMergerHierarchy( TokenLocation* location, SnippetMerger& fileScopedMerger, std::map>& mergers) const; + std::vector getSnippetsForErrorLocations(std::vector* errorMessages) const; + + std::vector getProjectDescription(TokenLocationFile* locationFile) const; + StorageAccess* m_storageAccess; }; diff --git a/src/lib/component/controller/FeatureController.cpp b/src/lib/component/controller/FeatureController.cpp index f103e355..136a3e39 100644 --- a/src/lib/component/controller/FeatureController.cpp +++ b/src/lib/component/controller/FeatureController.cpp @@ -53,6 +53,15 @@ void FeatureController::handleMessage(MessageSearch* message) } } +void FeatureController::handleMessage(MessageActivateTokenIds* message) +{ + std::shared_ptr m = m_activationTranslator.translateMessage(message); + if (m) + { + m->dispatchImmediately(); + } +} + void FeatureController::handleMessage(MessageActivateTokenLocations* message) { std::vector nodeIds = m_storageAccess->getNodeIdsForLocationIds(message->locationIds); diff --git a/src/lib/component/controller/FeatureController.h b/src/lib/component/controller/FeatureController.h index e07024aa..d9805b16 100644 --- a/src/lib/component/controller/FeatureController.h +++ b/src/lib/component/controller/FeatureController.h @@ -10,6 +10,7 @@ #include "utility/messaging/type/MessageActivateEdge.h" #include "utility/messaging/type/MessageActivateFile.h" #include "utility/messaging/type/MessageActivateNodes.h" +#include "utility/messaging/type/MessageActivateTokenIds.h" #include "utility/messaging/type/MessageActivateTokenLocations.h" #include "utility/messaging/type/MessageResetZoom.h" #include "utility/messaging/type/MessageSearch.h" @@ -23,6 +24,7 @@ class FeatureController , public MessageListener , public MessageListener , public MessageListener + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -38,6 +40,7 @@ private: virtual void handleMessage(MessageActivateFile* message); virtual void handleMessage(MessageActivateNodes* message); virtual void handleMessage(MessageSearch* message); + virtual void handleMessage(MessageActivateTokenIds* message); virtual void handleMessage(MessageActivateTokenLocations* message); virtual void handleMessage(MessageResetZoom* message); virtual void handleMessage(MessageSwitchColorScheme* message); diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 0308c3a1..2c656bce 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -4,6 +4,7 @@ #include "utility/logging/logging.h" #include "utility/utility.h" +#include "utility/utilityString.h" #include "component/controller/helper/DummyEdge.h" #include "component/controller/helper/DummyNode.h" @@ -23,6 +24,21 @@ GraphController::~GraphController() { } +void GraphController::handleMessage(MessageActivateAll* message) +{ + m_activeNodeIds.clear(); + m_activeEdgeIds.clear(); + + createDummyGraphForTokenIds(std::vector(), m_storageAccess->getGraphForAll()); + + bundleNodesByType(); + + layoutNesting(); + layoutGraph(); + + buildGraph(message); +} + void GraphController::handleMessage(MessageActivateTokens* message) { if (message->isEdge || message->keepContent()) @@ -49,7 +65,16 @@ void GraphController::handleMessage(MessageActivateTokens* message) return; } - createDummyGraphForTokenIds(utility::concat(m_activeNodeIds, m_activeEdgeIds)); + std::vector tokenIds = utility::concat(m_activeNodeIds, m_activeEdgeIds); + + std::shared_ptr graph = m_storageAccess->getGraphForActiveTokenIds(tokenIds); + + createDummyGraphForTokenIds(tokenIds, graph); + + bundleNodes(); + + layoutNesting(); + layoutGraph(); buildGraph(message); } @@ -76,7 +101,7 @@ void GraphController::handleMessage(MessageGraphNodeBundleSplit* message) DummyNode& node = m_dummyNodes[i]; if (node.isBundleNode() && node.tokenId == message->bundleId) { - m_dummyNodes.insert(m_dummyNodes.end(), node.bundledNodes.begin(), node.bundledNodes.end()); + m_dummyNodes.insert(m_dummyNodes.begin() + i + 1, node.bundledNodes.begin(), node.bundledNodes.end()); m_dummyNodes.erase(m_dummyNodes.begin() + i); break; } @@ -156,7 +181,7 @@ void GraphController::clear() getView()->clear(); } -void GraphController::createDummyGraphForTokenIds(const std::vector& tokenIds) +void GraphController::createDummyGraphForTokenIds(const std::vector& tokenIds, const std::shared_ptr graph) { GraphView* view = getView(); if (!view) @@ -165,8 +190,6 @@ void GraphController::createDummyGraphForTokenIds(const std::vector& tokenId return; } - std::shared_ptr graph = m_storageAccess->getGraphForActiveTokenIds(tokenIds); - m_dummyEdges.clear(); std::set addedNodes; @@ -190,6 +213,7 @@ void GraphController::createDummyGraphForTokenIds(const std::vector& tokenId for (DummyNode& node : dummyNodes) { node.hasParent = false; + node.name = node.data->getFullName(); } m_dummyNodes = dummyNodes; @@ -197,11 +221,6 @@ void GraphController::createDummyGraphForTokenIds(const std::vector& tokenId autoExpandActiveNode(tokenIds); setActiveAndVisibility(tokenIds); - bundleNodes(); - - layoutNesting(); - layoutGraph(); - m_graph = graph; } @@ -210,6 +229,7 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node) DummyNode result; result.data = node; result.tokenId = node->getId(); + result.name = node->getName(); // there is a global root node with id 0 afaik, so here we actually want the one node below this global root Node* parent = node; @@ -314,6 +334,8 @@ void GraphController::autoExpandActiveNode(const std::vector& activeTokenIds void GraphController::setActiveAndVisibility(const std::vector& activeTokenIds) { + bool noActive = activeTokenIds.size() == 0; + for (DummyNode& node : m_dummyNodes) { setNodeActiveRecursive(node, activeTokenIds); @@ -335,7 +357,7 @@ void GraphController::setActiveAndVisibility(const std::vector& activeTokenI DummyNode* from = findDummyNodeRecursive(m_dummyNodes, edge.ownerId); DummyNode* to = findDummyNodeRecursive(m_dummyNodes, edge.targetId); - if (from && to && (from->active || to->active || edge.active)) + if (from && to && (noActive || from->active || to->active || edge.active)) { edge.visible = true; from->connected = true; @@ -345,7 +367,7 @@ void GraphController::setActiveAndVisibility(const std::vector& activeTokenI for (DummyNode& node : m_dummyNodes) { - setNodeVisibilityRecursiveBottomUp(node); + setNodeVisibilityRecursiveBottomUp(node, noActive); } } @@ -364,7 +386,7 @@ void GraphController::setNodeActiveRecursive(DummyNode& node, const std::vector< } } -bool GraphController::setNodeVisibilityRecursiveBottomUp(DummyNode& node) const +bool GraphController::setNodeVisibilityRecursiveBottomUp(DummyNode& node, bool noActive) const { node.visible = false; node.childVisible = false; @@ -382,13 +404,13 @@ bool GraphController::setNodeVisibilityRecursiveBottomUp(DummyNode& node) const for (DummyNode& subNode : node.subNodes) { - if (setNodeVisibilityRecursiveBottomUp(subNode)) + if (setNodeVisibilityRecursiveBottomUp(subNode, noActive)) { node.childVisible = true; } } - if (node.active || node.connected || node.childVisible) + if (noActive || node.active || node.connected || node.childVisible) { setNodeVisibilityRecursiveTopDown(node, false); } @@ -617,6 +639,54 @@ bool GraphController::isTypeNodeWithSingleInheritance(const DummyNode& node, boo return matches; } +#define BUNDLE_BY_TYPE(__type__, __name__) \ + bundleNodesMatching( \ + [&](const DummyNode& node) \ + { \ + return node.visible && node.isGraphNode() && node.data->isType(__type__); \ + }, \ + 1, \ + __name__ \ + ); \ + +void GraphController::bundleNodesByType() +{ + BUNDLE_BY_TYPE(Node::NODE_CLASS, "Classes"); + BUNDLE_BY_TYPE(Node::NODE_STRUCT, "Structs"); + + BUNDLE_BY_TYPE(Node::NODE_FUNCTION, "Functions"); + BUNDLE_BY_TYPE(Node::NODE_GLOBAL_VARIABLE, "Global Variables"); + + BUNDLE_BY_TYPE(Node::NODE_TYPE, "Types"); + BUNDLE_BY_TYPE(Node::NODE_TYPEDEF, "Typedefs"); + BUNDLE_BY_TYPE(Node::NODE_ENUM, "Enums"); + + BUNDLE_BY_TYPE(Node::NODE_FILE, "Files"); + BUNDLE_BY_TYPE(Node::NODE_MACRO, "Macros"); + + // should never be visible + + BUNDLE_BY_TYPE(Node::NODE_METHOD, "Methods"); + BUNDLE_BY_TYPE(Node::NODE_FIELD, "Fields"); + BUNDLE_BY_TYPE(Node::NODE_ENUM_CONSTANT, "Enum Constants"); + BUNDLE_BY_TYPE(Node::NODE_TEMPLATE_PARAMETER_TYPE, "Template Parameter Types"); + BUNDLE_BY_TYPE(Node::NODE_UNDEFINED, "Undefined Symbols"); + BUNDLE_BY_TYPE(Node::NODE_NAMESPACE, "Namespaces"); + + for (DummyNode& node : m_dummyNodes) + { + if (node.isBundleNode()) + { + sort(node.bundledNodes.begin(), node.bundledNodes.end(), + [](const DummyNode& a, const DummyNode& b) -> bool + { + return utility::toLowerCase(a.name) < utility::toLowerCase(b.name); + } + ); + } + } +} + void GraphController::layoutNesting() { for (DummyNode& node : m_dummyNodes) @@ -663,15 +733,14 @@ void GraphController::layoutNestingRecursive(DummyNode& node) const if (node.isGraphNode()) { - if (!node.hasParent) + size_t maxNameSize = 50; + if (!node.active && node.name.size() > maxNameSize) { - width = margins.charWidth * node.data->getFullName().size(); - } - else - { - width = margins.charWidth * node.data->getName().size(); + node.name = node.name.substr(0, maxNameSize - 3) + "..."; } + width = margins.charWidth * node.name.size(); + if (node.data->isType(Node::NODE_TYPE | Node::NODE_CLASS | Node::NODE_STRUCT | Node::NODE_ENUM) && node.subNodes.size()) { addExpandToggleNode(node); diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 232f156f..20b9c7fd 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -4,6 +4,7 @@ #include #include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageActivateAll.h" #include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageFlushUpdates.h" #include "utility/messaging/type/MessageFocusIn.h" @@ -26,6 +27,7 @@ class StorageAccess; class GraphController : public Controller + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -40,6 +42,7 @@ public: ~GraphController(); private: + virtual void handleMessage(MessageActivateAll* message); virtual void handleMessage(MessageActivateTokens* message); virtual void handleMessage(MessageFlushUpdates* message); virtual void handleMessage(MessageFocusIn* message); @@ -53,20 +56,21 @@ private: void clear(); - void createDummyGraphForTokenIds(const std::vector& tokenIds); + void createDummyGraphForTokenIds(const std::vector& tokenIds, const std::shared_ptr graph); DummyNode createDummyNodeTopDown(Node* node); void autoExpandActiveNode(const std::vector& activeTokenIds); void setActiveAndVisibility(const std::vector& activeTokenIds); void setNodeActiveRecursive(DummyNode& node, const std::vector& activeTokenIds) const; - bool setNodeVisibilityRecursiveBottomUp(DummyNode& node) const; + bool setNodeVisibilityRecursiveBottomUp(DummyNode& node, bool noActive) const; void setNodeVisibilityRecursiveTopDown(DummyNode& node, bool parentExpanded) const; void bundleNodes(); void bundleNodesMatching(std::function matcher, size_t count, const std::string& name); bool isTypeNodeWithSingleAggregation(const DummyNode& node, TokenComponentAggregation::Direction direction) const; bool isTypeNodeWithSingleInheritance(const DummyNode& node, bool isBase) const; + void bundleNodesByType(); void layoutNesting(); void layoutNestingRecursive(DummyNode& node) const; diff --git a/src/lib/component/controller/SearchController.cpp b/src/lib/component/controller/SearchController.cpp index 3fa45e7d..e8fe7e1b 100644 --- a/src/lib/component/controller/SearchController.cpp +++ b/src/lib/component/controller/SearchController.cpp @@ -12,6 +12,12 @@ SearchController::~SearchController() { } +void SearchController::handleMessage(MessageActivateAll* message) +{ + SearchMatch match = SearchMatch::createCommand(SearchMatch::COMMAND_ALL); + getView()->setMatches(std::vector(1, match)); +} + void SearchController::handleMessage(MessageActivateTokens* message) { if (!message->keepContent() && !message->isFromSearch) @@ -33,7 +39,8 @@ void SearchController::handleMessage(MessageSearchAutocomplete* message) void SearchController::handleMessage(MessageShowErrors* message) { - getView()->setMatches(std::vector()); + SearchMatch match = SearchMatch::createCommand(SearchMatch::COMMAND_ERROR); + getView()->setMatches(std::vector(1, match)); } SearchView* SearchController::getView() diff --git a/src/lib/component/controller/SearchController.h b/src/lib/component/controller/SearchController.h index e47d90f4..2b11a7f5 100644 --- a/src/lib/component/controller/SearchController.h +++ b/src/lib/component/controller/SearchController.h @@ -3,6 +3,7 @@ #include "component/controller/Controller.h" #include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageActivateAll.h" #include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageFind.h" #include "utility/messaging/type/MessageSearchAutocomplete.h" @@ -13,6 +14,7 @@ class SearchView; class SearchController : public Controller + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -23,6 +25,7 @@ public: ~SearchController(); private: + virtual void handleMessage(MessageActivateAll* message); virtual void handleMessage(MessageActivateTokens* message); virtual void handleMessage(MessageFind* message); virtual void handleMessage(MessageSearchAutocomplete* message); diff --git a/src/lib/component/controller/UndoRedoController.cpp b/src/lib/component/controller/UndoRedoController.cpp index c2a6af34..f1a5a4ee 100644 --- a/src/lib/component/controller/UndoRedoController.cpp +++ b/src/lib/component/controller/UndoRedoController.cpp @@ -67,6 +67,18 @@ void UndoRedoController::handleMessage(MessageActivateNodes* message) processCommand(command); } +void UndoRedoController::handleMessage(MessageActivateTokenIds* message) +{ + if (m_lastCommand.message && m_lastCommand.message->getType() == message->getType() && message->tokenIds.size() && + static_cast(m_lastCommand.message.get())->tokenIds == message->tokenIds) + { + return; + } + + Command command(std::make_shared(*message), 0); + processCommand(command); +} + void UndoRedoController::handleMessage(MessageDeactivateEdge* message) { MessageBase* m = nullptr; @@ -140,23 +152,9 @@ void UndoRedoController::handleMessage(MessageRefresh* message) if (requiresActivateFallbackToken()) { - Id nodeId = m_storageAccess->getIdForNodeWithSearchNameHierarchy(NameHierarchy("main")); - if (!nodeId) - { - nodeId = m_storageAccess->getIdForFirstNode(); - } - - if (nodeId) - { - MessageActivateNodes m; - m.addNode( - nodeId, - m_storageAccess->getNodeTypeForNodeWithId(nodeId), - m_storageAccess->getNameHierarchyForNodeWithId(nodeId) - ); - m.isFromSystem = true; - m.dispatch(); - } + SearchMatch match = SearchMatch::createCommand(SearchMatch::COMMAND_ALL); + MessageSearch msg(std::vector(1, match)); + msg.dispatch(); } else { diff --git a/src/lib/component/controller/UndoRedoController.h b/src/lib/component/controller/UndoRedoController.h index c545cf29..f465b9d0 100644 --- a/src/lib/component/controller/UndoRedoController.h +++ b/src/lib/component/controller/UndoRedoController.h @@ -8,6 +8,7 @@ #include "utility/messaging/type/MessageActivateEdge.h" #include "utility/messaging/type/MessageActivateFile.h" #include "utility/messaging/type/MessageActivateNodes.h" +#include "utility/messaging/type/MessageActivateTokenIds.h" #include "utility/messaging/type/MessageDeactivateEdge.h" #include "utility/messaging/type/MessageGraphNodeBundleSplit.h" #include "utility/messaging/type/MessageGraphNodeExpand.h" @@ -32,6 +33,7 @@ class UndoRedoController , public MessageListener , public MessageListener , public MessageListener + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -63,6 +65,7 @@ private: virtual void handleMessage(MessageActivateEdge* message); virtual void handleMessage(MessageActivateFile* message); virtual void handleMessage(MessageActivateNodes* message); + virtual void handleMessage(MessageActivateTokenIds* message); virtual void handleMessage(MessageDeactivateEdge* message); virtual void handleMessage(MessageGraphNodeBundleSplit* message); virtual void handleMessage(MessageGraphNodeExpand* message); diff --git a/src/lib/component/controller/helper/ActivationTranslator.cpp b/src/lib/component/controller/helper/ActivationTranslator.cpp index 9a63b0ae..44c159f9 100644 --- a/src/lib/component/controller/helper/ActivationTranslator.cpp +++ b/src/lib/component/controller/helper/ActivationTranslator.cpp @@ -1,11 +1,14 @@ #include "component/controller/helper/ActivationTranslator.h" #include "data/access/StorageAccess.h" +#include "utility/messaging/type/MessageActivateAll.h" #include "utility/messaging/type/MessageActivateEdge.h" #include "utility/messaging/type/MessageActivateFile.h" #include "utility/messaging/type/MessageActivateNodes.h" +#include "utility/messaging/type/MessageActivateTokenIds.h" #include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageSearch.h" +#include "utility/messaging/type/MessageShowErrors.h" #include "utility/messaging/type/MessageShowFile.h" ActivationTranslator::ActivationTranslator(StorageAccess* storageAccess) @@ -99,9 +102,40 @@ std::shared_ptr ActivationTranslator::translateMessage(co return m; } +std::shared_ptr ActivationTranslator::translateMessage(const MessageActivateTokenIds* message) const +{ + std::shared_ptr m; + m = std::make_shared(message->tokenIds); + m->undoRedoType = message->undoRedoType; + m->setKeepContent(message->keepContent()); + return m; +} + std::shared_ptr ActivationTranslator::translateMessage(const MessageSearch* message) const { - std::vector tokenIds = m_storageAccess->getTokenIdsForMatches(message->getMatches()); + const std::vector& matches = message->getMatches(); + + for (const SearchMatch& match : matches) + { + if (match.searchType == SearchMatch::SEARCH_COMMAND && + match.getFullName() == SearchMatch::getCommandName(SearchMatch::COMMAND_ALL)) + { + MessageActivateAll msg; + msg.undoRedoType = message->undoRedoType; + msg.dispatchImmediately(); + return nullptr; + } + else if (match.searchType == SearchMatch::SEARCH_COMMAND && + match.getFullName() == SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR)) + { + MessageShowErrors msg; + msg.undoRedoType = message->undoRedoType; + msg.dispatchImmediately(); + return nullptr; + } + } + + std::vector tokenIds = m_storageAccess->getTokenIdsForMatches(matches); tokenIds = m_storageAccess->getActiveTokenIdsForTokenIds(tokenIds); std::shared_ptr m; diff --git a/src/lib/component/controller/helper/ActivationTranslator.h b/src/lib/component/controller/helper/ActivationTranslator.h index 33d13cc8..13a348eb 100644 --- a/src/lib/component/controller/helper/ActivationTranslator.h +++ b/src/lib/component/controller/helper/ActivationTranslator.h @@ -6,6 +6,7 @@ class MessageActivateEdge; class MessageActivateFile; class MessageActivateNodes; +class MessageActivateTokenIds; class MessageActivateTokens; class MessageSearch; class StorageAccess; @@ -19,6 +20,7 @@ public: std::shared_ptr translateMessage(const MessageActivateEdge* message) const; std::shared_ptr translateMessage(const MessageActivateFile* message) const; std::shared_ptr translateMessage(const MessageActivateNodes* message) const; + std::shared_ptr translateMessage(const MessageActivateTokenIds* message) const; std::shared_ptr translateMessage(const MessageSearch* message) const; private: diff --git a/src/lib/component/controller/helper/BucketGrid.cpp b/src/lib/component/controller/helper/BucketGrid.cpp index 3cd3f1d6..1ae4c17c 100644 --- a/src/lib/component/controller/helper/BucketGrid.cpp +++ b/src/lib/component/controller/helper/BucketGrid.cpp @@ -126,13 +126,18 @@ void BucketGrid::createBuckets(std::vector& nodes, const std::vector< bool activeNodeAdded = false; for (DummyNode& node : nodes) { - if (node.hasActiveSubNode()) + if (node.hasActiveSubNode() || !edges.size()) { addNode(&node); activeNodeAdded = true; } } + if (!edges.size()) + { + return; + } + if (!activeNodeAdded) { addNode(&nodes[0]); diff --git a/src/lib/component/controller/helper/DummyNode.h b/src/lib/component/controller/helper/DummyNode.h index 14f20424..3ec7df0c 100644 --- a/src/lib/component/controller/helper/DummyNode.h +++ b/src/lib/component/controller/helper/DummyNode.h @@ -114,6 +114,8 @@ public: // GraphNode const Node* data; + std::string name; + bool active; bool connected; bool expanded; @@ -127,7 +129,6 @@ public: // BundleNode std::vector bundledNodes; - std::string name; }; #endif // DUMMY_NODE_H diff --git a/src/lib/data/HierarchyCache.cpp b/src/lib/data/HierarchyCache.cpp index e6123c31..28ec422d 100644 --- a/src/lib/data/HierarchyCache.cpp +++ b/src/lib/data/HierarchyCache.cpp @@ -135,6 +135,27 @@ void HierarchyCache::addFirstVisibleChildIdsForNodeId(Id nodeId, std::vector } } +bool HierarchyCache::isChildOfVisibleNodeOrInvisible(Id nodeId) const +{ + HierarchyNode* node = getNode(nodeId); + if (!node) + { + return false; + } + + if (!node->isVisible()) + { + return true; + } + + if (node->getParent() && node->getParent()->isVisible()) + { + return true; + } + + return false; +} + HierarchyCache::HierarchyNode* HierarchyCache::getNode(Id nodeId) const { std::map>::const_iterator it = m_nodes.find(nodeId); diff --git a/src/lib/data/HierarchyCache.h b/src/lib/data/HierarchyCache.h index efea6eb8..81c60959 100644 --- a/src/lib/data/HierarchyCache.h +++ b/src/lib/data/HierarchyCache.h @@ -19,6 +19,8 @@ public: void addAllChildIdsForNodeId(Id nodeId, std::vector* nodeIds, std::vector* edgeIds) const; void addFirstVisibleChildIdsForNodeId(Id nodeId, std::vector* nodeIds) const; + bool isChildOfVisibleNodeOrInvisible(Id nodeId) const; + private: class HierarchyNode { diff --git a/src/lib/data/SqliteStorage.cpp b/src/lib/data/SqliteStorage.cpp index 6451eda7..2406dd10 100644 --- a/src/lib/data/SqliteStorage.cpp +++ b/src/lib/data/SqliteStorage.cpp @@ -119,10 +119,11 @@ Id SqliteStorage::addFile(const std::string& serializedName, const std::string& { Id id = addNode(Node::NODE_FILE, serializedName, true); std::shared_ptr content = TextAccess::createFromFile(filePath); + unsigned int loc = content->getLineCount(); CppSQLite3Statement stmt = m_database.compileStatement(( - "INSERT INTO file(id, path, modification_time, content) VALUES(" - + std::to_string(id) + ", '" + filePath + "', '" + modificationTime + "', ?);" + "INSERT INTO file(id, path, modification_time, content, loc) VALUES(" + + std::to_string(id) + ", '" + filePath + "', '" + modificationTime + "', ?, " + std::to_string(loc) + ");" ).c_str()); stmt.bind(1, content->getText().c_str()); @@ -653,6 +654,11 @@ int SqliteStorage::getFileCount() const return m_database.execScalar("SELECT COUNT(*) FROM file;"); } +int SqliteStorage::getFileLOCCount() const +{ + return m_database.execScalar("SELECT SUM(loc) FROM file;"); +} + int SqliteStorage::getSourceLocationCount() const { return m_database.execScalar("SELECT COUNT(*) FROM source_location;"); @@ -719,6 +725,7 @@ void SqliteStorage::setupTables() "path TEXT, " "modification_time TEXT, " "content TEXT, " + "loc INTEGER, " "PRIMARY KEY(id), " "FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE);" ); diff --git a/src/lib/data/SqliteStorage.h b/src/lib/data/SqliteStorage.h index 588def9d..0f4b295c 100644 --- a/src/lib/data/SqliteStorage.h +++ b/src/lib/data/SqliteStorage.h @@ -98,6 +98,7 @@ public: int getNodeCount() const; int getEdgeCount() const; int getFileCount() const; + int getFileLOCCount() const; int getSourceLocationCount() const; private: diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index ea5e81c5..a2ad8846 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -40,6 +40,9 @@ Version Storage::getVersion() const bool Storage::init() { + m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL))); + m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR))); + return m_sqliteStorage.init(); } @@ -141,19 +144,21 @@ const SearchIndex& Storage::getSearchIndex() const void Storage::logStats() const { std::stringstream ss; + StorageStats stats = getStorageStats(); ss << "\nGraph:\n"; - ss << "\t" << m_sqliteStorage.getNodeCount() << " Nodes\n"; - ss << "\t" << m_sqliteStorage.getEdgeCount() << " Edges\n"; + ss << "\t" << stats.nodeCount << " Nodes\n"; + ss << "\t" << stats.edgeCount << " Edges\n"; ss << "\nSearch:\n"; - ss << "\t" << m_tokenIndex.getCharCount() << " Characters\n"; - ss << "\t" << m_tokenIndex.getWordCount() << " Words\n"; - ss << "\t" << m_tokenIndex.getNodeCount() << " SearchNodes\n"; + ss << "\t" << stats.charCount << " Characters\n"; + ss << "\t" << stats.wordCount << " Words\n"; + ss << "\t" << stats.searchNodeCount << " SearchNodes\n"; ss << "\nCode:\n"; - ss << "\t" << m_sqliteStorage.getFileCount() << " Files\n"; - ss << "\t" << m_sqliteStorage.getSourceLocationCount() << " Source Locations\n"; + ss << "\t" << stats.fileCount << " Files\n"; + ss << "\t" << stats.fileLOCCount << " Lines of Code\n"; + ss << "\t" << stats.sourceLocationCount << " Source Locations\n"; LOG_WARNING(ss.str()); } @@ -812,7 +817,12 @@ std::vector Storage::getAutocompletionMatches(const std::string& qu m_cachedQuery = query; - std::vector matches = SearchIndex::getMatches(m_cachedResults, query); + SearchResults results = m_cachedResults; + SearchResults commandResults = m_commandIndex.runFuzzySearch(query); + results.insert(commandResults.begin(), commandResults.end()); + + std::vector matches = SearchIndex::getMatches(results, query); + LOG_INFO_STREAM(<< matches.size() << " matches for \"" << query << "\""); if (matches.size() > 100) @@ -825,6 +835,7 @@ std::vector Storage::getAutocompletionMatches(const std::string& qu if (!match.tokenIds.size()) { match.searchType = SearchMatch::SEARCH_COMMAND; + match.typeName = "command"; continue; } @@ -883,6 +894,25 @@ std::vector Storage::getSearchMatchesForTokenIds(const std::vector< return matches; } +std::shared_ptr Storage::getGraphForAll() const +{ + std::shared_ptr graph = std::make_shared(); + + std::vector tokenIds; + for (StorageNode node: m_sqliteStorage.getAllNodes()) + { + if (node.defined && Node::intToType(node.type) != Node::NODE_TEMPLATE_PARAMETER_TYPE + && !m_hierarchyCache.isChildOfVisibleNodeOrInvisible(node.id)) + { + tokenIds.push_back(node.id); + } + } + + addNodesToGraph(tokenIds, graph.get()); + + return graph; +} + std::shared_ptr Storage::getGraphForActiveTokenIds(const std::vector& tokenIds) const { std::shared_ptr g = std::make_shared(); @@ -1293,6 +1323,26 @@ TimePoint Storage::getFileModificationTime(const FilePath& filePath) const return TimePoint(m_sqliteStorage.getFileByPath(filePath.str()).modificationTime); } +StorageStats Storage::getStorageStats() const +{ + StorageStats stats; + + stats.nodeCount = m_sqliteStorage.getNodeCount(); + stats.edgeCount = m_sqliteStorage.getEdgeCount(); + + stats.charCount = m_tokenIndex.getCharCount(); + stats.wordCount = m_tokenIndex.getWordCount(); + stats.searchNodeCount = m_tokenIndex.getNodeCount(); + + stats.fileCount = m_sqliteStorage.getFileCount(); + stats.fileLOCCount = m_sqliteStorage.getFileLOCCount(); + stats.sourceLocationCount = m_sqliteStorage.getSourceLocationCount(); + + stats.errorCount = getErrorCount(); + + return stats; +} + Id Storage::addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarchy, bool defined) { if (nameHierarchy.size() == 0) diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index bd82bce1..63b2046d 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -146,6 +146,7 @@ public: virtual std::vector getAutocompletionMatches(const std::string& query) const; virtual std::vector getSearchMatchesForTokenIds(const std::vector& tokenIds) const; + virtual std::shared_ptr getGraphForAll() const; virtual std::shared_ptr getGraphForActiveTokenIds(const std::vector& tokenIds) const; virtual std::vector getActiveTokenIdsForTokenIds(const std::vector& tokenIds) const; @@ -171,6 +172,8 @@ public: virtual std::shared_ptr getFileContent(const FilePath& filePath) const; virtual TimePoint getFileModificationTime(const FilePath& filePath) const; + virtual StorageStats getStorageStats() const; + private: Id addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarchy, bool defined); Id addNodeHierarchy(Node::NodeType type, const ParseFunction& function, bool defined); @@ -205,6 +208,8 @@ private: void log(std::string type, std::string str, const ParseLocation& location) const; SearchIndex m_tokenIndex; + SearchIndex m_commandIndex; + SqliteStorage m_sqliteStorage; mutable std::map m_fileNodeIds; diff --git a/src/lib/data/StorageStats.h b/src/lib/data/StorageStats.h new file mode 100644 index 00000000..2aa11035 --- /dev/null +++ b/src/lib/data/StorageStats.h @@ -0,0 +1,32 @@ +#ifndef STORAGE_STATS_H +#define STORAGE_STATS_H + +struct StorageStats +{ + StorageStats() + : nodeCount(0) + , edgeCount(0) + , charCount(0) + , wordCount(0) + , searchNodeCount(0) + , fileCount(0) + , fileLOCCount(0) + , sourceLocationCount(0) + , errorCount(0) + {} + + size_t nodeCount; + size_t edgeCount; + + size_t charCount; + size_t wordCount; + size_t searchNodeCount; + + size_t fileCount; + size_t fileLOCCount; + size_t sourceLocationCount; + + size_t errorCount; +}; + +#endif // STORAGE_STATS_H diff --git a/src/lib/data/access/StorageAccess.h b/src/lib/data/access/StorageAccess.h index 46c625b7..4da0a04f 100644 --- a/src/lib/data/access/StorageAccess.h +++ b/src/lib/data/access/StorageAccess.h @@ -10,6 +10,7 @@ #include "data/graph/Node.h" #include "data/search/SearchMatch.h" +#include "data/StorageStats.h" struct FileInfo; class Graph; @@ -37,6 +38,7 @@ public: virtual std::vector getAutocompletionMatches(const std::string& query) const = 0; virtual std::vector getSearchMatchesForTokenIds(const std::vector& tokenIds) const = 0; + virtual std::shared_ptr getGraphForAll() const = 0; virtual std::shared_ptr getGraphForActiveTokenIds(const std::vector& tokenIds) const = 0; virtual std::vector getActiveTokenIdsForTokenIds(const std::vector& tokenIds) const = 0; @@ -60,6 +62,8 @@ public: virtual std::shared_ptr getFileContent(const FilePath& filePath) const = 0; virtual TimePoint getFileModificationTime(const FilePath& filePath) const = 0; + + virtual StorageStats getStorageStats() const = 0; }; #endif // STORAGE_ACCESS_H diff --git a/src/lib/data/access/StorageAccessProxy.cpp b/src/lib/data/access/StorageAccessProxy.cpp index 31daabb9..7264055e 100644 --- a/src/lib/data/access/StorageAccessProxy.cpp +++ b/src/lib/data/access/StorageAccessProxy.cpp @@ -113,6 +113,16 @@ std::vector StorageAccessProxy::getSearchMatchesForTokenIds(const s return std::vector(); } +std::shared_ptr StorageAccessProxy::getGraphForAll() const +{ + if (hasSubject()) + { + return m_subject->getGraphForAll(); + } + + return std::make_shared(); +} + std::shared_ptr StorageAccessProxy::getGraphForActiveTokenIds(const std::vector& tokenIds) const { if (hasSubject()) @@ -274,3 +284,13 @@ TimePoint StorageAccessProxy::getFileModificationTime(const FilePath& filePath) return TimePoint(boost::posix_time::not_a_date_time); } + +StorageStats StorageAccessProxy::getStorageStats() const +{ + if (hasSubject()) + { + return m_subject->getStorageStats(); + } + + return StorageStats(); +} diff --git a/src/lib/data/access/StorageAccessProxy.h b/src/lib/data/access/StorageAccessProxy.h index 9758d754..a5d68d74 100644 --- a/src/lib/data/access/StorageAccessProxy.h +++ b/src/lib/data/access/StorageAccessProxy.h @@ -26,6 +26,7 @@ public: virtual std::vector getAutocompletionMatches(const std::string& query) const; virtual std::vector getSearchMatchesForTokenIds(const std::vector& tokenIds) const; + virtual std::shared_ptr getGraphForAll() const; virtual std::shared_ptr getGraphForActiveTokenIds(const std::vector& tokenIds) const; virtual std::vector getActiveTokenIdsForTokenIds(const std::vector& tokenIds) const; @@ -51,6 +52,8 @@ public: virtual std::shared_ptr getFileContent(const FilePath& filePath) const; virtual TimePoint getFileModificationTime(const FilePath& filePath) const; + virtual StorageStats getStorageStats() const; + private: StorageAccess* m_subject; }; diff --git a/src/lib/data/search/SearchMatch.cpp b/src/lib/data/search/SearchMatch.cpp index 33a71337..d30d80a3 100644 --- a/src/lib/data/search/SearchMatch.cpp +++ b/src/lib/data/search/SearchMatch.cpp @@ -45,6 +45,28 @@ std::string SearchMatch::searchMatchesToString(const std::vector& m return ss.str(); } +SearchMatch SearchMatch::createCommand(CommandType type) +{ + SearchMatch match; + match.nameHierarchy = NameHierarchy(getCommandName(type)); + match.typeName = "command"; + match.searchType = SEARCH_COMMAND; + return match; +} + +std::string SearchMatch::getCommandName(CommandType type) +{ + switch (type) + { + case COMMAND_ALL: + return "overview"; + case COMMAND_ERROR: + return "error"; + } + + return "none"; +} + SearchMatch::SearchMatch() : typeName("") , searchType(SEARCH_NONE) diff --git a/src/lib/data/search/SearchMatch.h b/src/lib/data/search/SearchMatch.h index 76d39673..aa6f94eb 100644 --- a/src/lib/data/search/SearchMatch.h +++ b/src/lib/data/search/SearchMatch.h @@ -19,11 +19,20 @@ struct SearchMatch SEARCH_OPERATOR }; + enum CommandType + { + COMMAND_ALL, + COMMAND_ERROR + }; + static void log(const std::vector& matches, const std::string& query); static std::string getSearchTypeName(SearchType type); static std::string searchMatchesToString(const std::vector& matches); + static SearchMatch createCommand(CommandType type); + static std::string getCommandName(CommandType type); + SearchMatch(); SearchMatch(const std::string& query); diff --git a/src/lib/settings/ProjectSettings.cpp b/src/lib/settings/ProjectSettings.cpp index ef68808a..68f13813 100644 --- a/src/lib/settings/ProjectSettings.cpp +++ b/src/lib/settings/ProjectSettings.cpp @@ -122,3 +122,8 @@ bool ProjectSettings::setSourceExtensions(const std::vector &source { return setValues("source/extensions/source_extensions", sourceExtensions); } + +std::string ProjectSettings::getDescription() const +{ + return getValue("info/description", ""); +} diff --git a/src/lib/settings/ProjectSettings.h b/src/lib/settings/ProjectSettings.h index 4af52e79..596e6389 100644 --- a/src/lib/settings/ProjectSettings.h +++ b/src/lib/settings/ProjectSettings.h @@ -18,6 +18,9 @@ public: virtual void save(const FilePath& filePath); + // info + std::string getDescription() const; + // language settings std::string getLanguage() const; bool setLanguage(const std::string& language); diff --git a/src/lib/utility/messaging/type/MessageActivateAll.h b/src/lib/utility/messaging/type/MessageActivateAll.h new file mode 100644 index 00000000..eb642ca9 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageActivateAll.h @@ -0,0 +1,20 @@ +#ifndef MESSAGE_ACTIVATE_ALL_H +#define MESSAGE_ACTIVATE_ALL_H + +#include "utility/messaging/Message.h" + +class MessageActivateAll + : public Message +{ +public: + MessageActivateAll() + { + } + + static const std::string getStaticType() + { + return "MessageActivateAll"; + } +}; + +#endif // MESSAGE_ACTIVATE_ALL_H diff --git a/src/lib/utility/messaging/type/MessageActivateTokenIds.h b/src/lib/utility/messaging/type/MessageActivateTokenIds.h new file mode 100644 index 00000000..53e72d13 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageActivateTokenIds.h @@ -0,0 +1,32 @@ +#ifndef MESSAGE_ACTIVATE_TOKEN_IDS_H +#define MESSAGE_ACTIVATE_TOKEN_IDS_H + +#include "utility/messaging/Message.h" +#include "utility/types.h" + +class MessageActivateTokenIds + : public Message +{ +public: + MessageActivateTokenIds(const std::vector& tokenIds) + : tokenIds(tokenIds) + { + } + + static const std::string getStaticType() + { + return "MessageActivateTokenIds"; + } + + virtual void print(std::ostream& os) const + { + for (const Id& id : tokenIds) + { + os << id << " "; + } + } + + const std::vector tokenIds; +}; + +#endif // MESSAGE_ACTIVATE_TOKEN_IDS_H diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index 9b206b10..81df0ce7 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -128,6 +128,13 @@ namespace utility return res.first == prefix.end(); } + std::string toUpperCase(const std::string& in) + { + std::string out; + std::transform(in.begin(), in.end(), std::back_inserter(out), toupper); + return out; + } + std::string toLowerCase(const std::string& in) { std::string out; diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 1f8b656a..c7435bef 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -34,6 +34,7 @@ namespace utility bool isPrefix(const std::string& prefix, const std::string& text); + std::string toUpperCase(const std::string& in); std::string toLowerCase(const std::string& in); bool equalsCaseInsensitive(const std::string& a, const std::string& b); diff --git a/src/lib_gui/qt/element/QtAutocompletionList.cpp b/src/lib_gui/qt/element/QtAutocompletionList.cpp index 4e6c44cd..31e8c45d 100644 --- a/src/lib_gui/qt/element/QtAutocompletionList.cpp +++ b/src/lib_gui/qt/element/QtAutocompletionList.cpp @@ -105,7 +105,7 @@ void QtAutocompletionDelegate::paint(QPainter* painter, const QStyleOptionViewIt QColor color("#FFFFFF"); Node::NodeType nodeType = static_cast(index.sibling(index.row(), index.column() + 3).data().toInt()); - if (type.size()) + if (type.size() && type != "command") { color = QColor(GraphViewStyle::getNodeColor(Node::getTypeString(nodeType), false).fill.c_str()); } diff --git a/src/lib_gui/qt/element/QtCodeArea.cpp b/src/lib_gui/qt/element/QtCodeArea.cpp index e58b9cb4..bec2de11 100644 --- a/src/lib_gui/qt/element/QtCodeArea.cpp +++ b/src/lib_gui/qt/element/QtCodeArea.cpp @@ -10,6 +10,7 @@ #include #include "utility/messaging/type/MessageActivateTokenLocations.h" +#include "utility/messaging/type/MessageActivateTokenIds.h" #include "utility/messaging/type/MessageShowFile.h" #include "utility/messaging/type/MessageFocusIn.h" #include "utility/messaging/type/MessageFocusOut.h" @@ -369,21 +370,41 @@ void QtCodeArea::mouseReleaseEvent(QMouseEvent* event) m_eventPosition = event->pos(); setIDECursorPosition(); } - else + else if (!m_fileWidget->getErrorMessages().size()) { QTextCursor cursor = this->cursorForPosition(event->pos()); - std::vector locationIds = findLocationIdsForPosition(cursor.position()); - if (locationIds.size() && !m_fileWidget->getErrorMessages().size()) + std::vector annotations = getAnnotationsForPosition(cursor.position()); + + std::vector locationIds; + std::vector tokenIds; + + for (const Annotation* annotation : annotations) + { + if (annotation->locationId > 0) + { + locationIds.push_back(annotation->locationId); + } + if (annotation->tokenId > 0) + { + tokenIds.push_back(annotation->tokenId); + } + } + + if (locationIds.size()) { MessageActivateTokenLocations(locationIds).dispatch(); } + else if (tokenIds.size()) + { + MessageActivateTokenIds(tokenIds).dispatch(); + } } } } void QtCodeArea::mouseDoubleClickEvent(QMouseEvent* event) { - if (event->button() == Qt::LeftButton) + if (event->button() == Qt::LeftButton && m_fileWidget->getFilePath().str().size()) { MessageShowFile(m_fileWidget->getFilePath().str(), (m_fileWidget->getErrorMessages().size() > 0)).dispatch(); } @@ -482,21 +503,6 @@ void QtCodeArea::setIDECursorPosition() MessageMoveIDECursor(m_locationFile->getFilePath().str(), lineColumn.first, lineColumn.second).dispatch(); } -std::vector QtCodeArea::findLocationIdsForPosition(int pos) const -{ - std::vector locationIds; - - for (const Annotation& annotation : m_annotations) - { - if (!annotation.isScope && pos >= annotation.start && pos <= annotation.end) - { - locationIds.push_back(annotation.locationId); - } - } - - return locationIds; -} - std::vector QtCodeArea::getAnnotationsForPosition(int pos) const { std::vector annotations; diff --git a/src/lib_gui/qt/element/QtCodeArea.h b/src/lib_gui/qt/element/QtCodeArea.h index 22be4d61..984f1241 100644 --- a/src/lib_gui/qt/element/QtCodeArea.h +++ b/src/lib_gui/qt/element/QtCodeArea.h @@ -134,7 +134,6 @@ private: std::string fill; }; - std::vector findLocationIdsForPosition(int pos) const; std::vector getAnnotationsForPosition(int pos) const; void createAnnotations(std::shared_ptr locationFile); diff --git a/src/lib_gui/qt/element/QtCodeFile.cpp b/src/lib_gui/qt/element/QtCodeFile.cpp index 009fd1ae..38c81337 100644 --- a/src/lib_gui/qt/element/QtCodeFile.cpp +++ b/src/lib_gui/qt/element/QtCodeFile.cpp @@ -57,6 +57,11 @@ QtCodeFile::QtCodeFile(const FilePath& filePath, QtCodeFileList* parent) titleLayout->addWidget(m_title); + if (m_title->text().size() == 0) + { + m_title->hide(); + } + m_titleBar->setMinimumHeight(m_title->height() + 4); m_referenceCount = new QLabel(this); diff --git a/src/lib_gui/qt/view/QtGraphView.cpp b/src/lib_gui/qt/view/QtGraphView.cpp index e75a2dd4..0b155007 100644 --- a/src/lib_gui/qt/view/QtGraphView.cpp +++ b/src/lib_gui/qt/view/QtGraphView.cpp @@ -324,7 +324,7 @@ std::shared_ptr QtGraphView::createNodeRecursive( std::shared_ptr newNode; if (node.isGraphNode()) { - newNode = std::make_shared(node.data, node.hasParent, node.childVisible); + newNode = std::make_shared(node.data, node.name, node.hasParent, node.childVisible); } else if (node.isAccessNode()) { diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp b/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp index 06220e25..07cda5d2 100644 --- a/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp +++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeData.cpp @@ -7,20 +7,13 @@ #include "data/graph/token_component/TokenComponentSignature.h" -QtGraphNodeData::QtGraphNodeData(const Node* data, bool hasParent, bool childVisible) +QtGraphNodeData::QtGraphNodeData(const Node* data, const std::string& name, bool hasParent, bool childVisible) : m_data(data) , m_childVisible(childVisible) { this->setAcceptHoverEvents(true); - if (!hasParent) - { - this->setName(data->getFullName()); - } - else - { - this->setName(data->getName()); - } + this->setName(name); std::string toolTip = data->getTypeString(); if (!data->isDefined() && !data->isType(Node::NODE_UNDEFINED)) diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeData.h b/src/lib_gui/qt/view/graphElements/QtGraphNodeData.h index 8d2aa246..34c23c23 100644 --- a/src/lib_gui/qt/view/graphElements/QtGraphNodeData.h +++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeData.h @@ -7,7 +7,7 @@ class QtGraphNodeData : public QtGraphNode { public: - QtGraphNodeData(const Node* data, bool hasParent, bool childVisible); + QtGraphNodeData(const Node* data, const std::string& name, bool hasParent, bool childVisible); virtual ~QtGraphNodeData(); const Node* getData() const; diff --git a/web/documentation/img/error_view.png b/web/documentation/img/error_view.png index ce147ca3..c323daf8 100644 Binary files a/web/documentation/img/error_view.png and b/web/documentation/img/error_view.png differ diff --git a/web/documentation/index.html b/web/documentation/index.html index f8ec26db..af14fbaf 100644 --- a/web/documentation/index.html +++ b/web/documentation/index.html @@ -24,13 +24,13 @@ body { padding-top: 20px; } - + #nav { position:fixed; width: 20%; margin-left: 2%; } - + .tocify { position:static; width: 100%; @@ -50,14 +50,14 @@
-
-