Skip to content

Commit

Permalink
DYN-6123 Fix groups loose associations with notes and nested groups w…
Browse files Browse the repository at this point in the history
…hen a custom node is created (#14220)

* Fix note in group in customnode

* add test

* merge test from other PR
  • Loading branch information
zeusongit authored Aug 4, 2023
1 parent 9947ba9 commit 5a74097
Show file tree
Hide file tree
Showing 5 changed files with 605 additions and 37 deletions.
9 changes: 8 additions & 1 deletion src/DynamoCore/Core/CustomNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,14 @@ internal CustomNodeWorkspaceModel Collapse(
currentWorkspace.RemoveGroup(group);

group.GUID = Guid.NewGuid();
group.Nodes = group.DeletedModelBases;
group.Nodes = group.Nodes.Concat(group.DeletedModelBases);
//for nested groups
//if any of the previously added annotations has a DeletedModelBases with the same group as the current one, then add it to the Nodes
var nestedGroup = newAnnotations.FirstOrDefault(x => x.DeletedModelBases.OfType<AnnotationModel>().Any(y => y.GUID == group.GUID));
if (nestedGroup != null)
{
nestedGroup.Nodes = nestedGroup.Nodes.Append(group);
}
newAnnotations.Add(group);
}

Expand Down
47 changes: 26 additions & 21 deletions src/DynamoCoreWpf/ViewModels/Core/AnnotationViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class AnnotationViewModel : ViewModelBase
private AnnotationModel annotationModel;
private IEnumerable<PortModel> originalInPorts;
private IEnumerable<PortModel> originalOutPorts;
private Dictionary<Guid, int> GroupIdToCutGeometryIndex = new Dictionary<Guid, int>();
private Dictionary<Guid, Geometry> GroupIdToCutGeometry = new Dictionary<Guid, Geometry>();
// vertical offset accounts for the port margins
private const int verticalOffset = 20;
private const int portVerticalMidPoint = 17;
Expand Down Expand Up @@ -265,7 +265,7 @@ public bool IsExpanded
OutPorts.Clear();
if (value)
{
this.ShowGroupContents();
this.ShowGroupContents();
}
else
{
Expand Down Expand Up @@ -577,7 +577,8 @@ private void DissolveNestedGroups(object parameters)
var nodes = GetAllHostedNodes(hostedAnnotations);
DynamoSelection.Instance.ClearSelection();

foreach (var annotation in hostedAnnotations){
foreach (var annotation in hostedAnnotations)
{
var annotationGuid = annotation.GUID;
this.WorkspaceViewModel.DynamoViewModel.ExecuteCommand(
new DynamoModel.SelectModelCommand(annotationGuid, Keyboard.Modifiers.AsDynamoType()));
Expand Down Expand Up @@ -671,7 +672,7 @@ public AnnotationViewModel(WorkspaceViewModel workspaceViewModel, AnnotationMode
groupStyleList = new ObservableCollection<Configuration.StyleItem>();
//This will add the GroupStyles created in Preferences panel to the Group Style Context menu.
LoadGroupStylesFromPreferences(preferenceSettings.GroupStyleItemsList);
}
}


/// <summary>
Expand Down Expand Up @@ -988,7 +989,7 @@ private void RedrawConnectors()
.SelectMany(x => x.Nodes.OfType<NodeModel>())
.Concat(this.Nodes.OfType<NodeModel>());

foreach (var connector in allNodes.SelectMany(x=>x.AllConnectors))
foreach (var connector in allNodes.SelectMany(x => x.AllConnectors))
{
var connectorViewModel = WorkspaceViewModel
.Connectors
Expand Down Expand Up @@ -1016,7 +1017,7 @@ internal void ShowGroupContents()
if (viewModel is AnnotationViewModel annotationViewModel)
{
// Update connectors and ports if the nested group is not collapsed
if(annotationViewModel.Nodes.Any() && !annotationViewModel.IsCollapsed)
if (annotationViewModel.Nodes.Any() && !annotationViewModel.IsCollapsed)
{
UpdateConnectorsAndPortsOnShowContents(annotationViewModel.Nodes);
}
Expand Down Expand Up @@ -1240,7 +1241,7 @@ private void UpdateAllGroupedGroups()
private void HandleNodesCollectionChanges()
{
var allGroupedGroups = Nodes.OfType<AnnotationModel>();
var removedFromGroup = GroupIdToCutGeometryIndex.Keys
var removedFromGroup = GroupIdToCutGeometry.Keys
.ToList()
.Except(allGroupedGroups.Select(x => x.GUID));

Expand All @@ -1253,7 +1254,7 @@ private void HandleNodesCollectionChanges()

var addedToGroup = allGroupedGroups
.Select(x => x.GUID)
.Except(GroupIdToCutGeometryIndex.Keys.ToList());
.Except(GroupIdToCutGeometry.Keys.ToList());

foreach (var key in addedToGroup)
{
Expand All @@ -1270,14 +1271,14 @@ private void HandleNodesCollectionChanges()

private void RemoveKeyFromCutGeometryDictionary(Guid groupGuid)
{
if (GroupIdToCutGeometryIndex is null ||
!GroupIdToCutGeometryIndex.ContainsKey(groupGuid))
if (GroupIdToCutGeometry is null ||
!GroupIdToCutGeometry.ContainsKey(groupGuid))
{
return;
}

NestedGroupsGeometries.RemoveAt(GroupIdToCutGeometryIndex[groupGuid]);
GroupIdToCutGeometryIndex.Remove(groupGuid);
NestedGroupsGeometries.Remove(GroupIdToCutGeometry[groupGuid]);
GroupIdToCutGeometry.Remove(groupGuid);

var groupViewModel = this.WorkspaceViewModel.Annotations
.Where(x => x.AnnotationModel.GUID == groupGuid)
Expand All @@ -1292,11 +1293,12 @@ private void RemoveKeyFromCutGeometryDictionary(Guid groupGuid)
private void AddToCutGeometryDictionary(AnnotationViewModel annotationViewModel)
{
var key = annotationViewModel.AnnotationModel.GUID;
if (GroupIdToCutGeometryIndex.ContainsKey(key)) return;
if (GroupIdToCutGeometry.ContainsKey(key)) return;

int nextPos = NestedGroupsGeometries.Count;
NestedGroupsGeometries.Insert(nextPos, CreateRectangleGeometry(annotationViewModel));
GroupIdToCutGeometryIndex[key] = nextPos;
var geo = CreateRectangleGeometry(annotationViewModel);
NestedGroupsGeometries.Insert(nextPos, geo);
GroupIdToCutGeometry[key] = geo;

annotationViewModel.PropertyChanged += GroupViewModel_PropertyChanged;
}
Expand Down Expand Up @@ -1330,16 +1332,19 @@ private void GroupViewModel_PropertyChanged(object sender, System.ComponentModel
private void UpdateGroupCutGeometry(AnnotationViewModel annotationViewModel)
{
var key = annotationViewModel.AnnotationModel.GUID;
if (GroupIdToCutGeometryIndex == null ||
!GroupIdToCutGeometryIndex.ContainsKey(key))
if (GroupIdToCutGeometry == null ||
!GroupIdToCutGeometry.ContainsKey(key))
{
return;
}
var index = GroupIdToCutGeometryIndex[key];
if (index >= 0 &&
index < NestedGroupsGeometries.Count)
var geo = GroupIdToCutGeometry[key];
if (geo != null)
{
NestedGroupsGeometries[index] = CreateRectangleGeometry(annotationViewModel);
int index = NestedGroupsGeometries.IndexOf(geo);
if (index >= 0 && index < NestedGroupsGeometries.Count)
{
NestedGroupsGeometries[index] = CreateRectangleGeometry(annotationViewModel);
}
}
}

Expand Down
37 changes: 23 additions & 14 deletions test/DynamoCoreWpfTests/AnnotationViewModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,18 @@ public void CanAddGroupToOtherGroup()

OpenModel(@"core\annotationViewModelTests\groupsTestFile.dyn");

var group1ViewModel = ViewModel.CurrentSpaceViewModel.Annotations.FirstOrDefault(x=>x.AnnotationText == group1Name);
var group2ViewModel = ViewModel.CurrentSpaceViewModel.Annotations.FirstOrDefault(x=>x.AnnotationText == group2Name);
//Create 3rd group
var dummyNode = new DummyNode();
var command = new DynamoModel.CreateNodeCommand(dummyNode, 0, 0, true, false);
ViewModel.Model.ExecuteCommand(command);

ViewModel.ExecuteCommand(
new DynamoModel.SelectModelCommand(dummyNode.GUID, Keyboard.Modifiers.AsDynamoType()));
ViewModel.AddAnnotationCommand.Execute(null);

var group1ViewModel = ViewModel.CurrentSpaceViewModel.Annotations.FirstOrDefault(x => x.AnnotationText == group1Name);
var group2ViewModel = ViewModel.CurrentSpaceViewModel.Annotations.FirstOrDefault(x => x.AnnotationText == group2Name);
var group3ViewModel = ViewModel.CurrentSpaceViewModel.Annotations.FirstOrDefault(x => x.AnnotationText != group2Name && x.AnnotationText != group1Name);

var group1ContentBefore = group1ViewModel.Nodes.ToList();

Expand All @@ -925,36 +935,35 @@ public void CanAddGroupToOtherGroup()
var modelGuids = new List<Guid>
{
group1ViewModel.AnnotationModel.GUID,
group2ViewModel.AnnotationModel.GUID
group2ViewModel.AnnotationModel.GUID,
group3ViewModel.AnnotationModel.GUID
};

ViewModel.ExecuteCommand(
new DynamoModel.SelectModelCommand(modelGuids, Keyboard.Modifiers.AsDynamoType()));

Assert.That(
DynamoSelection.Instance.Selection.Contains(group1ViewModel.AnnotationModel) &&
DynamoSelection.Instance.Selection.Contains(group2ViewModel.AnnotationModel)
);

//Assert HasUnsavedChanges is false
Assert.AreEqual(false, ViewModel.CurrentSpaceViewModel.HasUnsavedChanges);
DynamoSelection.Instance.Selection.Contains(group2ViewModel.AnnotationModel) &&
DynamoSelection.Instance.Selection.Contains(group3ViewModel.AnnotationModel)
);

group1ViewModel.AddGroupToGroupCommand.Execute(null);

// Assert
Assert.That(group1ContentBefore.Count != group1ViewModel.Nodes.Count());
Assert.That(group1ViewModel.Nodes.Contains(group2ViewModel.AnnotationModel));
Assert.That(group1ViewModel.Nodes.Contains(group3ViewModel.AnnotationModel));

//Assert HasUnsavedChanges is true
Assert.AreEqual(true, ViewModel.CurrentSpaceViewModel.HasUnsavedChanges);

ViewModel.CurrentSpaceViewModel.Save(ViewModel.CurrentSpaceViewModel.FileName);

//Assert HasUnsavedChanges is false
Assert.AreEqual(false, ViewModel.CurrentSpaceViewModel.HasUnsavedChanges);
Assert.That(ViewModel.CurrentSpaceViewModel.HasUnsavedChanges);

ViewModel.CurrentSpace.Undo();

Assert.That(group1ContentBefore.Count == group1ViewModel.Nodes.Count());
Assert.That(!group1ViewModel.Nodes.Contains(group2ViewModel.AnnotationModel));
Assert.That(!group1ViewModel.Nodes.Contains(group3ViewModel.AnnotationModel));

//Assert HasUnsavedChanges is true
Assert.AreEqual(true, ViewModel.CurrentSpaceViewModel.HasUnsavedChanges);
}
Expand Down
59 changes: 58 additions & 1 deletion test/DynamoCoreWpfTests/CustomNodeTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Linq;
using System.IO;
using System.Linq;
using System.Windows.Annotations;
using CoreNodeModels.Input;
using Dynamo.Graph.Annotations;
using Dynamo.Graph.Nodes;
using Dynamo.Graph.Notes;
using Dynamo.Models;
Expand Down Expand Up @@ -37,5 +40,59 @@ public void TestNewNodeFromSelectionCommandState()

Assert.IsFalse(ViewModel.CurrentSpaceViewModel.NodeFromSelectionCommand.CanExecute(null));
}

[Test]
public void TestNestedGroupsOnCustomNodes()
{
string openPath = Path.Combine(TestDirectory, @"core\collapse\collapse-group.dyn");
OpenModel(openPath);

foreach (var node in ViewModel.CurrentSpaceViewModel.Nodes)
{
DynamoSelection.Instance.Selection.Add(node.NodeModel);
}
foreach (var note in ViewModel.CurrentSpaceViewModel.Notes)
{
DynamoSelection.Instance.Selection.Add(note.Model);
}
foreach (var grp in ViewModel.CurrentSpaceViewModel.Annotations)
{
DynamoSelection.Instance.Selection.Add(grp.AnnotationModel);
}

//assert that everything is selected
var groupsSelected = DynamoSelection.Instance.Selection.OfType<AnnotationModel>().Count();
var nodesSelected = DynamoSelection.Instance.Selection.OfType<NodeModel>().Count();
var notesSelected = DynamoSelection.Instance.Selection.OfType<NoteModel>().Count();
Assert.AreEqual(ViewModel.CurrentSpaceViewModel.Annotations.Count(), groupsSelected); // 3 groups
Assert.AreEqual(ViewModel.CurrentSpaceViewModel.Nodes.Count(), nodesSelected); //6 nodes
Assert.AreEqual(ViewModel.CurrentSpaceViewModel.Notes.Count(), notesSelected); // 2 notes

var ws = ViewModel.Model.CustomNodeManager.Collapse(
DynamoSelection.Instance.Selection.OfType<NodeModel>(),
DynamoSelection.Instance.Selection.OfType<NoteModel>(),
ViewModel.Model.CurrentWorkspace,
true,
new FunctionNamePromptEventArgs
{
Category = "Testing",
Description = "",
Name = "__CollapseTest3__",
Success = true
});

ViewModel.Model.AddCustomNodeWorkspace(ws);
ViewModel.Model.OpenCustomNodeWorkspace(ws.CustomNodeId);
var customNodeWorkspace = ViewModel.Model.CurrentWorkspace;

Assert.AreEqual(groupsSelected, customNodeWorkspace.Annotations.Count());
Assert.AreEqual(nodesSelected, customNodeWorkspace.Nodes.Count() - 1); //Subtract 1 for the Output Node
Assert.AreEqual(notesSelected, customNodeWorkspace.Notes.Count());

//assert that note and groups are still associated
var maingroup = customNodeWorkspace.Annotations.First(x => x.AnnotationText.Equals("Test"));
Assert.AreEqual(2, maingroup.Nodes.OfType<AnnotationModel>().Count()); // 2 groups inside the main group
Assert.AreEqual(1, maingroup.Nodes.OfType<NoteModel>().Count()); // 1 note inside the main group
}
}
}
Loading

0 comments on commit 5a74097

Please sign in to comment.