Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove InPortData and OutPortData #7301

Merged
merged 19 commits into from
Nov 5, 2016
Merged

Conversation

ikeough
Copy link
Contributor

@ikeough ikeough commented Oct 26, 2016

Purpose

This PR represents a substantial refactoring of ports and connectors.

This PR removes the InPortData and OutPortData collections on NodeModel. These collections pre-date the InPorts and OutPorts collections, and were previously deprecated. They acted as a way to store initialization data for ports during the construction of the node, with the assumption that at some point after they were filled, NodeModel.RegisterAllPorts would be called, subsequently creating/updating ports on the nodes. This indirection was not obvious or useful and led to the InportData and OutportData collections getting out of sync with the InPorts and OutPorts collections.

In the beginning, collections in Dynamo were not observable, so we created a lot of events like NodeModel.PortConnected and NodeModel.ConnectorConnected when ports and connectors were added. As we have moved to using observable collections, it's much easier to deal with the creation and deletion of ports, connectors, nodes, etc., by simply handling the collection changed events for those collections and doing the right thing. This PR gets us part of the way towards a fully observable methodology by adjusting NodeModel to watch the collection changed events for the InPorts and OutPorts collections, and consolidating logic previously spread among numerous event handlers into those collection change handlers.

Additionally, this PR removes a number of methods which seemed like a good idea three years ago, but now only add confusion. For example. PortModel.Connect was a very thin wrapper around PortModel.Connectors.Add(someNewConnector). These thin wrappers have been removed except in cases where the wrapper contained some assertion logic.

Declarations

Check these if you believe they are true

  • The code base is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI. (In progress)
  • Snapshot of UI changes, if any.
  • Follows Semantic Versioning standards (No change of public methods or types etc..)

Reviewers

@mjkkirschner

@ikeough ikeough changed the title Remove InPortData and OutPortData (WIP) Remove InPortData and OutPortData Oct 26, 2016
@ramramps
Copy link
Collaborator

@ikeough DynamoStorage is using node.inportdata.
image

@ikeough
Copy link
Contributor Author

ikeough commented Oct 28, 2016

@ramramps Thanks! I'll fix that.

@@ -895,6 +876,15 @@ protected NodeModel()
ArgumentLacing = LacingStrategy.Disabled;

RaisesModificationEvents = true;

InPorts.CollectionChanged += PortsCollectionChanged;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these handlers should be removed in the dispose method right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes. Nice catch @mjkkirschner.

private void PortsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
ValidateConnections();
ConfigureSnapEdges(sender == InPorts?InPorts : OutPorts);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sender will be a collection? not the modified element?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The CollectionChanged event's sender is the collection. You can get at the elements that have been changed by using the NotifyCollectionChangedEventArgs.

