* added buttons to enable grouping by file or namespace * last used group settings saved to ApplicationSettings * made groups hoverable/clickable on label only * improved node hatching and override edge colors * group overview lists fortune cookie message = Seen with the eyes of love, everything gets a new meaning.
This commit is contained in:
@@ -344,6 +344,9 @@
|
||||
<icon>
|
||||
<normal>#FFFFFF</normal>
|
||||
</icon>
|
||||
<hatching>
|
||||
<normal>#B05151</normal>
|
||||
</hatching>
|
||||
</namespace>
|
||||
<package>
|
||||
<like>namespace</like>
|
||||
@@ -352,7 +355,7 @@
|
||||
<file>
|
||||
<fill>
|
||||
<normal>#4E82F6</normal>
|
||||
<focus>#7FA9F4</focus>
|
||||
<focus>#6793F6</focus>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#20FFFFFF</normal>
|
||||
@@ -365,7 +368,7 @@
|
||||
<normal>#FFFFFF</normal>
|
||||
</icon>
|
||||
<hatching>
|
||||
<normal>#999999</normal>
|
||||
<normal>#416CCC</normal>
|
||||
</hatching>
|
||||
</file>
|
||||
<macro>
|
||||
@@ -423,6 +426,41 @@
|
||||
</text>
|
||||
</text>
|
||||
<group>
|
||||
<default>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#FFFFFF</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#807F80</normal>
|
||||
</border>
|
||||
</default>
|
||||
<file>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#D4D4D4</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#4E82F6</normal>
|
||||
<focus>#6793F6</focus>
|
||||
</border>
|
||||
</file>
|
||||
<namespace>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#D4D4D4</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#873E3E</normal>
|
||||
<focus>#944444</focus>
|
||||
</border>
|
||||
</namespace>
|
||||
<inheritance>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
|
||||
@@ -333,6 +333,9 @@
|
||||
<icon>
|
||||
<normal>#3D3D3D</normal>
|
||||
</icon>
|
||||
<hatching>
|
||||
<normal>#FFDEDE</normal>
|
||||
</hatching>
|
||||
</namespace>
|
||||
<package>
|
||||
<like>namespace</like>
|
||||
@@ -347,6 +350,9 @@
|
||||
<normal>#203C3C3C</normal>
|
||||
<focus>#3C3C3C</focus>
|
||||
</border>
|
||||
<hatching>
|
||||
<normal>#D7F7C8</normal>
|
||||
</hatching>
|
||||
</file>
|
||||
<macro>
|
||||
<like>file</like>
|
||||
@@ -397,6 +403,38 @@
|
||||
</text>
|
||||
</text>
|
||||
<group>
|
||||
<default>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#D0D0D0</normal>
|
||||
</border>
|
||||
</default>
|
||||
<file>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#5C5C5C</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#BEE0AF</normal>
|
||||
<focus>#A6D492</focus>
|
||||
</border>
|
||||
</file>
|
||||
<namespace>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#5C5C5C</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#EFC5C5</normal>
|
||||
<focus>#EFB3B3</focus>
|
||||
</border>
|
||||
</namespace>
|
||||
<inheritance>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
@@ -413,7 +451,7 @@
|
||||
</default>
|
||||
|
||||
<override>
|
||||
<normal>#955ECC</normal>
|
||||
<normal>#A37ACC</normal>
|
||||
</override>
|
||||
|
||||
<call>
|
||||
|
||||
@@ -336,6 +336,9 @@
|
||||
<icon>
|
||||
<normal>#C3C3C3</normal>
|
||||
</icon>
|
||||
<hatching>
|
||||
<normal>#521B1F</normal>
|
||||
</hatching>
|
||||
</namespace>
|
||||
<package>
|
||||
<like>namespace</like>
|
||||
@@ -344,12 +347,15 @@
|
||||
<file>
|
||||
<fill>
|
||||
<normal>#1B564E</normal>
|
||||
<focus>#247368</focus>
|
||||
<focus>#21695F</focus>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#20C3C3C3</normal>
|
||||
<focus>#C3C3C3</focus>
|
||||
</border>
|
||||
<hatching>
|
||||
<normal>#123B35</normal>
|
||||
</hatching>
|
||||
</file>
|
||||
<macro>
|
||||
<like>file</like>
|
||||
@@ -400,6 +406,38 @@
|
||||
</text>
|
||||
</text>
|
||||
<group>
|
||||
<default>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#5A5A5A</normal>
|
||||
</border>
|
||||
</default>
|
||||
<file>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#C3C3C3</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#1B564E</normal>
|
||||
<focus>#1E6158</focus>
|
||||
</border>
|
||||
</file>
|
||||
<namespace>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<text>
|
||||
<normal>#C3C3C3</normal>
|
||||
</text>
|
||||
<border>
|
||||
<normal>#78282D</normal>
|
||||
<focus>#872D33</focus>
|
||||
</border>
|
||||
</namespace>
|
||||
<inheritance>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
@@ -416,7 +454,7 @@
|
||||
</default>
|
||||
|
||||
<override>
|
||||
<normal>#B059C2</normal>
|
||||
<normal>#8A5A94</normal>
|
||||
</override>
|
||||
|
||||
<call>
|
||||
|
||||
@@ -14,7 +14,7 @@ QPushButton:disabled {
|
||||
background: <color:search/button/disabled>;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
QPushButton:hover, QPushButton:checked {
|
||||
background: <color:search/button/hover>;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ QPushButton:pressed {
|
||||
#expand_button {
|
||||
max-width: 26px;
|
||||
max-height: 26px;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
#collapse_button {
|
||||
@@ -82,3 +83,21 @@ QPushButton:pressed {
|
||||
#depth_slider::groove:disabled, #depth_slider::handle:disabled {
|
||||
background: <color:search/button/icon_disabled>;
|
||||
}
|
||||
|
||||
#group_left_button {
|
||||
border-radius: 0;
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
max-width: 26px;
|
||||
max-height: 26px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
#group_right_button {
|
||||
border-radius: 0;
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
max-width: 26px;
|
||||
max-height: 26px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -32,6 +32,7 @@
|
||||
<verbose_indexer_logging_enabled><!-- BOOL: define if verbose indexer logging is enabled --></verbose_indexer_logging_enabled>
|
||||
|
||||
<graph_controls_visible><!-- BOOL: define if the graph controls are visible or collapsed --></graph_controls_visible>
|
||||
<graph_grouping><!-- STRING: group type name --></graph_grouping>
|
||||
</application>
|
||||
|
||||
<screen>
|
||||
|
||||
@@ -265,6 +265,8 @@ add_files(
|
||||
data/ErrorCountInfo.h
|
||||
data/ErrorFilter.h
|
||||
data/ErrorInfo.h
|
||||
data/GroupType.cpp
|
||||
data/GroupType.h
|
||||
data/HierarchyCache.cpp
|
||||
data/HierarchyCache.h
|
||||
data/NodeType.cpp
|
||||
|
||||
@@ -79,12 +79,22 @@ void ActivationController::handleMessage(MessageActivateNodes* message)
|
||||
MessageActivateTokens m(message);
|
||||
for (const MessageActivateNodes::ActiveNode& node : message->nodes)
|
||||
{
|
||||
Id nodeId = node.nodeId ? node.nodeId : m_storageAccess->getNodeIdForNameHierarchy(node.nameHierarchy);
|
||||
Id nodeId = node.nodeId;
|
||||
NameHierarchy name = node.nameHierarchy;
|
||||
if (!nodeId)
|
||||
{
|
||||
nodeId = m_storageAccess->getNodeIdForNameHierarchy(name);
|
||||
}
|
||||
else if (!name.size())
|
||||
{
|
||||
name = m_storageAccess->getNameHierarchyForNodeId(nodeId);
|
||||
}
|
||||
|
||||
if (nodeId > 0)
|
||||
{
|
||||
m.tokenIds.push_back(nodeId);
|
||||
}
|
||||
m.tokenNames.push_back(node.nameHierarchy);
|
||||
m.tokenNames.push_back(name);
|
||||
}
|
||||
m.searchMatches = m_storageAccess->getSearchMatchesForTokenIds(m.tokenIds);
|
||||
m.dispatchImmediately();
|
||||
@@ -104,7 +114,7 @@ void ActivationController::handleMessage(MessageActivateSourceLocations* message
|
||||
MessageActivateNodes m;
|
||||
for (Id nodeId : m_storageAccess->getNodeIdsForLocationIds(message->locationIds))
|
||||
{
|
||||
m.addNode(nodeId, m_storageAccess->getNameHierarchyForNodeId(nodeId));
|
||||
m.addNode(nodeId);
|
||||
}
|
||||
m.dispatchImmediately();
|
||||
}
|
||||
|
||||
@@ -188,9 +188,7 @@ void BookmarkController::activateBookmark(const std::shared_ptr<Bookmark> bookma
|
||||
Id activeNodeId = edgeBookmark->getActiveNodeId();
|
||||
if (activeNodeId)
|
||||
{
|
||||
MessageActivateNodes activateNodes;
|
||||
activateNodes.addNode(activeNodeId, m_storageAccess->getNameHierarchyForNodeId(activeNodeId));
|
||||
activateNodes.dispatch();
|
||||
MessageActivateNodes(activeNodeId).dispatch();
|
||||
}
|
||||
|
||||
MessageActivateEdge(firstEdgeId, Edge::intToType(storageEdge.type), sourceName, targetName).dispatch();
|
||||
@@ -216,7 +214,7 @@ void BookmarkController::activateBookmark(const std::shared_ptr<Bookmark> bookma
|
||||
|
||||
for (Id nodeId: nodeBookmark->getNodeIds())
|
||||
{
|
||||
activateNodes.addNode(nodeId, m_storageAccess->getNameHierarchyForNodeId(nodeId));
|
||||
activateNodes.addNode(nodeId);
|
||||
}
|
||||
|
||||
activateNodes.dispatch();
|
||||
|
||||
@@ -109,6 +109,16 @@ void GraphController::handleMessage(MessageActivateTokens* message)
|
||||
if (isNamespace)
|
||||
{
|
||||
addCharacterIndex();
|
||||
|
||||
DummyNode* group = groupAllNodes(GroupType::NAMESPACE, tokenIds[0]);
|
||||
group->groupLayout = GroupLayout::LIST;
|
||||
|
||||
if (!group->name.size())
|
||||
{
|
||||
group->name = m_storageAccess->getNameHierarchyForNodeId(tokenIds[0]).getQualifiedName();
|
||||
group->tokenId = tokenIds[0];
|
||||
}
|
||||
|
||||
layoutNesting();
|
||||
layoutList();
|
||||
}
|
||||
@@ -141,6 +151,8 @@ void GraphController::handleMessage(MessageActivateTokens* message)
|
||||
m_useBezierEdges = !isInheritanceChain;
|
||||
}
|
||||
|
||||
groupNodesByParents(getView()->getGrouping());
|
||||
|
||||
layoutNesting();
|
||||
layoutGraph(true);
|
||||
assignBundleIds();
|
||||
@@ -187,7 +199,7 @@ void GraphController::handleMessage(MessageActivateTrail* message)
|
||||
|
||||
if (message->trailType & Edge::EDGE_INHERITANCE)
|
||||
{
|
||||
groupTrailNodes(NodeType::GROUP_INHERITANCE);
|
||||
groupTrailNodes(GroupType::INHERITANCE);
|
||||
}
|
||||
|
||||
layoutNesting();
|
||||
@@ -241,11 +253,14 @@ void GraphController::handleMessage(MessageFocusOut *message)
|
||||
|
||||
void GraphController::handleMessage(MessageGraphNodeBundleSplit* message)
|
||||
{
|
||||
std::wstring name;
|
||||
for (size_t i = 0; i < m_dummyNodes.size(); i++)
|
||||
{
|
||||
DummyNode* node = m_dummyNodes[i].get();
|
||||
if ((node->isBundleNode() || node->isGroupNode()) && node->tokenId == message->bundleId)
|
||||
{
|
||||
name = node->name;
|
||||
|
||||
std::vector<std::shared_ptr<DummyNode>> nodes;
|
||||
if (node->isBundleNode())
|
||||
{
|
||||
@@ -296,7 +311,7 @@ void GraphController::handleMessage(MessageGraphNodeBundleSplit* message)
|
||||
}
|
||||
}
|
||||
|
||||
relayoutGraph(message, false, true, message->layoutToList, message->layoutToList);
|
||||
relayoutGraph(message, false, true, message->layoutToList, message->layoutToList, name);
|
||||
}
|
||||
|
||||
void GraphController::handleMessage(MessageGraphNodeExpand* message)
|
||||
@@ -310,9 +325,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message)
|
||||
{
|
||||
if (!message->isReplayed())
|
||||
{
|
||||
MessageActivateNodes msg;
|
||||
msg.addNode(message->tokenId, m_storageAccess->getNameHierarchyForNodeId(message->tokenId));
|
||||
msg.dispatch();
|
||||
MessageActivateNodes(message->tokenId).dispatch();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -433,7 +446,7 @@ void GraphController::handleMessage(MessageGraphNodeHide* message)
|
||||
|
||||
if (node || edge)
|
||||
{
|
||||
relayoutGraph(message, false, true, false, false);
|
||||
relayoutGraph(message, false, true, false, false, L"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,8 +555,8 @@ void GraphController::createDummyGraph(const std::shared_ptr<Graph> graph)
|
||||
updateDummyNodeNamesAndAddQualifiers(dummyNodes);
|
||||
|
||||
m_dummyNodes = dummyNodes;
|
||||
|
||||
m_graph = graph;
|
||||
|
||||
m_useBezierEdges = false;
|
||||
}
|
||||
|
||||
@@ -662,7 +675,7 @@ void GraphController::updateDummyNodeNamesAndAddQualifiers(
|
||||
qualifierNode->visible = true;
|
||||
|
||||
node->subNodes.push_back(qualifierNode);
|
||||
node->hasQualifier = true;
|
||||
node->qualifierName = qualifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -986,7 +999,7 @@ void GraphController::bundleNodes()
|
||||
// std::cout << node->bundleInfo.layoutVertical << " ";
|
||||
// std::cout << node->bundleInfo.isReferenced << " ";
|
||||
// std::cout << node->bundleInfo.isReferencing << " ";
|
||||
// std::cout << node->name << std::endl;
|
||||
// std::wcout << node->name << std::endl;
|
||||
// }
|
||||
|
||||
// bundle
|
||||
@@ -1380,7 +1393,174 @@ bool GraphController::hasCharacterIndex() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void GraphController::groupTrailNodes(NodeType::GroupType groupType)
|
||||
void GraphController::groupNodesByParents(GroupType groupType)
|
||||
{
|
||||
TRACE();
|
||||
|
||||
if (groupType != GroupType::FILE && groupType != GroupType::NAMESPACE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<std::wstring, std::shared_ptr<DummyNode>> groupNodes;
|
||||
std::map<std::wstring, std::vector<std::shared_ptr<DummyNode>>> nodesToGroup;
|
||||
|
||||
std::map<Id, std::pair<Id, NameHierarchy>> nodeIdtoParentMap;
|
||||
if (groupType == GroupType::FILE)
|
||||
{
|
||||
std::vector<Id> nodeIds;
|
||||
for (const std::shared_ptr<DummyNode>& dummyNode : m_dummyNodes)
|
||||
{
|
||||
if (dummyNode->isGraphNode())
|
||||
{
|
||||
nodeIds.push_back(dummyNode->tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
nodeIdtoParentMap = m_storageAccess->getNodeIdToParentFileMap(nodeIds);
|
||||
}
|
||||
|
||||
std::map<std::wstring, Id> qualifierNameToIdMap;
|
||||
for (const std::shared_ptr<DummyNode>& dummyNode : m_dummyNodes)
|
||||
{
|
||||
if (dummyNode->isGroupNode())
|
||||
{
|
||||
groupNodes.emplace(dummyNode->name, dummyNode);
|
||||
}
|
||||
else if (dummyNode->visible)
|
||||
{
|
||||
if (groupType == GroupType::FILE)
|
||||
{
|
||||
if (dummyNode->isGraphNode())
|
||||
{
|
||||
auto it = nodeIdtoParentMap.find(dummyNode->tokenId);
|
||||
if (it != nodeIdtoParentMap.end())
|
||||
{
|
||||
nodesToGroup[it->second.second.getQualifiedName()].push_back(dummyNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (groupType == GroupType::NAMESPACE)
|
||||
{
|
||||
const DummyNode* qualifierNode = dummyNode->getQualifierNode();
|
||||
if (qualifierNode)
|
||||
{
|
||||
Id qualifierId = 0;
|
||||
std::wstring qualifierName = qualifierNode->qualifierName.getQualifiedName();
|
||||
auto it = qualifierNameToIdMap.find(qualifierName);
|
||||
if (it != qualifierNameToIdMap.end())
|
||||
{
|
||||
qualifierId = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
qualifierId = m_storageAccess->getNodeIdForNameHierarchy(qualifierNode->qualifierName);
|
||||
qualifierNameToIdMap.emplace(qualifierName, qualifierId);
|
||||
}
|
||||
|
||||
nodesToGroup[qualifierName].push_back(dummyNode);
|
||||
nodeIdtoParentMap.emplace(
|
||||
dummyNode->tokenId, std::make_pair(qualifierId, qualifierNode->qualifierName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<Id> groupedNodeIds;
|
||||
for (const std::pair<std::wstring, std::vector<std::shared_ptr<DummyNode>>>& p : nodesToGroup)
|
||||
{
|
||||
std::shared_ptr<DummyNode> groupNode;
|
||||
|
||||
std::wstring name = p.first;
|
||||
if (groupType == GroupType::FILE)
|
||||
{
|
||||
name = FilePath(p.first).fileName();
|
||||
}
|
||||
|
||||
auto it = groupNodes.find(name);
|
||||
if (it != groupNodes.end())
|
||||
{
|
||||
groupNode = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
groupNode = std::make_shared<DummyNode>(DummyNode::DUMMY_GROUP);
|
||||
groupNode->visible = true;
|
||||
groupNode->groupType = groupType;
|
||||
groupNode->groupLayout = GroupLayout::BUCKET;
|
||||
groupNode->name = name;
|
||||
|
||||
auto it = nodeIdtoParentMap.find(p.second[0]->tokenId);
|
||||
if (it != nodeIdtoParentMap.end())
|
||||
{
|
||||
groupNode->tokenId = it->second.first;
|
||||
}
|
||||
m_topLevelAncestorIds[groupNode->tokenId] = groupNode->tokenId;
|
||||
m_dummyNodes.push_back(groupNode);
|
||||
}
|
||||
|
||||
std::vector<DummyNode::BundleInfo> bundleInfos;
|
||||
for (std::shared_ptr<DummyNode> dummyNode : p.second)
|
||||
{
|
||||
if (dummyNode->hasActiveSubNode())
|
||||
{
|
||||
groupNode->bundleInfo = dummyNode->bundleInfo;
|
||||
groupNode->bundleId = dummyNode->bundleId;
|
||||
}
|
||||
else
|
||||
{
|
||||
bundleInfos.push_back(dummyNode->bundleInfo);
|
||||
}
|
||||
|
||||
groupNode->subNodes.push_back(dummyNode);
|
||||
m_topLevelAncestorIds[dummyNode->tokenId] = groupNode->tokenId;
|
||||
groupedNodeIds.insert(dummyNode->tokenId);
|
||||
}
|
||||
|
||||
if (!groupNode->bundleId)
|
||||
{
|
||||
groupNode->bundleId = groupNode->subNodes[0]->bundleId;
|
||||
groupNode->bundleInfo = DummyNode::BundleInfo::averageBundleInfo(bundleInfos);
|
||||
}
|
||||
|
||||
groupNode->sortSubNodesByName();
|
||||
}
|
||||
|
||||
for (int i = 0; i < int(m_dummyNodes.size()); i++)
|
||||
{
|
||||
if (groupedNodeIds.find(m_dummyNodes[i]->tokenId) != groupedNodeIds.end())
|
||||
{
|
||||
m_dummyNodes.erase(m_dummyNodes.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DummyNode* GraphController::groupAllNodes(GroupType groupType, Id groupNodeId)
|
||||
{
|
||||
TRACE();
|
||||
|
||||
std::shared_ptr<DummyNode> groupNode = std::make_shared<DummyNode>(DummyNode::DUMMY_GROUP);
|
||||
groupNode->visible = true;
|
||||
groupNode->groupType = groupType;
|
||||
groupNode->tokenId = groupNodeId;
|
||||
m_topLevelAncestorIds[groupNode->tokenId] = groupNode->tokenId;
|
||||
|
||||
for (std::shared_ptr<DummyNode> dummyNode : m_dummyNodes)
|
||||
{
|
||||
groupNode->subNodes.push_back(dummyNode);
|
||||
m_topLevelAncestorIds[dummyNode->tokenId] = groupNode->tokenId;
|
||||
}
|
||||
|
||||
if (groupNode->subNodes.size())
|
||||
{
|
||||
m_dummyNodes = { groupNode };
|
||||
}
|
||||
|
||||
return groupNode.get();
|
||||
}
|
||||
|
||||
void GraphController::groupTrailNodes(GroupType groupType)
|
||||
{
|
||||
TRACE();
|
||||
|
||||
@@ -1455,6 +1635,7 @@ void GraphController::groupTrailNodes(NodeType::GroupType groupType)
|
||||
std::shared_ptr<DummyNode> groupNode = std::make_shared<DummyNode>(DummyNode::DUMMY_GROUP);
|
||||
groupNode->visible = true;
|
||||
groupNode->groupType = groupType;
|
||||
groupNode->groupLayout = GroupLayout::SKEWED;
|
||||
|
||||
// Use token Id of first node and make first 2 bits 1
|
||||
groupNode->tokenId = ~(~size_t(0) >> 2) + node.nodeId;
|
||||
@@ -1626,6 +1807,10 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
{
|
||||
width = margins.charWidth * node->name.size();
|
||||
}
|
||||
else if (node->isGroupNode())
|
||||
{
|
||||
width = margins.charWidth * node->name.size() + 5;
|
||||
}
|
||||
|
||||
width += margins.iconWidth;
|
||||
width = std::max(width, margins.minWidth);
|
||||
@@ -1651,19 +1836,44 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
}
|
||||
}
|
||||
|
||||
int top = margins.top + margins.charHeight + margins.spacingA;
|
||||
int left = margins.left;
|
||||
Vec2i size;
|
||||
if (node->isGroupNode())
|
||||
{
|
||||
size = ListLayouter::layoutSkewed(
|
||||
&node->subNodes, top, left, margins.spacingX, margins.spacingY, getView()->getViewSize().x() * 1.5);
|
||||
Vec2i viewSize = getView()->getViewSize();
|
||||
|
||||
switch (node->groupLayout)
|
||||
{
|
||||
case GroupLayout::LIST:
|
||||
viewSize.x = viewSize.x - 150; // prevent horizontal scroll
|
||||
ListLayouter::layoutMultiColumn(viewSize, &node->subNodes);
|
||||
break;
|
||||
|
||||
case GroupLayout::SKEWED:
|
||||
ListLayouter::layoutSkewed(&node->subNodes, margins.spacingX, margins.spacingY, viewSize.x() * 1.5);
|
||||
break;
|
||||
|
||||
case GroupLayout::BUCKET:
|
||||
if (node->hasActiveSubNode())
|
||||
{
|
||||
BucketLayouter grid(viewSize);
|
||||
grid.createBuckets(node->subNodes, m_dummyEdges);
|
||||
grid.layoutBuckets(true);
|
||||
node->subNodes = grid.getSortedNodes();
|
||||
}
|
||||
else
|
||||
{
|
||||
ListLayouter::layoutColumn(&node->subNodes, margins.spacingY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = ListLayouter::layoutColumn(&node->subNodes, top, left, margins.spacingY);
|
||||
ListLayouter::layoutColumn(&node->subNodes, margins.spacingY);
|
||||
}
|
||||
|
||||
Vec2i size = ListLayouter::offsetNodes(
|
||||
node->subNodes, margins.top + margins.charHeight + margins.spacingA, margins.left);
|
||||
|
||||
width = std::max(size.x(), width);
|
||||
height = size.y();
|
||||
|
||||
@@ -1795,7 +2005,7 @@ void GraphController::layoutGraph(bool getSortedNodes)
|
||||
|
||||
BucketLayouter grid(getView()->getViewSize());
|
||||
grid.createBuckets(visibleNodes, m_dummyEdges);
|
||||
grid.layoutBuckets();
|
||||
grid.layoutBuckets(false);
|
||||
|
||||
if (getSortedNodes)
|
||||
{
|
||||
@@ -1891,7 +2101,8 @@ DummyEdge* GraphController::getDummyGraphEdgeById(Id tokenId) const
|
||||
}
|
||||
|
||||
void GraphController::relayoutGraph(
|
||||
MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop, bool withCharacterIndex)
|
||||
MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop, bool withCharacterIndex,
|
||||
const std::wstring& groupName)
|
||||
{
|
||||
bool showsTrail = m_graph->getTrailMode() != Graph::TRAIL_NONE;
|
||||
|
||||
@@ -1900,11 +2111,28 @@ void GraphController::relayoutGraph(
|
||||
if (hasCharacterIndex() || withCharacterIndex)
|
||||
{
|
||||
addCharacterIndex();
|
||||
|
||||
if (withCharacterIndex && m_dummyNodes.size())
|
||||
{
|
||||
// Use token Id of first node and make first 2 bits 1
|
||||
Id groupId = ~(~size_t(0) >> 2) + m_dummyNodes[0]->tokenId;
|
||||
|
||||
DummyNode* group = groupAllNodes(GroupType::DEFAULT, groupId);
|
||||
group->groupLayout = GroupLayout::LIST;
|
||||
group->interactive = false;
|
||||
group->name = groupName;
|
||||
}
|
||||
|
||||
layoutNesting();
|
||||
layoutList();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!showsTrail)
|
||||
{
|
||||
groupNodesByParents(getView()->getGrouping());
|
||||
}
|
||||
|
||||
layoutNesting();
|
||||
|
||||
if (showsTrail)
|
||||
|
||||
@@ -109,7 +109,9 @@ private:
|
||||
void addCharacterIndex();
|
||||
bool hasCharacterIndex() const;
|
||||
|
||||
void groupTrailNodes(NodeType::GroupType groupType);
|
||||
void groupNodesByParents(GroupType groupType);
|
||||
DummyNode* groupAllNodes(GroupType groupType, Id groupNodeId);
|
||||
void groupTrailNodes(GroupType groupType);
|
||||
|
||||
void layoutNesting();
|
||||
void layoutNestingRecursive(DummyNode* node) const;
|
||||
@@ -126,7 +128,8 @@ private:
|
||||
DummyEdge* getDummyGraphEdgeById(Id tokenId) const;
|
||||
|
||||
void relayoutGraph(
|
||||
MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop, bool withCharacterIndex);
|
||||
MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop, bool withCharacterIndex,
|
||||
const std::wstring& groupName);
|
||||
void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop);
|
||||
|
||||
void forEachDummyNodeRecursive(std::function<void(DummyNode*)> func);
|
||||
|
||||
@@ -194,7 +194,7 @@ void BucketLayouter::createBuckets(
|
||||
}
|
||||
}
|
||||
|
||||
void BucketLayouter::layoutBuckets()
|
||||
void BucketLayouter::layoutBuckets(bool addVerticalOffset)
|
||||
{
|
||||
std::map<int, int> widths;
|
||||
std::map<int, int> heights;
|
||||
@@ -236,6 +236,11 @@ void BucketLayouter::layoutBuckets()
|
||||
Bucket* midBucket = &m_buckets[0][0];
|
||||
yOff = (heights[0] - midBucket->getHeight()) / 2 * -j;
|
||||
}
|
||||
// move every second bucket in a row slighly lower to avoid edges over nodes
|
||||
else if (addVerticalOffset && std::abs(i) % 2 == 1)
|
||||
{
|
||||
yOff += GraphViewStyle::toGridGap(10);
|
||||
}
|
||||
|
||||
bucket->layout(x, y + yOff, widths[i], heights[j]);
|
||||
x += widths[i] + GraphViewStyle::toGridGap(85);
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
void createBuckets(
|
||||
std::vector<std::shared_ptr<DummyNode>>& nodes,
|
||||
const std::vector<std::shared_ptr<DummyEdge>>& edges);
|
||||
void layoutBuckets();
|
||||
void layoutBuckets(bool addVerticalOffset);
|
||||
|
||||
std::vector<std::shared_ptr<DummyNode>> getSortedNodes();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/GroupType.h"
|
||||
#include "data/name/NameHierarchy.h"
|
||||
#include "data/parser/AccessKind.h"
|
||||
|
||||
@@ -54,6 +55,32 @@ public:
|
||||
, isReferencing(false)
|
||||
{}
|
||||
|
||||
static BundleInfo averageBundleInfo(const std::vector<DummyNode::BundleInfo>& bundleInfos)
|
||||
{
|
||||
size_t activeCount = 0;
|
||||
size_t definedCount = 0;
|
||||
size_t verticalLayoutCount = 0;
|
||||
size_t referencedCount = 0;
|
||||
size_t referencingCount = 0;
|
||||
|
||||
for (const BundleInfo& info : bundleInfos)
|
||||
{
|
||||
if (info.isActive) activeCount++;
|
||||
if (info.isDefined) definedCount++;
|
||||
if (info.layoutVertical) verticalLayoutCount++;
|
||||
if (info.isReferenced) referencedCount++;
|
||||
if (info.isReferencing) referencingCount++;
|
||||
}
|
||||
|
||||
BundleInfo info;
|
||||
if (activeCount > bundleInfos.size() / 2) info.isActive = true;
|
||||
if (definedCount > bundleInfos.size() / 2) info.isDefined = true;
|
||||
if (verticalLayoutCount > bundleInfos.size() / 2) info.layoutVertical = true;
|
||||
if (referencedCount > bundleInfos.size() / 2) info.isReferenced = true;
|
||||
if (referencingCount > bundleInfos.size() / 2) info.isReferencing = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
bool isActive;
|
||||
bool isDefined;
|
||||
bool layoutVertical;
|
||||
@@ -73,7 +100,6 @@ public:
|
||||
, expanded(false)
|
||||
, autoExpanded(false)
|
||||
, hasParent(true)
|
||||
, hasQualifier(false)
|
||||
, accessKind(ACCESS_NONE)
|
||||
, invisibleSubNodeCount(0)
|
||||
, bundleId(0)
|
||||
@@ -81,7 +107,9 @@ public:
|
||||
, bundledNodeCount(0)
|
||||
, bundledNodeType(NodeType::NODE_SYMBOL)
|
||||
, qualifierName(NAME_DELIMITER_UNKNOWN)
|
||||
, groupType(NodeType::GROUP_FRAMELESS)
|
||||
, groupType(GroupType::DEFAULT)
|
||||
, groupLayout(GroupLayout::LIST)
|
||||
, interactive(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -365,6 +393,23 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
bool getsLayouted() const
|
||||
{
|
||||
return visible && !isExpandToggleNode() && !isQualifierNode();
|
||||
}
|
||||
|
||||
const DummyNode* getQualifierNode() const
|
||||
{
|
||||
for (const std::shared_ptr<DummyNode>& subNode : subNodes)
|
||||
{
|
||||
if (subNode->isQualifierNode())
|
||||
{
|
||||
return subNode.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type type;
|
||||
|
||||
Vec2i position;
|
||||
@@ -387,7 +432,6 @@ public:
|
||||
bool expanded;
|
||||
bool autoExpanded;
|
||||
bool hasParent;
|
||||
bool hasQualifier;
|
||||
|
||||
// AccessNode
|
||||
AccessKind accessKind;
|
||||
@@ -411,8 +455,10 @@ public:
|
||||
NameHierarchy qualifierName;
|
||||
|
||||
// GroupNode
|
||||
NodeType::GroupType groupType;
|
||||
GroupType groupType;
|
||||
GroupLayout groupLayout;
|
||||
std::vector<Id> hiddenEdgeIds;
|
||||
bool interactive;
|
||||
};
|
||||
|
||||
#endif // DUMMY_NODE_H
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
#include "component/controller/helper/DummyNode.h"
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
|
||||
Vec2i ListLayouter::layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap)
|
||||
void ListLayouter::layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int gap)
|
||||
{
|
||||
return layoutSimple(nodes, top, left, gap, 0, true);
|
||||
layoutSimple(nodes, gap, 0, true);
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap)
|
||||
void ListLayouter::layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int gap)
|
||||
{
|
||||
return layoutSimple(nodes, top, left, 0, gap, false);
|
||||
layoutSimple(nodes, 0, gap, false);
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes)
|
||||
void ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes)
|
||||
{
|
||||
size_t colsFinal;
|
||||
std::vector<int> maxWidthsFinal;
|
||||
@@ -26,7 +26,7 @@ Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_pt
|
||||
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
|
||||
for (auto node : *nodes)
|
||||
{
|
||||
if (node->visible)
|
||||
if (node->getsLayouted())
|
||||
{
|
||||
visibleNodes.push_back(node);
|
||||
}
|
||||
@@ -82,8 +82,6 @@ Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_pt
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
size_t nodesPerCol =
|
||||
(colsFinal == 1 ? visibleNodes.size() : std::ceil((visibleNodes.size() + colsFinal - 1) / double(colsFinal)));
|
||||
@@ -122,30 +120,21 @@ Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_pt
|
||||
visibleNodes[i]->position.y = y;
|
||||
|
||||
y += visibleNodes[i]->size.y + gapY;
|
||||
height = std::max(height, y);
|
||||
|
||||
if (visibleNodes[i]->isTextNode())
|
||||
{
|
||||
lastTextNode = visibleNodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int w : maxWidthsFinal)
|
||||
{
|
||||
width += w + gapX;
|
||||
}
|
||||
|
||||
return Vec2i(width - gapX, height - gapY);
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutSkewed(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, int maxWidth)
|
||||
void ListLayouter::layoutSkewed(std::vector<std::shared_ptr<DummyNode>>* nodes, int gapX, int gapY, int maxWidth)
|
||||
{
|
||||
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
|
||||
std::multiset<int> nodeWidths;
|
||||
for (auto node : *nodes)
|
||||
{
|
||||
if (node->visible)
|
||||
if (node->getsLayouted())
|
||||
{
|
||||
visibleNodes.push_back(node);
|
||||
nodeWidths.insert(node->size.x());
|
||||
@@ -185,8 +174,8 @@ Vec2i ListLayouter::layoutSkewed(
|
||||
}
|
||||
|
||||
DummyNode* node = visibleNodes[i].get();
|
||||
node->position.x = left + x + (nodeWidth - node->size.x()) / 2;
|
||||
node->position.y = top + height;
|
||||
node->position.x = x + (nodeWidth - node->size.x()) / 2;
|
||||
node->position.y = height;
|
||||
|
||||
rowHeight = std::max(rowHeight, node->size.y());
|
||||
x += nodeWidth + gapX;
|
||||
@@ -201,16 +190,6 @@ Vec2i ListLayouter::layoutSkewed(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Vec4i rect = boundingRect(visibleNodes);
|
||||
Vec2i offset(left - rect.x(), top - rect.y());
|
||||
|
||||
for (auto node : visibleNodes)
|
||||
{
|
||||
node->position += offset;
|
||||
}
|
||||
|
||||
return Vec2i(rect.z() - rect.x(), rect.w() - rect.y());
|
||||
}
|
||||
|
||||
Vec4i ListLayouter::boundingRect(const std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
@@ -219,7 +198,7 @@ Vec4i ListLayouter::boundingRect(const std::vector<std::shared_ptr<DummyNode>>&
|
||||
|
||||
for (auto node : nodes)
|
||||
{
|
||||
if (!node->visible)
|
||||
if (!node->getsLayouted())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -243,46 +222,44 @@ Vec4i ListLayouter::boundingRect(const std::vector<std::shared_ptr<DummyNode>>&
|
||||
return rect;
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutSimple(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, bool horizontal)
|
||||
Vec2i ListLayouter::offsetNodes(std::vector<std::shared_ptr<DummyNode>> nodes, int top, int left)
|
||||
{
|
||||
Vec4i rect = boundingRect(nodes);
|
||||
Vec2i offset(left - rect.x(), top - rect.y());
|
||||
|
||||
for (auto node : nodes)
|
||||
{
|
||||
if (node->getsLayouted())
|
||||
{
|
||||
node->position += offset;
|
||||
}
|
||||
}
|
||||
|
||||
return Vec2i(rect.z() - rect.x(), rect.w() - rect.y());
|
||||
}
|
||||
|
||||
void ListLayouter::layoutSimple(std::vector<std::shared_ptr<DummyNode>>* nodes, int gapX, int gapY, bool horizontal)
|
||||
{
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
for (const std::shared_ptr<DummyNode>& node : *nodes)
|
||||
{
|
||||
if (!node->visible || node->isExpandToggleNode() || node->isQualifierNode())
|
||||
if (!node->getsLayouted())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node->position.x = left + x;
|
||||
node->position.y = top + y;
|
||||
node->position.x = x;
|
||||
node->position.y = y;
|
||||
|
||||
if (horizontal)
|
||||
{
|
||||
x += node->size.x + gapX;
|
||||
height = std::max(height, node->size.y());
|
||||
}
|
||||
else
|
||||
{
|
||||
y += node->size.y + gapY;
|
||||
width = std::max(width, node->size.x());
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
width = x - gapX;
|
||||
}
|
||||
|
||||
if (y > 0)
|
||||
{
|
||||
height = y - gapY;
|
||||
}
|
||||
|
||||
return Vec2i(width, height);
|
||||
}
|
||||
|
||||
@@ -12,17 +12,17 @@ struct DummyNode;
|
||||
class ListLayouter
|
||||
{
|
||||
public:
|
||||
static Vec2i layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap);
|
||||
static Vec2i layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap);
|
||||
static void layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int gap);
|
||||
static void layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int gap);
|
||||
|
||||
static Vec2i layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes);
|
||||
static Vec2i layoutSkewed(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, int maxWidth);
|
||||
static void layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes);
|
||||
static void layoutSkewed(std::vector<std::shared_ptr<DummyNode>>* nodes, int gapX, int gapY, int maxWidth);
|
||||
|
||||
static Vec4i boundingRect(const std::vector<std::shared_ptr<DummyNode>>& nodes);
|
||||
static Vec2i offsetNodes(std::vector<std::shared_ptr<DummyNode>> nodes, int top, int left);
|
||||
|
||||
private:
|
||||
static Vec2i layoutSimple(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, bool horizontal);
|
||||
static void layoutSimple(std::vector<std::shared_ptr<DummyNode>>* nodes, int gapX, int gapY, bool horizontal);
|
||||
};
|
||||
|
||||
#endif // LIST_LAYOUTER_H
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "component/controller/helper/ScreenSearchInterfaces.h"
|
||||
#include "component/view/View.h"
|
||||
#include "data/GroupType.h"
|
||||
|
||||
struct DummyEdge;
|
||||
struct DummyNode;
|
||||
@@ -47,6 +48,7 @@ public:
|
||||
virtual void resizeView() = 0;
|
||||
|
||||
virtual Vec2i getViewSize() const = 0;
|
||||
virtual GroupType getGrouping() const = 0;
|
||||
|
||||
virtual void scrollToValues(int xValue, int yValue) = 0;
|
||||
|
||||
|
||||
@@ -156,6 +156,9 @@ size_t GraphViewStyle::getFontSizeForStyleType(NodeType::StyleType type)
|
||||
case NodeType::STYLE_SMALL_NODE:
|
||||
return s_fontSize - 3;
|
||||
|
||||
case NodeType::STYLE_GROUP:
|
||||
return s_fontSize - 2;
|
||||
|
||||
default:
|
||||
return s_fontSize;
|
||||
}
|
||||
@@ -188,7 +191,7 @@ size_t GraphViewStyle::getFontSizeOfTextNode()
|
||||
|
||||
size_t GraphViewStyle::getFontSizeOfGroupNode()
|
||||
{
|
||||
return s_fontSize;
|
||||
return getFontSizeForStyleType(NodeType::STYLE_GROUP);
|
||||
}
|
||||
|
||||
std::string GraphViewStyle::getFontNameForDataNode()
|
||||
@@ -225,6 +228,7 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsForDataNode(NodeType::Styl
|
||||
switch (type)
|
||||
{
|
||||
case NodeType::STYLE_PACKAGE:
|
||||
case NodeType::STYLE_GROUP:
|
||||
margins.left = margins.right = 5;
|
||||
margins.top = margins.bottom = 3;
|
||||
margins.iconWidth = s_fontSize - 3;
|
||||
@@ -331,20 +335,20 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfTextNode()
|
||||
return margins;
|
||||
}
|
||||
|
||||
GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfGroupNode(NodeType::GroupType type, bool hasName)
|
||||
GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfGroupNode(GroupType type, bool hasName)
|
||||
{
|
||||
NodeMargins margins;
|
||||
margins.spacingX = margins.spacingY = GraphViewStyle::s_gridCellPadding;
|
||||
|
||||
if (type == NodeType::GROUP_FRAMELESS)
|
||||
if (type == GroupType::FRAMELESS)
|
||||
{
|
||||
return margins;
|
||||
}
|
||||
|
||||
margins.spacingA = (hasName ? 22 : 0);
|
||||
margins.spacingA = (hasName ? 14 : 0);
|
||||
|
||||
margins.left = margins.right = 20;
|
||||
margins.top = (hasName ? 8 : 20);
|
||||
margins.top = (hasName ? 12 : 20);
|
||||
margins.bottom = 20;
|
||||
|
||||
if (hasName)
|
||||
@@ -352,7 +356,7 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfGroupNode(NodeType::Grou
|
||||
margins.minWidth = margins.charHeight = getFontSizeOfGroupNode();
|
||||
}
|
||||
|
||||
margins.charWidth = getCharWidth(NodeType::STYLE_BIG_NODE);
|
||||
margins.charWidth = getCharWidth(NodeType::STYLE_GROUP);
|
||||
|
||||
return margins;
|
||||
}
|
||||
@@ -401,6 +405,7 @@ GraphViewStyle::NodeStyle GraphViewStyle::getStyleForNodeType(
|
||||
switch (type)
|
||||
{
|
||||
case NodeType::STYLE_PACKAGE:
|
||||
case NodeType::STYLE_GROUP:
|
||||
style.cornerRadius = 0;
|
||||
style.textOffset.x = 5;
|
||||
style.textOffset.y = 3;
|
||||
@@ -555,27 +560,48 @@ GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfTextNode()
|
||||
return style;
|
||||
}
|
||||
|
||||
GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfGroupNode(NodeType::GroupType type, bool isFocused)
|
||||
GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfGroupNode(GroupType type, bool isFocused)
|
||||
{
|
||||
NodeStyle style;
|
||||
|
||||
style.cornerRadius = 15;
|
||||
style.borderWidth = 2;
|
||||
|
||||
std::string colorType = "group/";
|
||||
if (type == NodeType::GROUP_INHERITANCE)
|
||||
if (type == GroupType::DEFAULT)
|
||||
{
|
||||
colorType += "default";
|
||||
}
|
||||
else if (type == GroupType::FILE)
|
||||
{
|
||||
colorType += "file";
|
||||
}
|
||||
else if (type == GroupType::NAMESPACE)
|
||||
{
|
||||
colorType += "namespace";
|
||||
}
|
||||
else if (type == GroupType::INHERITANCE)
|
||||
{
|
||||
colorType += "inheritance";
|
||||
|
||||
if (isFocused)
|
||||
{
|
||||
style.borderWidth = 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return style;
|
||||
}
|
||||
|
||||
style.color = getNodeColor(colorType, isFocused);
|
||||
|
||||
style.cornerRadius = 15;
|
||||
style.borderWidth = 2;
|
||||
|
||||
style.fontName = getFontNameOfGroupNode();
|
||||
style.fontSize = getFontSizeOfGroupNode();
|
||||
style.fontBold = true;
|
||||
|
||||
style.textOffset.x = 15;
|
||||
style.textOffset.y = 6;
|
||||
style.textOffset.x = 12;
|
||||
style.textOffset.y = 5;
|
||||
|
||||
return style;
|
||||
}
|
||||
@@ -638,7 +664,7 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
|
||||
style.verticalOffset = 6;
|
||||
break;
|
||||
case Edge::EDGE_INHERITANCE:
|
||||
style.arrowLength = 20;
|
||||
style.arrowLength = 17;
|
||||
style.arrowWidth = 14;
|
||||
style.arrowClosed = true;
|
||||
style.originOffset.x = 7;
|
||||
@@ -648,6 +674,7 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
|
||||
style.verticalOffset = 0;
|
||||
style.cornerRadius = 7;
|
||||
style.zValue = isActive ? 2 : -3;
|
||||
style.width = isActive ? 3 : 2;
|
||||
|
||||
if (isTrailEdge)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "utility/math/Vector2.h"
|
||||
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/GroupType.h"
|
||||
#include "data/parser/AccessKind.h"
|
||||
|
||||
class GraphViewStyleImpl;
|
||||
@@ -117,7 +118,7 @@ public:
|
||||
static NodeMargins getMarginsOfExpandToggleNode();
|
||||
static NodeMargins getMarginsOfBundleNode();
|
||||
static NodeMargins getMarginsOfTextNode();
|
||||
static NodeMargins getMarginsOfGroupNode(NodeType::GroupType type, bool hasName);
|
||||
static NodeMargins getMarginsOfGroupNode(GroupType type, bool hasName);
|
||||
|
||||
static NodeStyle getStyleForNodeType(
|
||||
NodeType type, bool defined, bool isActive, bool isFocused, bool hasChildren, bool hasQualifier);
|
||||
@@ -127,7 +128,7 @@ public:
|
||||
static NodeStyle getStyleOfBundleNode(bool isFocused);
|
||||
static NodeStyle getStyleOfQualifier();
|
||||
static NodeStyle getStyleOfTextNode();
|
||||
static NodeStyle getStyleOfGroupNode(NodeType::GroupType type, bool isFocused);
|
||||
static NodeStyle getStyleOfGroupNode(GroupType type, bool isFocused);
|
||||
|
||||
static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge);
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "data/GroupType.h"
|
||||
|
||||
std::wstring groupTypeToString(GroupType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GroupType::NONE: return L"none";
|
||||
case GroupType::DEFAULT: return L"default";
|
||||
case GroupType::FRAMELESS: return L"frameless";
|
||||
case GroupType::FILE: return L"file";
|
||||
case GroupType::NAMESPACE: return L"namespace";
|
||||
case GroupType::INHERITANCE: return L"inheritance";
|
||||
}
|
||||
|
||||
return L"none";
|
||||
}
|
||||
|
||||
GroupType stringToGroupType(const std::wstring& value)
|
||||
{
|
||||
if (value == groupTypeToString(GroupType::NONE)) return GroupType::NONE;
|
||||
if (value == groupTypeToString(GroupType::DEFAULT)) return GroupType::DEFAULT;
|
||||
if (value == groupTypeToString(GroupType::FRAMELESS)) return GroupType::FRAMELESS;
|
||||
if (value == groupTypeToString(GroupType::FILE)) return GroupType::FILE;
|
||||
if (value == groupTypeToString(GroupType::NAMESPACE)) return GroupType::NAMESPACE;
|
||||
if (value == groupTypeToString(GroupType::INHERITANCE)) return GroupType::INHERITANCE;
|
||||
|
||||
return GroupType::NONE;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef GROUP_TYPE_H
|
||||
#define GROUP_TYPE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class GroupType
|
||||
{
|
||||
NONE,
|
||||
DEFAULT,
|
||||
FRAMELESS,
|
||||
FILE,
|
||||
NAMESPACE,
|
||||
INHERITANCE
|
||||
};
|
||||
|
||||
std::wstring groupTypeToString(GroupType type);
|
||||
GroupType stringToGroupType(const std::wstring& value);
|
||||
|
||||
enum class GroupLayout
|
||||
{
|
||||
LIST,
|
||||
SKEWED,
|
||||
BUCKET
|
||||
};
|
||||
|
||||
#endif // GROUP_TYPE_H
|
||||
@@ -48,13 +48,8 @@ public:
|
||||
{
|
||||
STYLE_PACKAGE = 0,
|
||||
STYLE_SMALL_NODE = 1,
|
||||
STYLE_BIG_NODE = 2
|
||||
};
|
||||
|
||||
enum GroupType
|
||||
{
|
||||
GROUP_FRAMELESS,
|
||||
GROUP_INHERITANCE
|
||||
STYLE_BIG_NODE = 2,
|
||||
STYLE_GROUP = 3
|
||||
};
|
||||
|
||||
struct BundleInfo
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id id) const = 0;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id>& nodeIds) const = 0;
|
||||
virtual std::map<Id, std::pair<Id, NameHierarchy>> getNodeIdToParentFileMap(const std::vector<Id>& nodeIds) const = 0;
|
||||
|
||||
virtual NodeType getNodeTypeForNodeWithId(Id id) const = 0;
|
||||
|
||||
|
||||
@@ -85,6 +85,16 @@ std::vector<NameHierarchy> StorageAccessProxy::getNameHierarchiesForNodeIds(cons
|
||||
return std::vector<NameHierarchy>();
|
||||
}
|
||||
|
||||
std::map<Id, std::pair<Id, NameHierarchy>> StorageAccessProxy::getNodeIdToParentFileMap(const std::vector<Id>& nodeIds) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNodeIdToParentFileMap(nodeIds);
|
||||
}
|
||||
|
||||
return { };
|
||||
}
|
||||
|
||||
NodeType StorageAccessProxy::getNodeTypeForNodeWithId(Id id) const
|
||||
{
|
||||
if (hasSubject())
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id id) const override;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id>& nodeIds) const override;
|
||||
virtual std::map<Id, std::pair<Id, NameHierarchy>> getNodeIdToParentFileMap(const std::vector<Id>& nodeIds) const override;
|
||||
|
||||
virtual NodeType getNodeTypeForNodeWithId(Id id) const override;
|
||||
|
||||
|
||||
@@ -445,6 +445,28 @@ std::vector<NameHierarchy> PersistentStorage::getNameHierarchiesForNodeIds(const
|
||||
return nameHierarchies;
|
||||
}
|
||||
|
||||
std::map<Id, std::pair<Id, NameHierarchy>> PersistentStorage::getNodeIdToParentFileMap(const std::vector<Id>& nodeIds) const
|
||||
{
|
||||
std::map<Id, std::pair<Id, NameHierarchy>> nodeIdToParentFileMap;
|
||||
|
||||
std::shared_ptr<SourceLocationCollection> locations = m_sqliteIndexStorage.getSourceLocationsForElementIds(nodeIds);
|
||||
locations->forEachSourceLocation(
|
||||
[this, &nodeIdToParentFileMap](SourceLocation* location)
|
||||
{
|
||||
if (location->isStartLocation() && location->isScopeLocation())
|
||||
{
|
||||
for (Id tokenId : location->getTokenIds())
|
||||
{
|
||||
nodeIdToParentFileMap.emplace(tokenId, std::make_pair(getFileNodeId(location->getFilePath()),
|
||||
NameHierarchy(location->getFilePath().wstr(), NAME_DELIMITER_FILE)));
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return nodeIdToParentFileMap;
|
||||
}
|
||||
|
||||
NodeType PersistentStorage::getNodeTypeForNodeWithId(Id nodeId) const
|
||||
{
|
||||
return utility::intToType(m_sqliteIndexStorage.getFirstById<StorageNode>(nodeId).type);
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id nodeId) const override;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id>& nodeIds) const override;
|
||||
virtual std::map<Id, std::pair<Id, NameHierarchy>> getNodeIdToParentFileMap(const std::vector<Id>& nodeIds) const override;
|
||||
|
||||
virtual NodeType getNodeTypeForNodeWithId(Id nodeId) const override;
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "utility/text/TextAccess.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
#include "data/location/SourceLocationCollection.h"
|
||||
#include "data/location/SourceLocationFile.h"
|
||||
|
||||
const size_t SqliteIndexStorage::s_storageVersion = 15;
|
||||
|
||||
SqliteIndexStorage::SqliteIndexStorage(const FilePath& dbFilePath)
|
||||
@@ -704,9 +707,60 @@ std::shared_ptr<SourceLocationFile> SqliteIndexStorage::getSourceLocationsOfType
|
||||
return getSourceLocationsForFile(filePath, "AND type == " + std::to_string(locationTypeToInt(type)));
|
||||
}
|
||||
|
||||
std::shared_ptr<SourceLocationCollection> SqliteIndexStorage::getSourceLocationsForElementIds(
|
||||
const std::vector<Id>& elementIds) const
|
||||
{
|
||||
std::vector<Id> sourceLocationIds;
|
||||
std::map<Id, std::vector<Id>> sourceLocationIdToElementIds;
|
||||
for (const StorageOccurrence& occurrence : getOccurrencesForElementIds(elementIds))
|
||||
{
|
||||
sourceLocationIds.push_back(occurrence.sourceLocationId);
|
||||
sourceLocationIdToElementIds[occurrence.sourceLocationId].push_back(occurrence.elementId);
|
||||
}
|
||||
|
||||
CppSQLite3Query q = executeQuery(
|
||||
"SELECT source_location.id, file.path, source_location.start_line, source_location.start_column, "
|
||||
"source_location.end_line, source_location.end_column, source_location.type "
|
||||
"FROM source_location INNER JOIN file ON (file.id = source_location.file_node_id) "
|
||||
"WHERE source_location.id IN (" + utility::join(utility::toStrings(sourceLocationIds), ',') + ");"
|
||||
);
|
||||
|
||||
std::shared_ptr<SourceLocationCollection> ret = std::make_shared<SourceLocationCollection>();
|
||||
|
||||
while (!q.eof())
|
||||
{
|
||||
const Id id = q.getIntField(0, 0);
|
||||
const std::string filePath = q.getStringField(1, "");
|
||||
const int startLineNumber = q.getIntField(2, -1);
|
||||
const int startColNumber = q.getIntField(3, -1);
|
||||
const int endLineNumber = q.getIntField(4, -1);
|
||||
const int endColNumber = q.getIntField(5, -1);
|
||||
const int type = q.getIntField(6, -1);
|
||||
|
||||
if (id != 0 && filePath.size() && startLineNumber != -1 && startColNumber != -1 && endLineNumber != -1 &&
|
||||
endColNumber != -1 && type != -1)
|
||||
{
|
||||
ret->addSourceLocation(
|
||||
intToLocationType(type),
|
||||
id,
|
||||
sourceLocationIdToElementIds[id],
|
||||
FilePath(utility::decodeFromUtf8(filePath)),
|
||||
startLineNumber,
|
||||
startColNumber,
|
||||
endLineNumber,
|
||||
endColNumber
|
||||
);
|
||||
}
|
||||
|
||||
q.nextRow();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<StorageOccurrence> SqliteIndexStorage::getOccurrencesForLocationId(Id locationId) const
|
||||
{
|
||||
std::vector<Id> locationIds {locationId};
|
||||
std::vector<Id> locationIds { locationId };
|
||||
return getOccurrencesForLocationIds(locationIds);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "data/location/SourceLocationFile.h"
|
||||
#include "data/location/LocationType.h"
|
||||
#include "data/storage/sqlite/SqliteDatabaseIndex.h"
|
||||
#include "data/storage/sqlite/SqliteStorage.h"
|
||||
#include "data/storage/type/StorageCommentLocation.h"
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
class TextAccess;
|
||||
class Version;
|
||||
class SourceLocationCollection;
|
||||
class SourceLocationFile;
|
||||
struct ParseLocation;
|
||||
|
||||
class SqliteIndexStorage
|
||||
@@ -95,6 +97,8 @@ public:
|
||||
std::shared_ptr<SourceLocationFile> getSourceLocationsOfTypeInFile(
|
||||
const FilePath& filePath, LocationType type) const;
|
||||
|
||||
std::shared_ptr<SourceLocationCollection> getSourceLocationsForElementIds(const std::vector<Id>& elementIds) const;
|
||||
|
||||
std::vector<StorageOccurrence> getOccurrencesForLocationId(Id locationId) const;
|
||||
std::vector<StorageOccurrence> getOccurrencesForLocationIds(const std::vector<Id>& locationIds) const;
|
||||
std::vector<StorageOccurrence> getOccurrencesForElementIds(const std::vector<Id>& elementIds) const;
|
||||
|
||||
@@ -241,6 +241,16 @@ void ApplicationSettings::setGraphControlsVisible(bool visible)
|
||||
setValue<bool>("application/graph_controls_visible", visible);
|
||||
}
|
||||
|
||||
GroupType ApplicationSettings::getGraphGrouping() const
|
||||
{
|
||||
return stringToGroupType(getValue<std::wstring>("application/graph_grouping", groupTypeToString(GroupType::NONE)));
|
||||
}
|
||||
|
||||
void ApplicationSettings::setGraphGrouping(GroupType type)
|
||||
{
|
||||
setValue<std::wstring>("application/graph_grouping", groupTypeToString(type));
|
||||
}
|
||||
|
||||
int ApplicationSettings::getScreenAutoScaling() const
|
||||
{
|
||||
return getValue<int>("screen/auto_scaling", 1);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "data/GroupType.h"
|
||||
#include "settings/Settings.h"
|
||||
|
||||
class TimeStamp;
|
||||
@@ -63,6 +64,9 @@ public:
|
||||
bool getGraphControlsVisible() const;
|
||||
void setGraphControlsVisible(bool visible);
|
||||
|
||||
GroupType getGraphGrouping() const;
|
||||
void setGraphGrouping(GroupType type);
|
||||
|
||||
// screen
|
||||
int getScreenAutoScaling() const;
|
||||
void setScreenAutoScaling(int autoScaling);
|
||||
|
||||
@@ -18,8 +18,19 @@ public:
|
||||
NameHierarchy nameHierarchy;
|
||||
};
|
||||
|
||||
MessageActivateNodes()
|
||||
MessageActivateNodes(Id tokenId = 0)
|
||||
{
|
||||
if (tokenId > 0)
|
||||
{
|
||||
addNode(tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
void addNode(Id tokenId)
|
||||
{
|
||||
ActiveNode node;
|
||||
node.nodeId = tokenId;
|
||||
nodes.push_back(node);
|
||||
}
|
||||
|
||||
void addNode(Id tokenId, const NameHierarchy& nameHierarchy)
|
||||
@@ -27,7 +38,6 @@ public:
|
||||
ActiveNode node;
|
||||
node.nodeId = tokenId;
|
||||
node.nameHierarchy = nameHierarchy;
|
||||
|
||||
nodes.push_back(node);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "utility/messaging/type/MessageActivateTrail.h"
|
||||
#include "utility/messaging/type/MessageDeactivateEdge.h"
|
||||
#include "utility/messaging/type/MessageRefresh.h"
|
||||
#include "utility/messaging/type/MessageScrollGraph.h"
|
||||
#include "utility/messaging/type/MessageStatus.h"
|
||||
#include "utility/ResourcePaths.h"
|
||||
@@ -158,6 +159,52 @@ void QtGraphView::initView()
|
||||
updateTrailButtons();
|
||||
trailDepthChanged(0);
|
||||
}
|
||||
|
||||
// group controls
|
||||
{
|
||||
m_groupFileButton = new QtSelfRefreshIconButton(
|
||||
"", ResourcePaths::getGuiPath().concatenate(L"graph_view/images/file.png"), "search/button");
|
||||
m_groupNamespaceButton = new QtSelfRefreshIconButton(
|
||||
"", ResourcePaths::getGuiPath().concatenate(L"graph_view/images/group_namespace.png"), "search/button");
|
||||
|
||||
m_groupFileButton->setObjectName("group_right_button");
|
||||
m_groupNamespaceButton->setObjectName("group_left_button");
|
||||
|
||||
m_groupFileButton->setToolTip("group by file");
|
||||
m_groupNamespaceButton->setToolTip("group by package/namespace");
|
||||
|
||||
m_groupFileButton->setCheckable(true);
|
||||
m_groupNamespaceButton->setCheckable(true);
|
||||
|
||||
m_groupFileButton->setIconSize(QSize(14, 14));
|
||||
m_groupNamespaceButton->setIconSize(QSize(14, 14));
|
||||
|
||||
connect(m_groupFileButton, &QPushButton::clicked, [this](){ groupingUpdated(m_groupFileButton); });
|
||||
connect(m_groupNamespaceButton, &QPushButton::clicked, [this]() { groupingUpdated(m_groupNamespaceButton); });
|
||||
|
||||
GroupType type = ApplicationSettings::getInstance()->getGraphGrouping();
|
||||
if (type == GroupType::FILE)
|
||||
{
|
||||
m_groupFileButton->setChecked(true);
|
||||
}
|
||||
else if (type == GroupType::NAMESPACE)
|
||||
{
|
||||
m_groupNamespaceButton->setChecked(true);
|
||||
}
|
||||
|
||||
|
||||
m_groupWidget = new QWidget(widget);
|
||||
m_groupWidget->setGeometry(38, 8, 54, 26);
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(2);
|
||||
|
||||
layout->addWidget(m_groupNamespaceButton);
|
||||
layout->addWidget(m_groupFileButton);
|
||||
|
||||
m_groupWidget->setLayout(layout);
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphView::refreshView()
|
||||
@@ -173,6 +220,8 @@ void QtGraphView::refreshView()
|
||||
view->setAppZoomFactor(GraphViewStyle::getZoomFactor());
|
||||
|
||||
m_trailWidget->setStyleSheet(css.c_str());
|
||||
m_groupWidget->setStyleSheet(css.c_str());
|
||||
|
||||
updateTrailButtons();
|
||||
});
|
||||
}
|
||||
@@ -407,7 +456,7 @@ void QtGraphView::defocusTokenIds(const std::vector<Id>& defocusedTokenIds)
|
||||
for (const Id& tokenId : defocusedTokenIds)
|
||||
{
|
||||
QtGraphNode* node = findNodeRecursive(m_oldNodes, tokenId);
|
||||
if (node && node->isDataNode())
|
||||
if (node && (node->isDataNode() || node->isGroupNode()))
|
||||
{
|
||||
node->focusOut();
|
||||
continue;
|
||||
@@ -441,6 +490,20 @@ Vec2i QtGraphView::getViewSize() const
|
||||
return Vec2i((view->width() - 50) / zoomFactor, (view->height() - 100) / zoomFactor);
|
||||
}
|
||||
|
||||
GroupType QtGraphView::getGrouping() const
|
||||
{
|
||||
if (m_groupFileButton->isChecked())
|
||||
{
|
||||
return GroupType::FILE;
|
||||
}
|
||||
else if (m_groupNamespaceButton->isChecked())
|
||||
{
|
||||
return GroupType::NAMESPACE;
|
||||
}
|
||||
|
||||
return GroupType::NONE;
|
||||
}
|
||||
|
||||
void QtGraphView::scrollToValues(int xValue, int yValue)
|
||||
{
|
||||
m_restoreScroll = true;
|
||||
@@ -560,9 +623,17 @@ void QtGraphView::pressedCharacterKey(QChar c)
|
||||
const QtGraphNode* node = nullptr;
|
||||
bool hasTextNodes = false;
|
||||
|
||||
for (const QtGraphNode* n : m_oldNodes)
|
||||
std::vector<QtGraphNode*> nodes(m_oldNodes.begin(), m_oldNodes.end());
|
||||
|
||||
size_t i = 0;
|
||||
while (i < nodes.size())
|
||||
{
|
||||
if (n->isTextNode() && n->getName().size())
|
||||
QtGraphNode* n = nodes[i++];
|
||||
if (n->isGroupNode())
|
||||
{
|
||||
nodes.insert(nodes.end(), n->getSubNodes().begin(), n->getSubNodes().end());
|
||||
}
|
||||
else if (n->isTextNode() && n->getName().size())
|
||||
{
|
||||
hasTextNodes = true;
|
||||
QChar start(n->getName()[0]);
|
||||
@@ -657,6 +728,20 @@ void QtGraphView::clickedForwardTrail()
|
||||
activateTrail(true);
|
||||
}
|
||||
|
||||
void QtGraphView::groupingUpdated(QPushButton* button)
|
||||
{
|
||||
(button == m_groupFileButton ? m_groupNamespaceButton : m_groupFileButton)->setChecked(false);
|
||||
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
if (appSettings->getGraphGrouping() != getGrouping())
|
||||
{
|
||||
appSettings->setGraphGrouping(getGrouping());
|
||||
appSettings->save();
|
||||
}
|
||||
|
||||
MessageRefresh().refreshUiOnly().noReloadStyle().dispatch();
|
||||
}
|
||||
|
||||
MessageActivateTrail QtGraphView::getMessageActivateTrail(bool forward)
|
||||
{
|
||||
MessageActivateTrail message(0, 0, 0, 0, false);
|
||||
@@ -868,7 +953,7 @@ QtGraphNode* QtGraphView::createNodeRecursive(
|
||||
QtGraphNode* newNode = nullptr;
|
||||
if (node->isGraphNode())
|
||||
{
|
||||
newNode = new QtGraphNodeData(node->data, node->name, node->childVisible, node->hasQualifier);
|
||||
newNode = new QtGraphNodeData(node->data, node->name, node->childVisible, node->getQualifierNode() != nullptr);
|
||||
}
|
||||
else if (node->isAccessNode())
|
||||
{
|
||||
@@ -892,7 +977,7 @@ QtGraphNode* QtGraphView::createNodeRecursive(
|
||||
}
|
||||
else if (node->isGroupNode())
|
||||
{
|
||||
newNode = new QtGraphNodeGroup(node->tokenId, node->name, node->groupType);
|
||||
newNode = new QtGraphNodeGroup(node->tokenId, node->name, node->groupType, node->interactive);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
virtual void resizeView();
|
||||
|
||||
virtual Vec2i getViewSize() const;
|
||||
virtual GroupType getGrouping() const;
|
||||
|
||||
virtual void scrollToValues(int xValue, int yValue);
|
||||
|
||||
@@ -84,6 +85,8 @@ private slots:
|
||||
void clickedBackwardTrail();
|
||||
void clickedForwardTrail();
|
||||
|
||||
void groupingUpdated(QPushButton* button);
|
||||
|
||||
private:
|
||||
MessageActivateTrail getMessageActivateTrail(bool forward);
|
||||
void activateTrail(bool forward);
|
||||
@@ -153,6 +156,10 @@ private:
|
||||
QSlider* m_trailDepthSlider;
|
||||
QLabel* m_trailDepthLabel;
|
||||
|
||||
QWidget* m_groupWidget;
|
||||
QtSelfRefreshIconButton* m_groupFileButton;
|
||||
QtSelfRefreshIconButton* m_groupNamespaceButton;
|
||||
|
||||
std::vector<QRectF> m_virtualNodeRects;
|
||||
|
||||
// Name matches
|
||||
|
||||
@@ -88,8 +88,8 @@ Id QtGraphEdge::getTokenId() const
|
||||
|
||||
void QtGraphEdge::updateLine()
|
||||
{
|
||||
QtGraphNode* owner = m_owner;
|
||||
QtGraphNode* target = m_target;
|
||||
const QtGraphNode* owner = m_owner;
|
||||
const QtGraphNode* target = m_target;
|
||||
|
||||
Edge::EdgeType type = (getData() ? getData()->getType() : Edge::EDGE_AGGREGATION);
|
||||
GraphViewStyle::EdgeStyle style = GraphViewStyle::getStyleForEdgeType(type, m_isActive | m_isFocused, false, m_isTrailEdge);
|
||||
@@ -97,8 +97,22 @@ void QtGraphEdge::updateLine()
|
||||
Vec4i ownerRect = owner->getBoundingRect();
|
||||
Vec4i targetRect = target->getBoundingRect();
|
||||
|
||||
Vec4i ownerParentRect = owner->getParentBoundingRect();
|
||||
Vec4i targetParentRect = target->getParentBoundingRect();
|
||||
Vec4i ownerParentRect;
|
||||
Vec4i targetParentRect;
|
||||
|
||||
const QtGraphNode* ownerNonGroupParent = owner->getLastNonGroupParent();
|
||||
const QtGraphNode* targetNonGroupParent = target->getLastNonGroupParent();
|
||||
|
||||
if (owner->getLastParent() == target->getLastParent() && owner->getLastParent()->isGroupNode())
|
||||
{
|
||||
ownerParentRect = ownerNonGroupParent->getBoundingRect();
|
||||
targetParentRect = targetNonGroupParent->getBoundingRect();
|
||||
}
|
||||
else
|
||||
{
|
||||
ownerParentRect = owner->getLastParent()->getBoundingRect();
|
||||
targetParentRect = target->getLastParent()->getBoundingRect();
|
||||
}
|
||||
|
||||
if (m_useBezier)
|
||||
{
|
||||
@@ -142,7 +156,7 @@ void QtGraphEdge::updateLine()
|
||||
bezier->setRoute(route);
|
||||
bezier->setPivot(QtLineItemBase::PIVOT_MIDDLE);
|
||||
|
||||
if (owner->getLastParent() == target->getLastParent())
|
||||
if (ownerNonGroupParent == targetNonGroupParent)
|
||||
{
|
||||
if (ownerRect.y() < target->getBoundingRect().y())
|
||||
{
|
||||
@@ -163,7 +177,7 @@ void QtGraphEdge::updateLine()
|
||||
|
||||
QtLineItemAngled* child = dynamic_cast<QtLineItemAngled*>(m_child);
|
||||
|
||||
if (owner->getIsActive() && owner->getLastParent() == target->getLastParent())
|
||||
if (owner->getIsActive() && ownerNonGroupParent == targetNonGroupParent)
|
||||
{
|
||||
child->setOnBack(true);
|
||||
}
|
||||
@@ -172,7 +186,7 @@ void QtGraphEdge::updateLine()
|
||||
{
|
||||
child->setEarlyBend(true);
|
||||
|
||||
if (owner->getLastParent() == target->getLastParent() ||
|
||||
if (ownerNonGroupParent == targetNonGroupParent ||
|
||||
(type == Edge::EDGE_OVERRIDE &&
|
||||
targetParentRect.z() + style.targetOffset.x + style.originOffset.x > ownerParentRect.x()))
|
||||
{
|
||||
@@ -185,7 +199,7 @@ void QtGraphEdge::updateLine()
|
||||
}
|
||||
|
||||
if (type == Edge::EDGE_INHERITANCE || (type == Edge::EDGE_TEMPLATE_SPECIALIZATION &&
|
||||
owner == owner->getLastParent() && target == target->getLastParent()))
|
||||
owner == owner->getLastNonGroupParent() && target == target->getLastNonGroupParent()))
|
||||
{
|
||||
child->setRoute(QtLineItemBase::ROUTE_VERTICAL);
|
||||
|
||||
@@ -194,7 +208,8 @@ void QtGraphEdge::updateLine()
|
||||
child->setEarlyBend(true);
|
||||
}
|
||||
}
|
||||
else if (type != Edge::EDGE_AGGREGATION || owner != owner->getLastParent() || target != target->getLastParent())
|
||||
else if (type != Edge::EDGE_AGGREGATION ||
|
||||
owner != owner->getLastNonGroupParent() || target != target->getLastNonGroupParent())
|
||||
{
|
||||
child->setRoute(QtLineItemBase::ROUTE_HORIZONTAL);
|
||||
}
|
||||
@@ -250,13 +265,18 @@ void QtGraphEdge::setIsFocused(bool isFocused)
|
||||
|
||||
void QtGraphEdge::onClick()
|
||||
{
|
||||
Edge::EdgeType type = (getData() ? getData()->getType() : Edge::EDGE_AGGREGATION);
|
||||
|
||||
if (!getData() || m_owner->isGroupNode() || m_target->isGroupNode())
|
||||
{
|
||||
QtGraphNode* node =
|
||||
((m_direction == TokenComponentAggregation::DIRECTION_BACKWARD) == (type != Edge::EDGE_INHERITANCE))
|
||||
? m_owner : m_target;
|
||||
QtGraphNode* node = (m_direction == TokenComponentAggregation::DIRECTION_BACKWARD ? m_owner : m_target);
|
||||
if (m_owner->isGroupNode())
|
||||
{
|
||||
node = m_owner;
|
||||
}
|
||||
else if (m_target->isGroupNode())
|
||||
{
|
||||
node = m_target;
|
||||
}
|
||||
|
||||
MessageGraphNodeBundleSplit(node->getTokenId()).dispatch();
|
||||
}
|
||||
else if (isTrailEdge())
|
||||
|
||||
@@ -61,13 +61,13 @@ QtGraphNode* QtGraphNode::getParent() const
|
||||
return m_parentNode;
|
||||
}
|
||||
|
||||
QtGraphNode* QtGraphNode::getLastParent() const
|
||||
QtGraphNode* QtGraphNode::getLastParent(bool noGroups) const
|
||||
{
|
||||
QtGraphNode* node = const_cast<QtGraphNode*>(this);
|
||||
while (true)
|
||||
{
|
||||
QtGraphNode* parent = dynamic_cast<QtGraphNode*>(node->parentItem());
|
||||
if (!parent)
|
||||
if (!parent || (noGroups && parent->isGroupNode()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -76,6 +76,11 @@ QtGraphNode* QtGraphNode::getLastParent() const
|
||||
return node;
|
||||
}
|
||||
|
||||
QtGraphNode* QtGraphNode::getLastNonGroupParent() const
|
||||
{
|
||||
return getLastParent(true);
|
||||
}
|
||||
|
||||
void QtGraphNode::setParent(QtGraphNode* parentNode)
|
||||
{
|
||||
m_parentNode = parentNode;
|
||||
@@ -86,7 +91,7 @@ void QtGraphNode::setParent(QtGraphNode* parentNode)
|
||||
}
|
||||
}
|
||||
|
||||
std::list<QtGraphNode*> QtGraphNode::getSubNodes() const
|
||||
const std::list<QtGraphNode*>& QtGraphNode::getSubNodes() const
|
||||
{
|
||||
return m_subNodes;
|
||||
}
|
||||
@@ -142,11 +147,6 @@ Vec4i QtGraphNode::getBoundingRect() const
|
||||
return Vec4i(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
|
||||
}
|
||||
|
||||
Vec4i QtGraphNode::getParentBoundingRect() const
|
||||
{
|
||||
return getLastParent()->getBoundingRect();
|
||||
}
|
||||
|
||||
void QtGraphNode::addOutEdge(QtGraphEdge* edge)
|
||||
{
|
||||
m_outEdges.push_back(edge);
|
||||
@@ -348,7 +348,7 @@ void QtGraphNode::addSubNode(QtGraphNode* node)
|
||||
if (node->getIsActive())
|
||||
{
|
||||
QtGraphNode* parent = this;
|
||||
while (parent)
|
||||
while (parent && !parent->isGroupNode())
|
||||
{
|
||||
parent->setZValue(-10.0f);
|
||||
parent->m_text->setZValue(-9.0f);
|
||||
|
||||
@@ -37,10 +37,11 @@ public:
|
||||
virtual ~QtGraphNode();
|
||||
|
||||
QtGraphNode* getParent() const;
|
||||
QtGraphNode* getLastParent() const;
|
||||
QtGraphNode* getLastParent(bool noGroups = false) const;
|
||||
QtGraphNode* getLastNonGroupParent() const;
|
||||
void setParent(QtGraphNode* parentNode);
|
||||
|
||||
std::list<QtGraphNode*> getSubNodes() const;
|
||||
const std::list<QtGraphNode*>& getSubNodes() const;
|
||||
|
||||
Vec2i getPosition() const;
|
||||
virtual bool setPosition(const Vec2i& position);
|
||||
@@ -52,7 +53,6 @@ public:
|
||||
void setSize(const QSize& size);
|
||||
|
||||
Vec4i getBoundingRect() const;
|
||||
Vec4i getParentBoundingRect() const;
|
||||
|
||||
void addOutEdge(QtGraphEdge* edge);
|
||||
void addInEdge(QtGraphEdge* edge);
|
||||
|
||||
@@ -55,11 +55,7 @@ void QtGraphNodeData::onClick()
|
||||
return;
|
||||
}
|
||||
|
||||
FilePath path = getFilePath();
|
||||
|
||||
MessageActivateNodes message;
|
||||
message.addNode(m_data->getId(), path.empty() ? m_data->getNameHierarchy() : NameHierarchy(path.wstr(), NAME_DELIMITER_FILE));
|
||||
message.dispatch();
|
||||
MessageActivateNodes(m_data->getId()).dispatch();
|
||||
}
|
||||
|
||||
void QtGraphNodeData::moved(const Vec2i& oldPosition)
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
#include "qt/view/graphElements/QtGraphNodeGroup.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QGraphicsPolygonItem>
|
||||
#include <QGraphicsSceneHoverEvent>
|
||||
#include <QPainterPath>
|
||||
#include <QPen>
|
||||
|
||||
#include "utility/messaging/type/MessageActivateNodes.h"
|
||||
#include "utility/messaging/type/MessageFocusIn.h"
|
||||
#include "utility/messaging/type/MessageFocusOut.h"
|
||||
#include "utility/messaging/type/MessageGraphNodeBundleSplit.h"
|
||||
|
||||
#include "qt/graphics/QtRoundedRectItem.h"
|
||||
|
||||
QtGraphNodeGroup::QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeType::GroupType type)
|
||||
QtGraphNodeGroup::QtGraphNodeGroup(
|
||||
Id tokenId, const std::wstring& name, GroupType type, bool interactive
|
||||
)
|
||||
: m_tokenId(tokenId)
|
||||
, m_type(type)
|
||||
, m_interactive(interactive)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
if (interactive)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
|
||||
setName(name);
|
||||
setZValue(-10.0f);
|
||||
m_rect->setZValue(-10.0f);
|
||||
|
||||
if (type == NodeType::GROUP_FRAMELESS)
|
||||
if (type == GroupType::FRAMELESS)
|
||||
{
|
||||
m_rect->hide();
|
||||
return;
|
||||
@@ -29,25 +38,26 @@ QtGraphNodeGroup::QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeTyp
|
||||
return;
|
||||
}
|
||||
|
||||
m_background = new QtRoundedRectItem(this);
|
||||
m_backgroundTopRight = new QGraphicsRectItem(this);
|
||||
m_backgroundBottomLeft = new QGraphicsRectItem(this);
|
||||
|
||||
m_background->setZValue(-10.0f);
|
||||
m_backgroundTopRight->setZValue(-10.0f);
|
||||
m_backgroundBottomLeft->setZValue(-10.0f);
|
||||
m_background = new QGraphicsPolygonItem(this);
|
||||
m_background->setZValue(-3.f);
|
||||
|
||||
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(type, false);
|
||||
GraphViewStyle::NodeMargins margins = GraphViewStyle::getMarginsOfGroupNode(type, true);
|
||||
|
||||
int width = style.textOffset.x * 2 + style.borderWidth + margins.charWidth * name.size();
|
||||
int height = margins.top * 2 + margins.charHeight;
|
||||
int height = margins.spacingA + margins.charHeight;
|
||||
int radius = style.cornerRadius;
|
||||
|
||||
m_background->setRadius(style.cornerRadius);
|
||||
m_background->setRect(0, 0, width, height);
|
||||
QPainterPath path;
|
||||
path.moveTo(width, 0);
|
||||
path.lineTo(radius, 0);
|
||||
path.arcTo(0, 0, 2 * radius, 2 * radius, 90, 90);
|
||||
path.lineTo(0, height);
|
||||
path.lineTo(width - radius, height);
|
||||
path.arcTo(width - 2 * radius, height - 2 * radius, 2 * radius, 2 * radius, 270, 90);
|
||||
path.closeSubpath();
|
||||
|
||||
m_backgroundTopRight->setRect(width - style.cornerRadius, 0, style.cornerRadius, style.cornerRadius);
|
||||
m_backgroundBottomLeft->setRect(0, height - style.cornerRadius, style.cornerRadius, style.cornerRadius);
|
||||
m_background->setPolygon(path.toFillPolygon());
|
||||
}
|
||||
|
||||
QtGraphNodeGroup::~QtGraphNodeGroup()
|
||||
@@ -66,24 +76,64 @@ Id QtGraphNodeGroup::getTokenId() const
|
||||
|
||||
void QtGraphNodeGroup::onClick()
|
||||
{
|
||||
MessageGraphNodeBundleSplit(m_tokenId).dispatch();
|
||||
if (!m_interactive || !m_isHovering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_type == GroupType::FILE || m_type == GroupType::NAMESPACE)
|
||||
{
|
||||
MessageActivateNodes(m_tokenId).dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageGraphNodeBundleSplit(m_tokenId).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNodeGroup::updateStyle()
|
||||
{
|
||||
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(m_type, false);
|
||||
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(m_type, m_isHovering);
|
||||
|
||||
if (m_background)
|
||||
{
|
||||
m_background->setBrush(QColor(style.color.border.c_str()));
|
||||
m_background->setPen(QPen(Qt::transparent));
|
||||
|
||||
m_backgroundTopRight->setBrush(QColor(style.color.border.c_str()));
|
||||
m_backgroundTopRight->setPen(QPen(Qt::transparent));
|
||||
|
||||
m_backgroundBottomLeft->setBrush(QColor(style.color.border.c_str()));
|
||||
m_backgroundBottomLeft->setPen(QPen(Qt::transparent));
|
||||
}
|
||||
|
||||
setStyle(style);
|
||||
}
|
||||
|
||||
void QtGraphNodeGroup::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
|
||||
{
|
||||
if (m_type == GroupType::FILE || m_type == GroupType::NAMESPACE)
|
||||
{
|
||||
MessageFocusOut({ m_tokenId }).dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
focusOut();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNodeGroup::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
|
||||
{
|
||||
if (!m_background || m_background->contains(event->pos()))
|
||||
{
|
||||
if (!m_isHovering)
|
||||
{
|
||||
if (m_type == GroupType::FILE || m_type == GroupType::NAMESPACE)
|
||||
{
|
||||
MessageFocusIn({ m_tokenId }, TOOLTIP_ORIGIN_GRAPH).dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
focusIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_isHovering)
|
||||
{
|
||||
hoverLeaveEvent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#ifndef QT_GRAPH_NODE_GROUP_H
|
||||
#define QT_GRAPH_NODE_GROUP_H
|
||||
|
||||
#include "data/NodeType.h"
|
||||
#include "data/GroupType.h"
|
||||
#include "qt/view/graphElements/QtGraphNode.h"
|
||||
|
||||
class QGraphicsRectItem;
|
||||
class QtRoundedRectItem;
|
||||
class QGraphicsPolygonItem;
|
||||
|
||||
class QtGraphNodeGroup
|
||||
: public QtGraphNode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeType::GroupType type);
|
||||
QtGraphNodeGroup(Id tokenId, const std::wstring& name, GroupType type, bool interactive);
|
||||
virtual ~QtGraphNodeGroup();
|
||||
|
||||
// QtGraphNode implementation
|
||||
@@ -22,13 +21,16 @@ public:
|
||||
virtual void onClick();
|
||||
virtual void updateStyle();
|
||||
|
||||
protected:
|
||||
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
|
||||
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event);
|
||||
|
||||
private:
|
||||
Id m_tokenId;
|
||||
NodeType::GroupType m_type;
|
||||
GroupType m_type;
|
||||
const bool m_interactive;
|
||||
|
||||
QtRoundedRectItem* m_background = nullptr;
|
||||
QGraphicsRectItem* m_backgroundTopRight = nullptr;
|
||||
QGraphicsRectItem* m_backgroundBottomLeft = nullptr;
|
||||
QGraphicsPolygonItem* m_background = nullptr;
|
||||
};
|
||||
|
||||
#endif // QT_GRAPH_NODE_GROUP_H
|
||||
|
||||
Reference in New Issue
Block a user