diff --git a/src/app/qt/view/QtGraphView.cpp b/src/app/qt/view/QtGraphView.cpp index 11d67f89..797f369b 100644 --- a/src/app/qt/view/QtGraphView.cpp +++ b/src/app/qt/view/QtGraphView.cpp @@ -190,7 +190,7 @@ std::shared_ptr QtGraphView::createNodeRecursive( } else { - newNode = std::make_shared(node.accessType, node.expanded, node.invisibleSubNodeCount); + newNode = std::make_shared(node.accessType, node.isExpanded(), node.invisibleSubNodeCount); } newNode->setPosition(node.position); diff --git a/src/app/qt/view/graphElements/QtGraphEdge.cpp b/src/app/qt/view/graphElements/QtGraphEdge.cpp index c85bcd64..68f39de6 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.cpp +++ b/src/app/qt/view/graphElements/QtGraphEdge.cpp @@ -90,6 +90,11 @@ QtCorneredConnection::QtCorneredConnection( , m_targetParentRect(targetParentRect) { this->setAcceptHoverEvents(true); + + m_ownerRect.x = m_ownerRect.x - 1; + m_ownerRect.z = m_ownerRect.z + 1; + m_targetRect.x = m_targetRect.x - 1; + m_targetRect.z = m_targetRect.z + 1; } QtCorneredConnection::~QtCorneredConnection() @@ -214,8 +219,8 @@ void QtCorneredConnection::paint(QPainter *painter, const QStyleOptionGraphicsIt } } - int arrowLength = 3; - int arrowWidth = 6; + int arrowLength = 5; + int arrowWidth = 8; QPointF arrow = poly.at(0) + QPointF((poly.at(0).x() - poly.at(1).x() > 0 ? -1 : 1) * arrowLength, -arrowWidth / 2); path.lineTo(arrow); @@ -410,7 +415,7 @@ void QtGraphEdge::updateLine() break; } - m_child->setPen(QPen(color, getPenWidth())); + m_child->setPen(QPen(color, getPenWidth(), Qt::SolidLine, Qt::RoundCap)); setIsActive(m_isActive); } @@ -433,7 +438,7 @@ void QtGraphEdge::setIsActive(bool isActive) else { QPen p = m_child->pen(); - p.setWidth(getPenWidth() + 1); + p.setWidthF(getPenWidth() + 1); m_child->setPen(p); } this->setZValue(getZValue(isActive)); @@ -447,7 +452,7 @@ void QtGraphEdge::setIsActive(bool isActive) else { QPen p = m_child->pen(); - p.setWidth(getPenWidth()); + p.setWidthF(getPenWidth()); m_child->setPen(p); } this->setZValue(getZValue(isActive)); @@ -530,13 +535,13 @@ int QtGraphEdge::getZValue(bool active) const return 1; } -int QtGraphEdge::getPenWidth() const +float QtGraphEdge::getPenWidth() const { if (isAggregation()) { return getAggregationCount() + 1; } - return 1; + return 1.5; } int QtGraphEdge::getAggregationCount() const diff --git a/src/app/qt/view/graphElements/QtGraphEdge.h b/src/app/qt/view/graphElements/QtGraphEdge.h index ddafab30..ae459851 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.h +++ b/src/app/qt/view/graphElements/QtGraphEdge.h @@ -77,7 +77,7 @@ protected: private: bool isAggregation() const; int getZValue(bool active) const; - int getPenWidth() const; + float getPenWidth() const; int getAggregationCount() const; std::weak_ptr m_owner; diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 357fe956..36ac6fa0 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -61,7 +61,15 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message) DummyNode* node = findDummyNodeAccessRecursive(m_dummyNodes, message->tokenId, message->access); if (node) { - node->expanded = !node->expanded; + if (node->autoExpanded) + { + node->autoExpanded = false; + node->expanded = false; + } + else + { + node->expanded = !node->expanded; + } setActiveAndVisibility(m_currentActiveTokenIds); layoutNesting(); @@ -125,6 +133,7 @@ void GraphController::createDummyGraphForTokenIds(const std::vector& tokenId m_dummyNodes = dummyNodes; + autoExpandActiveNode(tokenIds); setActiveAndVisibility(tokenIds); layoutNesting(); @@ -210,6 +219,28 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node) return result; } +void GraphController::autoExpandActiveNode(const std::vector& activeTokenIds) +{ + DummyNode* node = nullptr; + if (activeTokenIds.size() == 1) + { + node = findDummyNodeRecursive(m_dummyNodes, activeTokenIds[0]); + } + + if (!node) + { + return; + } + + if (node->data->isType(Node::NODE_CLASS | Node::NODE_STRUCT)) + { + for (DummyNode& subNode : node->subNodes) + { + subNode.autoExpanded = true; + } + } +} + void GraphController::setActiveAndVisibility(const std::vector& activeTokenIds) { for (DummyNode& node : m_dummyNodes) @@ -262,7 +293,7 @@ void GraphController::setNodeVisibilityRecursiveTopDown(DummyNode& node) const for (DummyNode& subNode : node.subNodes) { - if (subNode.accessType != TokenComponentAccess::ACCESS_NONE || node.expanded || + if (subNode.accessType != TokenComponentAccess::ACCESS_NONE || node.isExpanded() || (node.data && node.data->isType(Node::NODE_ENUM)) || (node.active && node.data && node.data->isType(Node::NODE_NAMESPACE | Node::NODE_UNDEFINED))) { @@ -308,7 +339,7 @@ void GraphController::layoutNestingRecursive(DummyNode& node) const layoutNestingRecursive(subNode); - if (subNode.data || subNode.expanded || subNode.invisibleSubNodeCount != subNode.subNodes.size()) + if (subNode.data || subNode.isExpanded() || subNode.invisibleSubNodeCount != subNode.subNodes.size()) { layoutHorizontal = false; } @@ -441,7 +472,7 @@ GraphController::Margins GraphController::getMarginsForDummyNode(DummyNode& node { margins.minWidth = 82; - if (node.expanded) + if (node.isExpanded()) { margins.bottom = 15; } diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 4b0c3e0d..0bb05c73 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -57,6 +57,8 @@ private: void createDummyGraphForTokenIds(const std::vector& tokenIds); DummyNode createDummyNodeTopDown(Node* node); + void autoExpandActiveNode(const std::vector& activeTokenIds); + void setActiveAndVisibility(const std::vector& activeTokenIds); bool setNodeActiveAndVisibilityRecursiveBottomUp( DummyNode& node, const std::vector& activeTokenIds, bool aggregated) const; diff --git a/src/lib/component/view/graphElements/GraphNode.h b/src/lib/component/view/graphElements/GraphNode.h index 8e782f5d..7d11a250 100644 --- a/src/lib/component/view/graphElements/GraphNode.h +++ b/src/lib/component/view/graphElements/GraphNode.h @@ -54,6 +54,7 @@ struct DummyNode , connected(false) , aggregated(false) , expanded(false) + , autoExpanded(false) , invisibleSubNodeCount(0) , visible(false) { @@ -66,11 +67,17 @@ struct DummyNode , connected(false) , aggregated(false) , expanded(false) + , autoExpanded(false) , invisibleSubNodeCount(0) , visible(false) { } + bool isExpanded() const + { + return expanded || autoExpanded; + } + const Node* data; TokenComponentAccess::AccessType accessType; @@ -82,6 +89,7 @@ struct DummyNode bool aggregated; bool expanded; + bool autoExpanded; size_t invisibleSubNodeCount; bool visible; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 8e1c6d10..2c8e0fe7 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -474,11 +474,8 @@ std::vector Storage::getAutocompletionMatches( tokenResults = m_tokenIndex.runFuzzySearch(word); } - if (word.size()) - { - SearchResults filterResults = m_filterIndex.runFuzzySearch(word); - tokenResults.insert(filterResults.begin(), filterResults.end()); - } + SearchResults filterResults = m_filterIndex.runFuzzySearch(word); + tokenResults.insert(filterResults.begin(), filterResults.end()); std::vector matches = SearchIndex::getMatches(tokenResults, word); SearchMatch::log(matches, word); @@ -904,7 +901,6 @@ bool Storage::getSubQuerySearchResults( SearchResults* results ) const { std::string q = query; - bool returnChilds = false; if (QueryOperator::getOperatorType(q.back()) == QueryOperator::OPERATOR_SUB) { @@ -913,7 +909,6 @@ bool Storage::getSubQuerySearchResults( else if (QueryOperator::getOperatorType(q.back()) == QueryOperator::OPERATOR_HAS) { q.pop_back(); - returnChilds = true; } else if (QueryOperator::getOperatorType(q.back()) != QueryOperator::OPERATOR_NONE) { @@ -946,19 +941,19 @@ bool Storage::getSubQuerySearchResults( { if (word.size()) { - SearchResults res = node->runFuzzySearch(word, returnChilds); + SearchResults res = node->runFuzzySearch(word); results->insert(res.begin(), res.end()); } - else if (returnChilds) + else if (searchNodes.size() == 1) { for (const std::shared_ptr& child : node->getChildren()) { - results->insert(SearchResult(0, child.get(), child.get())); + child->addResultsRecursive(*results, 0, child.get()); } } - else if (searchNodes.size() > 1) + else { - results->insert(SearchResult(0, node, node)); + node->addResultsRecursive(*results, 0, node); } } diff --git a/src/lib/data/graph/filter/GraphFilterConductor.cpp b/src/lib/data/graph/filter/GraphFilterConductor.cpp index 1bfaa9b1..687be981 100644 --- a/src/lib/data/graph/filter/GraphFilterConductor.cpp +++ b/src/lib/data/graph/filter/GraphFilterConductor.cpp @@ -18,10 +18,11 @@ GraphFilterConductor::~GraphFilterConductor() { } -void GraphFilterConductor::filter(const QueryTree* tree, const FilterableGraph* in, FilterableGraph* out) const +void GraphFilterConductor::filter(const QueryTree* tree, const FilterableGraph* in, FilterableGraph* out) { if (tree->isValid()) { + m_inGraph = in; filterRecursively(tree->getRoot().get(), in, out); } } @@ -38,7 +39,7 @@ void GraphFilterConductor::filterRecursively(const QueryNode* node, const Filter } else if (node->isToken()) { - filterTokenNode(dynamic_cast(node), in, out); + filterTokenNode(dynamic_cast(node), out); } } @@ -172,7 +173,7 @@ void GraphFilterConductor::filterCommandNode(const QueryCommand* node, const Fil } } -void GraphFilterConductor::filterTokenNode(const QueryToken* node, const FilterableGraph* in, FilterableGraph* out) const +void GraphFilterConductor::filterTokenNode(const QueryToken* node, FilterableGraph* out) const { - GraphFilterToken(node->getTokenName(), node->getTokenIds()).apply(in, out); + GraphFilterToken(node->getTokenName(), node->getTokenIds()).apply(m_inGraph, out); } diff --git a/src/lib/data/graph/filter/GraphFilterConductor.h b/src/lib/data/graph/filter/GraphFilterConductor.h index ee84285e..a461c190 100644 --- a/src/lib/data/graph/filter/GraphFilterConductor.h +++ b/src/lib/data/graph/filter/GraphFilterConductor.h @@ -14,13 +14,15 @@ public: GraphFilterConductor(); ~GraphFilterConductor(); - void filter(const QueryTree* tree, const FilterableGraph* in, FilterableGraph* out) const; + void filter(const QueryTree* tree, const FilterableGraph* in, FilterableGraph* out); private: void filterRecursively(const QueryNode* node, const FilterableGraph* in, FilterableGraph* out) const; void filterOperatorNode(const QueryOperator* node, const FilterableGraph* in, FilterableGraph* out) const; void filterCommandNode(const QueryCommand* node, const FilterableGraph* in, FilterableGraph* out) const; - void filterTokenNode(const QueryToken* node, const FilterableGraph* in, FilterableGraph* out) const; + void filterTokenNode(const QueryToken* node, FilterableGraph* out) const; + + const FilterableGraph* m_inGraph; }; #endif // GRAPH_FILTER_CONDUCTOR_H diff --git a/src/lib/data/search/SearchIndex.cpp b/src/lib/data/search/SearchIndex.cpp index d5f74cfb..5fa7f4b4 100644 --- a/src/lib/data/search/SearchIndex.cpp +++ b/src/lib/data/search/SearchIndex.cpp @@ -73,7 +73,7 @@ SearchNode* SearchIndex::getNode(const std::string& fullName) const SearchResults SearchIndex::runFuzzySearch(const std::string& query) const { - return m_root.runFuzzySearch(query, true); + return m_root.runFuzzySearch(query); } std::vector SearchIndex::runFuzzySearchAndGetMatches(const std::string& query) const diff --git a/src/lib/data/search/SearchNode.cpp b/src/lib/data/search/SearchNode.cpp index 71b0c04d..d254cc46 100644 --- a/src/lib/data/search/SearchNode.cpp +++ b/src/lib/data/search/SearchNode.cpp @@ -89,30 +89,16 @@ const std::set>& SearchNode::getChildren() const return m_nodes; } -SearchResults SearchNode::runFuzzySearch(const std::string& query, bool recursive) const +SearchResults SearchNode::runFuzzySearch(const std::string& query) const { SearchResults result; - if (recursive) + for (std::shared_ptr n: m_nodes) { - for (std::shared_ptr n: m_nodes) + FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0); + for (const std::pair& p : m) { - FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0); - for (const std::pair& p : m) - { - result.insert(SearchResult(p.first, p.second, this)); - } - } - } - else - { - std::pair p = fuzzyMatch(query, 0, 0); - size_t pos = p.first; - size_t weight = p.second; - - if (pos == query.size()) - { - result.insert(SearchResult(weight, this, this)); + addResultsRecursive(result, p.first, p.second); } } @@ -121,6 +107,16 @@ SearchResults SearchNode::runFuzzySearch(const std::string& query, bool recursiv return result; } +void SearchNode::addResultsRecursive(SearchResults& result, size_t weight, const SearchNode* node) const +{ + result.insert(SearchResult(weight, node, this)); + + for (std::shared_ptr n: node->m_nodes) + { + addResultsRecursive(result, weight, n.get()); + } +} + std::shared_ptr SearchNode::addNodeRecursive( std::deque* nameIds, const Dictionary& dictionary ){ diff --git a/src/lib/data/search/SearchNode.h b/src/lib/data/search/SearchNode.h index 34837b53..d3c7ab9b 100644 --- a/src/lib/data/search/SearchNode.h +++ b/src/lib/data/search/SearchNode.h @@ -36,12 +36,14 @@ public: const std::set>& getChildren() const; - SearchResults runFuzzySearch(const std::string& query, bool recursive) const; + SearchResults runFuzzySearch(const std::string& query) const; + void addResultsRecursive(SearchResults& result, size_t weight, const SearchNode* node) const; private: typedef std::multimap FuzzyMap; typedef FuzzyMap::const_iterator FuzzyMapIterator; + // Accessed by SearchIndex std::shared_ptr addNodeRecursive(std::deque* nameIds, const Dictionary& dictionary); std::shared_ptr getNodeRecursive(std::deque* nameIds) const; diff --git a/src/test/SearchIndexTestSuite.h b/src/test/SearchIndexTestSuite.h index d1e7188b..d4582c50 100644 --- a/src/test/SearchIndexTestSuite.h +++ b/src/test/SearchIndexTestSuite.h @@ -189,8 +189,13 @@ public: std::vector matches = index.runFuzzySearchAndGetMatches("t"); - TS_ASSERT_EQUALS(1, matches.size()); + TS_ASSERT_EQUALS(6, matches.size()); TS_ASSERT_EQUALS("util", matches[0].fullName); + TS_ASSERT_EQUALS("util::math", matches[1].fullName); + TS_ASSERT_EQUALS("util::math::ceil", matches[2].fullName); + TS_ASSERT_EQUALS("util::math::floor", matches[3].fullName); + TS_ASSERT_EQUALS("util::string", matches[4].fullName); + TS_ASSERT_EQUALS("util::string::concat", matches[5].fullName); matches = index.runFuzzySearchAndGetMatches("uml"); @@ -208,9 +213,10 @@ public: std::vector matches = index.runFuzzySearchAndGetMatches("u:i"); - TS_ASSERT_EQUALS(2, matches.size()); + TS_ASSERT_EQUALS(3, matches.size()); TS_ASSERT_EQUALS("util::string", matches[0].fullName); - TS_ASSERT_EQUALS("util::math::ceil", matches[1].fullName); + TS_ASSERT_EQUALS("util::string::concat", matches[1].fullName); + TS_ASSERT_EQUALS("util::math::ceil", matches[2].fullName); matches = index.runFuzzySearchAndGetMatches("u:t:i");