diff --git a/TuneUp/TuneUpWindowViewModel.cs b/TuneUp/TuneUpWindowViewModel.cs index 56ff898..24db23e 100644 --- a/TuneUp/TuneUpWindowViewModel.cs +++ b/TuneUp/TuneUpWindowViewModel.cs @@ -327,18 +327,22 @@ internal void ResetProfiledNodes() // Create a profiled node for each AnnotationModel foreach (var group in CurrentWorkspace.Annotations) { - var pGroup = new ProfiledNodeViewModel(group); - ProfiledNodesNotExecuted.Add(pGroup); - groupDictionary[pGroup.NodeGUID] = (pGroup); - groupModelDictionary[group.GUID] = new List { pGroup }; + // Initialize an empty entry for each group in groupModelDictionary + groupModelDictionary[group.GUID] = new List (); - var groupedNodeGUIDs = group.Nodes.OfType().Select(n => n.GUID); - - foreach (var nodeGuid in groupedNodeGUIDs) + // Only create and add groups to ProfiledNodesNotExecuted if they contain NodeModel instances + if (group.Nodes.Any(n => n is NodeModel)) { - if (nodeDictionary.TryGetValue(nodeGuid, out var pNode)) + var pGroup = CreateAndRegisterGroupNode(group, ProfiledNodesNotExecuted); + + var groupedNodeGUIDs = group.Nodes.OfType().Select(n => n.GUID); + + foreach (var nodeGuid in groupedNodeGUIDs) { - ApplyGroupPropertiesAndRegisterNode(pNode, pGroup); + if (nodeDictionary.TryGetValue(nodeGuid, out var pNode)) + { + ApplyGroupPropertiesAndRegisterNode(pNode, pGroup); + } } } } @@ -542,11 +546,7 @@ private void CalculateGroupNodes() } // create new group node - var pGroup = new ProfiledNodeViewModel(pNode); - - groupDictionary[pGroup.NodeGUID] = pGroup; - groupModelDictionary[pNode.GroupGUID].Add(pGroup); - + var pGroup = CreateAndRegisterGroupNode(pNode); uiContext.Send(_ => ProfiledNodesNotExecuted.Add(pGroup), null); } } @@ -589,17 +589,12 @@ private void CreateGroupNodesForCollection(ObservableCollection n.GUID.Equals(pNode.GroupGUID)) - }; + var pGroup = CreateAndRegisterGroupNode(pNode); + pGroup.GroupExecutionOrderNumber = executionCounter++; + pGroup.GroupExecutionMilliseconds = groupExecTime; + pGroup.GroupModel = CurrentWorkspace.Annotations.First(n => n.GUID.Equals(pNode.GroupGUID)); collection.Add(pGroup); - groupDictionary[pGroup.NodeGUID] = pGroup; - groupModelDictionary[pNode.GroupGUID].Add(pGroup); - // Create an register a new time node var timeNode = CreateAndRegisterGroupTimeNode(pGroup); collection.Add(timeNode); @@ -699,20 +694,19 @@ internal void OnGroupPropertyChanged(object sender, PropertyChangedEventArgs e) } } + // Detect change of nodes if (e.PropertyName == nameof(groupModel.Nodes)) { - var allNodesInGroup = groupModelDictionary[groupModel.GUID]; - var modelNodeGuids = groupModel.Nodes .OfType() .Select(n => n.GUID) .ToHashSet(); // Determine if we adding or removing a node - var pNodeToRemove = allNodesInGroup + var pNodeToRemove = nodesInGroup .FirstOrDefault(n => !n.IsGroup && !n.IsGroupExecutionTime && !modelNodeGuids.Contains(n.NodeGUID)); - - var pNodeToAdd = nodeDictionary.FirstOrDefault(kvp => modelNodeGuids.Contains(kvp.Key) && !allNodesInGroup.Contains(kvp.Value)).Value; + var pNodeToAdd = nodeDictionary + .FirstOrDefault(kvp => modelNodeGuids.Contains(kvp.Key) && !nodesInGroup.Contains(kvp.Value)).Value; var (pNodeModified, addNode) = pNodeToRemove == null ? (pNodeToAdd, true) : (pNodeToRemove, false); @@ -723,7 +717,7 @@ internal void OnGroupPropertyChanged(object sender, PropertyChangedEventArgs e) collection = GetObservableCollectionFromState(state); // Get all nodes for this group in the same state - var allNodesInGroupForState = allNodesInGroup.Where(n => n.State == state).ToList(); + var allNodesInGroupForState = nodesInGroup.Where(n => n.State == state).ToList(); var pGroupToModify = allNodesInGroupForState.FirstOrDefault(n => n.IsGroup); var timeNodeToModify = allNodesInGroupForState.FirstOrDefault(n => n.IsGroupExecutionTime); var pNodesOfSameState = allNodesInGroupForState.Where(n => !n.IsGroupExecutionTime && !n.IsGroup).ToList(); @@ -734,9 +728,16 @@ internal void OnGroupPropertyChanged(object sender, PropertyChangedEventArgs e) ResetGroupPropertiesAndUnregisterNode(pNodeModified); pNodesOfSameState.Remove(pNodeModified); - // Update group execution time - if (state != ProfiledNodeState.NotExecuted && pGroupToModify != null && timeNodeToModify != null) + // check if there are any nodes left of the same state + if (!pNodesOfSameState.Any()) + { + // remove the group node and time node from the collection + collection.Remove(pGroupToModify); + collection.Remove(timeNodeToModify); + } + else if (state != ProfiledNodeState.NotExecuted && pGroupToModify != null && timeNodeToModify != null) { + // Update group execution time pGroupToModify.GroupExecutionMilliseconds -= pNodeModified.ExecutionMilliseconds; pGroupToModify.ExecutionMilliseconds = pGroupToModify.GroupExecutionMilliseconds; timeNodeToModify.GroupExecutionMilliseconds = pGroupToModify.GroupExecutionMilliseconds; @@ -749,15 +750,10 @@ internal void OnGroupPropertyChanged(object sender, PropertyChangedEventArgs e) // Create a new group node if it doesn't exist for this state if (pGroupToModify == null) { - pGroupToModify = new ProfiledNodeViewModel(groupModel) { State = state }; - collection.Add(pGroupToModify); - groupDictionary[pGroupToModify.NodeGUID] = pGroupToModify; - groupModelDictionary[groupModel.GUID].Add(pGroupToModify); + pGroupToModify = CreateAndRegisterGroupNode(groupModel, collection); + pGroupToModify.State = state; - if (timeNodeToModify == null) - { - timeNodeToModify = CreateAndRegisterGroupTimeNode(pGroupToModify); - } + timeNodeToModify ??= CreateAndRegisterGroupTimeNode(pGroupToModify); } ApplyGroupPropertiesAndRegisterNode(pNodeModified, pGroupToModify); @@ -798,6 +794,7 @@ internal void OnGroupPropertyChanged(object sender, PropertyChangedEventArgs e) if (collection != null) { SortCollectionViewForProfiledNodesCollection(collection); + UpdateTableVisibility(); } } } @@ -907,10 +904,8 @@ private void CurrentWorkspaceModel_GroupAdded(AnnotationModel group) var collection = GetObservableCollectionFromState(state); // Create and log new group node - var pGroup = new ProfiledNodeViewModel(group) { State = state }; - groupModelDictionary[groupGUID].Add(pGroup); - groupDictionary[pGroup.NodeGUID] = pGroup; - collection.Add(pGroup); + var pGroup = CreateAndRegisterGroupNode(group, collection); + pGroup.State = state; // Accumulate execution times and create a time node if (collection != ProfiledNodesNotExecuted) @@ -1103,6 +1098,35 @@ private ProfiledNodeViewModel CreateAndRegisterGroupTimeNode(ProfiledNodeViewMod return timeNode; } + /// + /// Creates and registers a group node for an AnnotationModel. + /// Adds it to the specified collection and dictionaries. + /// + private ProfiledNodeViewModel CreateAndRegisterGroupNode( + AnnotationModel groupModel, + ObservableCollection collection) + { + var pGroup = new ProfiledNodeViewModel(groupModel); + collection.Add(pGroup); + groupDictionary[pGroup.NodeGUID] = pGroup; + groupModelDictionary[groupModel.GUID].Add(pGroup); + + return pGroup; + } + + /// + /// Creates and registers a group node based on an existing ProfiledNodeViewModel. + /// Adding it to group-related dictionaries. + /// + private ProfiledNodeViewModel CreateAndRegisterGroupNode(ProfiledNodeViewModel pNode) + { + var pGroup = new ProfiledNodeViewModel(pNode); + groupDictionary[pGroup.NodeGUID] = pGroup; + groupModelDictionary[pNode.GroupGUID].Add(pGroup); + + return pGroup; + } + /// /// Returns the appropriate ObservableCollection based on the node's profiling state. ///