@@ -268,8 +268,8 @@ void _port_PropertyChanged(object sender, System.ComponentModel.PropertyChangedE
case "Center":
RaisePropertyChanged("Center");
break;
case "DefaultValueEnabled":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what was the reason to get rid of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DefaultValueEnabled was removed on the NodeModel, so the change event can be removed here. The property was removed from NodeModel in favor of using the more precise DefaultValue == null.

InPortData.Add(new PortData("reductor", Resources.ReducePortDataReductorToolTip));
InPortData.Add(new PortData("seed", Resources.ReducePortDataSeedToolTip));
InPortData.Add(new PortData("list1", Resources.PortDataListToolTip + " #1"));
InPorts.Add(new PortModel(PortType.Input, this, new PortData("reductor", Resources.ReducePortDataReductorToolTip)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious... what happens when a zero touch node author adds a PortModel of type Output to the InPortscollection... do we crash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing. This design is not great and needs to be cleaned up, but I didn't want to do it as part of this PR. We should remove PortType because it doesn't have any real meaning. Whether a port is an "input" or an "output" can be determined by whether it's in the InPorts or the OutPorts collections respectively.

@@ -116,35 +116,6 @@ protected override void DeserializeCore(XmlElement nodeElement, SaveContext cont
.Select(subNode => subNode.Attributes[0].Value)
.Last();
}

//public override Value Evaluate(FSharpList<Value> args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😉

@mjkkirschner
Copy link
Member

mjkkirschner commented Oct 31, 2016

@ikeough this looks good to me. I have a few questions though, see some of the comments, also, does this effectively break all nodeModelnodes made by third parties, or any other others up until now. For example, the Dynamo Samples repo will need to be updated and Revit UI nodes?

Is there any work necessary for zero touch node authors?

@ikeough ikeough changed the title (WIP) Remove InPortData and OutPortData Remove InPortData and OutPortData Nov 1, 2016
@ikeough
Copy link
Contributor Author

ikeough commented Nov 1, 2016

@mjkkirschner Yes. This will break third party nodes, the samples, and Revit. That is why this is a 2.0 change. Fortunately, the InportData and OutportData collections have been marked as deprecated for several versions.

- Remove Connect and Disconnect methods in favor of allowing connectors to be added to the Connectors collection.
- Consolidate port connect and disconnect handling logic into collection changed handlers.
- Remove methods on NodeModel which allow finding whether a port is connected by index, in favor of one method on PortModel, IsConnected.
- Fix collapse logic on custom node manager.
@@ -50,7 +50,7 @@ public class CustomNodeDefinition : IFunctionDescriptor
if (outputs.Any())
{
topMost.AddRange(
outputs.Where(x => x.HasInput(0)).Select(x => Tuple.Create(0, x as NodeModel)));
outputs.Where(x => x.InPorts[0].IsConnected).Select(x => Tuple.Create(0, x as NodeModel)));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: NodeModel.HasInput(...) has been removed. Use PortModel.IsConnected instead.

@@ -767,7 +771,7 @@ internal bool TryGetNodeInfo(string name, out CustomNodeInfo info)
selectedNodeSet.SelectMany(
node =>
Enumerable.Range(0, node.InPorts.Count)
.Where(node.HasConnectedInput)
.Where(index=>node.InPorts[index].Connectors.Any())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use the PortModel.IsConnected method here because that assumes default values as part of connection. Here we really want to know if the port has any connectors, so we use the more idiomatic Connectors.Any()

/// without raising port disconnection events.</param>
internal void Delete(bool silent = false)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The silent parameter was never used.

var inputs = Definition.DisplayParameters.Zip(Definition.Parameters, (dp, p) => Tuple.Create(dp, p.Description, p.DefaultValue));
foreach (var p in inputs)
model.InPortData.Add(new PortData(p.Item1, p.Item2, p.Item3));
var inputs = Definition.DisplayParameters.Zip(Definition.Parameters, (dp, p) => Tuple.Create(dp, p.Description, p.DefaultValue)).ToList();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following logic originally lived on NodeModel in RegisterOutputs(). We move it here for custom nodes so that their ports are not deleted when the underlying function definition changes, but the ports are updated.

@@ -1281,28 +1284,28 @@ public void SelectNeighbors()
/// Sets the <seealso cref="ElementState"/> for the node based on
/// the port's default value status and connectivity.
/// </summary>
public void ValidateConnections()
Copy link
Contributor Author

@ikeough ikeough Nov 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: NodeModel.ValidateConnections() has been removed.

@@ -1387,35 +1390,12 @@ internal double GetPortVerticalOffset(PortModel portModel)
/// Reads inputs list and adds ports for each input.
/// </summary>
[Obsolete("RegisterInputPorts is deprecated, please use the InPortNamesAttribute, InPortDescriptionsAttribute, and InPortTypesAttribute instead.")]
public void RegisterInputPorts()
public void RegisterInputPorts(IEnumerable<PortData> portDatas)
Copy link
Contributor Author

@ikeough ikeough Nov 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: NodeModel.RegisterInputPorts() is now NodeModel.RegisterInputPorts(IEnumerable<PortData> portDatas)

}

/// <summary>
/// Reads outputs list and adds ports for each output
/// </summary>
[Obsolete("RegisterOutputPorts is deprecated, please use the OutPortNamesAttribute, OutPortDescriptionsAttribute, and OutPortTypesAttribute instead.")]
public void RegisterOutputPorts()
public void RegisterOutputPorts(IEnumerable<PortData> portDatas)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: NodeModel.RegisterOutputPorts() is now NodeModel.RegisterOutputPorts(IEnumerable<PortData> portDatas)

@@ -1603,7 +1559,7 @@ public void RegisterAllPorts()
/// <param name="data"></param>
/// <param name="index"></param>
/// <returns></returns>
public PortModel AddPort(PortType portType, PortData data, int index)
private PortModel AddPort(PortType portType, PortData data, int index)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: NodeModel.AddPort(...) has been removed. Ports can now be added using NodeModel.InPorts.Add(...)

/// A <see cref="PortData"/> object used for the construction of the node.
/// </summary>
[JsonIgnore]
public PortData Data { get { return portData; } }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: The PortModel.Data property has been removed.

}

/// <summary>
/// Tooltip of the port.
/// </summary>
[JsonProperty("Description")]
public string ToolTipContent
public string ToolTip
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: The PortModel.ToolTipContent property is now PortModel.ToolTip.

/// Controls whether the Use Default Value option is available.
/// </summary>
[JsonIgnore]
public bool DefaultValueEnabled
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: PortModel.DefaultValueEnabled has been removed. Please use PortModel.DefaultValue == null to check whether a port has a default value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got one concern here and this is a lot of zt node authors desire to actually use null as a default value... maybe that design decision is out of scope for this PR and this won't actually change the behavior (I dont think it will) just wanted to mention it.

/// Returns true if the port has connectors or if the
/// default value is enabled and not null. Otherwise, returns false.
/// </summary>
internal bool IsConnected
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: PortModel.IsConnected property is added. This property replaces functionality previously contained in the NodeModel.HasInput and NodeModel.HasConnectedInput properties.

/// </summary>
[Obsolete("Please use NodeModel.HasConnectedInput instead.")]
[JsonIgnore]
public bool IsConnected
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: Obsolete PortModel.IsConnected property has been removed.

@@ -106,18 +106,6 @@ public DelegateCommand ViewCustomNodeWorkspaceCommand
}
}

public DelegateCommand ValidateConnectionsCommand
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API Change: NodeCommands.ValidateConnectionsCommand has been removed.

@ikeough
Copy link
Contributor Author

ikeough commented Nov 3, 2016

@mjkkirschner ping. Ready for another round. Call me to chat if you want to know more about some of these refactors.

{
foreach (UIElement e in inputGrid.Children)
{
if (enabledDict.ContainsKey(e))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did anything use this dictionary?

@mjkkirschner
Copy link
Member

@ikeough this looks pretty good to me.

@mjkkirschner
Copy link
Member

:shipit:

@ikeough ikeough merged commit afe5b10 into DynamoDS:master Nov 5, 2016
@ikeough ikeough deleted the PortDataRemoval branch November 5, 2016 19:07
@mjkkirschner
Copy link
Member

because this change will effect our internal libraries and many external ones, should we create an issue to track public documentation / update notes on this change and what internal repos still need to be updated?

@ikeough
Copy link
Contributor Author

ikeough commented Nov 5, 2016

@mjkkirschner I'll make a project for it :)

@ikeough
Copy link
Contributor Author

ikeough commented Nov 5, 2016

Project added: https://github.com/DynamoDS/Dynamo/projects/3. I'll tackle these in short order.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants