diff --git a/doc/distrib/NodeHelpFiles/DSCore.List.IndexOf_img.jpg b/doc/distrib/NodeHelpFiles/DSCore.List.IndexOf_img.jpg index 335f8615fe4..149d623b394 100644 Binary files a/doc/distrib/NodeHelpFiles/DSCore.List.IndexOf_img.jpg and b/doc/distrib/NodeHelpFiles/DSCore.List.IndexOf_img.jpg differ diff --git a/src/DocumentationBrowserViewExtension/NodeDocumentationHtmlGenerator.cs b/src/DocumentationBrowserViewExtension/NodeDocumentationHtmlGenerator.cs index b60426ba4f0..b1eaf43bac9 100644 --- a/src/DocumentationBrowserViewExtension/NodeDocumentationHtmlGenerator.cs +++ b/src/DocumentationBrowserViewExtension/NodeDocumentationHtmlGenerator.cs @@ -315,7 +315,8 @@ private static string GetDefaultValueFromDescription(string element) { if (line.ToLowerInvariant().Contains(Resources.InputDefaultValue)) { - return line.Remove(0, 16); + var index = line.IndexOf(":"); + return line.Remove(0, index + 1); } } return string.Empty; diff --git a/src/DynamoCore/Logging/DynamoAnalyticsClient.cs b/src/DynamoCore/Logging/DynamoAnalyticsClient.cs index 37ecab06c98..98138164e73 100644 --- a/src/DynamoCore/Logging/DynamoAnalyticsClient.cs +++ b/src/DynamoCore/Logging/DynamoAnalyticsClient.cs @@ -124,7 +124,7 @@ public DynamoAnalyticsClient(HostAnalyticsInfo hostAnalyticsInfo) Session.Start(); var hostName = string.IsNullOrEmpty(hostAnalyticsInfo.HostName) ? Configurations.DynamoAsString : hostAnalyticsInfo.HostName; - var appversion = hostAnalyticsInfo.HostVersion != null ? hostAnalyticsInfo.HostVersion.ToString() : string.Empty; + var appversion = hostAnalyticsInfo.HostVersion?.ToString(); hostInfo = new HostContextInfo() { ParentId = hostAnalyticsInfo.ParentId, SessionId = hostAnalyticsInfo.SessionId }; diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index e233387a79f..9ac8028a741 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -98,10 +98,14 @@ public static DynamoPreferencesData Default() /// public struct HostAnalyticsInfo { - // Dynamo variation identified by host. + // Dynamo variation identified by host, e.g. Dynamo Revit public string HostName; // Dynamo variation version specific to host public Version HostVersion; + // Dynamo host application name, e.g. Revit + public string HostProductName; + // Dynamo host application version, e.g. 2025.2.0 + public Version HostProductVersion; // Dynamo host parent id for analytics purpose. public string ParentId; // Dynamo host session id for analytics purpose. @@ -2946,6 +2950,26 @@ public bool OpenCustomNodeWorkspace(Guid guid) return false; } + /// + /// Opens an existing custom node workspace. + /// + /// Identifier of the workspace to open + /// True if workspace was found and open + internal bool OpenCustomNodeWorkspaceSilent(Guid guid) + { + CustomNodeWorkspaceModel customNodeWorkspace; + if (CustomNodeManager.TryGetFunctionWorkspace(guid, IsTestMode, out customNodeWorkspace)) + { + if (!Workspaces.OfType().Contains(customNodeWorkspace)) + { + AddWorkspace(customNodeWorkspace); + } + + return true; + } + + return false; + } /// /// Adds a node to the current workspace. diff --git a/src/DynamoCore/PublicAPI.Unshipped.txt b/src/DynamoCore/PublicAPI.Unshipped.txt index bb9716fd6e0..f7ecb28e9be 100644 --- a/src/DynamoCore/PublicAPI.Unshipped.txt +++ b/src/DynamoCore/PublicAPI.Unshipped.txt @@ -2041,6 +2041,8 @@ Dynamo.Models.EvaluationCompletedEventArgs.EvaluationSucceeded.get -> bool Dynamo.Models.EvaluationCompletedEventArgs.EvaluationTookPlace.get -> bool Dynamo.Models.HostAnalyticsInfo Dynamo.Models.HostAnalyticsInfo.HostAnalyticsInfo() -> void +Dynamo.Models.HostAnalyticsInfo.HostProductName -> string +Dynamo.Models.HostAnalyticsInfo.HostProductVersion -> System.Version Dynamo.Models.HostAnalyticsInfo.HostName -> string Dynamo.Models.HostAnalyticsInfo.HostVersion -> System.Version Dynamo.Models.HostAnalyticsInfo.ParentId -> string diff --git a/src/DynamoCoreWpf/Commands/WorkspaceCommands.cs b/src/DynamoCoreWpf/Commands/WorkspaceCommands.cs index cb402539e11..b15c1194291 100644 --- a/src/DynamoCoreWpf/Commands/WorkspaceCommands.cs +++ b/src/DynamoCoreWpf/Commands/WorkspaceCommands.cs @@ -328,6 +328,17 @@ public bool HasSelection get { return DynamoSelection.Instance.Selection.Count > 0; } } + [JsonIgnore] + public bool CanUpdatePythonEngine + { + get { return DynamoViewModel.CanUpdatePythonNodeEngine(null); } + } + [JsonIgnore] + public bool CanUpdateAllPythonEngine + { + get { return DynamoViewModel.CanUpdateAllPythonEngine(null); } + } + [JsonIgnore] public bool IsGeometryOperationEnabled { diff --git a/src/DynamoCoreWpf/Properties/Resources.Designer.cs b/src/DynamoCoreWpf/Properties/Resources.Designer.cs index 37a97fb1fb5..141cc6e0fd4 100644 --- a/src/DynamoCoreWpf/Properties/Resources.Designer.cs +++ b/src/DynamoCoreWpf/Properties/Resources.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -10557,5 +10557,38 @@ public static string ZoomLevel { return ResourceManager.GetString("ZoomLevel", resourceCulture); } } + + /// + /// Looks up a localized string similar to Update all {0} python nodes in the current workspace to use {1} engine?. + /// + public static string UpdateAllPythonEngineWarning + { + get + { + return ResourceManager.GetString("UpdateAllPythonEngineWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Update All Python Nodes. + /// + public static string UpdateAllPythonEngineWarningTitle + { + get + { + return ResourceManager.GetString("UpdateAllPythonEngineWarningTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Set Python Engine. + /// + public static string UpdateAllPythonEngineMainMenuHeader + { + get + { + return ResourceManager.GetString("UpdateAllPythonEngineMainMenuHeader", resourceCulture); + } + } } } diff --git a/src/DynamoCoreWpf/Properties/Resources.en-US.resx b/src/DynamoCoreWpf/Properties/Resources.en-US.resx index 962c0041ca9..0afa100be71 100644 --- a/src/DynamoCoreWpf/Properties/Resources.en-US.resx +++ b/src/DynamoCoreWpf/Properties/Resources.en-US.resx @@ -4025,4 +4025,13 @@ To make this file into a new template, save it to a different folder, then move Node Help Data is dumped to \"{0}\". + + Update all {0} python nodes in the current workspace to use {1} engine? + + + Update All Python Nodes + + + Set Python Engine + diff --git a/src/DynamoCoreWpf/Properties/Resources.resx b/src/DynamoCoreWpf/Properties/Resources.resx index b6262ac5efd..ff5426a0527 100644 --- a/src/DynamoCoreWpf/Properties/Resources.resx +++ b/src/DynamoCoreWpf/Properties/Resources.resx @@ -4012,4 +4012,13 @@ To make this file into a new template, save it to a different folder, then move Node Help Data is dumped to \"{0}\". + + Update all {0} python nodes in the current workspace to use {1} engine? + + + Update All Python Nodes + + + Set Python Engine + diff --git a/src/DynamoCoreWpf/PublicAPI.Unshipped.txt b/src/DynamoCoreWpf/PublicAPI.Unshipped.txt index ef105d2fb6a..22f10109f6f 100644 --- a/src/DynamoCoreWpf/PublicAPI.Unshipped.txt +++ b/src/DynamoCoreWpf/PublicAPI.Unshipped.txt @@ -2144,6 +2144,8 @@ Dynamo.ViewModels.DynamoViewModel.UngroupAnnotationCommand.get -> Dynamo.UI.Comm Dynamo.ViewModels.DynamoViewModel.UngroupAnnotationCommand.set -> void Dynamo.ViewModels.DynamoViewModel.UngroupModelCommand.get -> Dynamo.UI.Commands.DelegateCommand Dynamo.ViewModels.DynamoViewModel.UngroupModelCommand.set -> void +Dynamo.ViewModels.DynamoViewModel.UpdateAllPythonEngineCommand.get -> Dynamo.UI.Commands.DelegateCommand +Dynamo.ViewModels.DynamoViewModel.UpdateAllPythonEngineCommand.set -> void Dynamo.ViewModels.DynamoViewModel.UpdateGraphicHelpersScale(object parameter) -> void Dynamo.ViewModels.DynamoViewModel.UpdateGraphicHelpersScaleCommand.get -> Dynamo.UI.Commands.DelegateCommand Dynamo.ViewModels.DynamoViewModel.UpdateGraphicHelpersScaleCommand.set -> void @@ -2992,6 +2994,8 @@ Dynamo.ViewModels.WorkspaceViewModel.CanFindNodesFromElements.set -> void Dynamo.ViewModels.WorkspaceViewModel.CanPaste.get -> bool Dynamo.ViewModels.WorkspaceViewModel.CanRunNodeToCode.get -> bool Dynamo.ViewModels.WorkspaceViewModel.CanShowInfoBubble.get -> bool +Dynamo.ViewModels.WorkspaceViewModel.CanUpdateAllPythonEngine.get -> bool +Dynamo.ViewModels.WorkspaceViewModel.CanUpdatePythonEngine.get -> bool Dynamo.ViewModels.WorkspaceViewModel.CanZoomIn.get -> bool Dynamo.ViewModels.WorkspaceViewModel.CanZoomOut.get -> bool Dynamo.ViewModels.WorkspaceViewModel.Checksum.get -> string @@ -5492,6 +5496,9 @@ static Dynamo.Wpf.Properties.Resources.UnknowDateFormat.get -> string static Dynamo.Wpf.Properties.Resources.UnloadFailureMessageBoxTitle.get -> string static Dynamo.Wpf.Properties.Resources.UnpinNodeTooltip.get -> string static Dynamo.Wpf.Properties.Resources.UnsavedChangesMessageBoxTitle.get -> string +static Dynamo.Wpf.Properties.Resources.UpdateAllPythonEngineMainMenuHeader.get -> string +static Dynamo.Wpf.Properties.Resources.UpdateAllPythonEngineWarning.get -> string +static Dynamo.Wpf.Properties.Resources.UpdateAllPythonEngineWarningTitle.get -> string static Dynamo.Wpf.Properties.Resources.UpdateMessage.get -> string static Dynamo.Wpf.Properties.Resources.UpdateNodeIconsDebugMenu.get -> string static Dynamo.Wpf.Properties.Resources.UsageReportPromptDialogTitle.get -> string diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index fc339f9b0f9..4a401ee6e3a 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -15,6 +15,7 @@ using System.Windows.Media; using System.Windows.Threading; using Dynamo.Configuration; +using Dynamo.Controls; using Dynamo.Core; using Dynamo.Engine; using Dynamo.Exceptions; @@ -22,6 +23,7 @@ using Dynamo.Graph.Annotations; using Dynamo.Graph.Connectors; using Dynamo.Graph.Nodes; +using Dynamo.Graph.Nodes.CustomNodes; using Dynamo.Graph.Workspaces; using Dynamo.Interfaces; using Dynamo.Logging; @@ -1394,6 +1396,148 @@ private void Paste(object parameter) RaiseCanExecuteUndoRedo(); } + internal bool CanUpdatePythonNodeEngine(object parameter) + { + if (DynamoSelection.Instance.Selection.Count > 0 && SelectionHasPythonNodes()) + { + return true; + } + return false; + } + private bool SelectionHasPythonNodes() + { + if (GetSelectedPythonNodes().Any()) + { + return true; + } + return false; + } + /// + /// Updates the engine for the Python nodes, + /// if the nodes belong to another workspace (like custom nodes), they will be opened silently. + /// + /// + /// + internal void UpdatePythonNodeEngine(PythonNodeBase pythonNode, string engine) + { + try + { + var workspaceGUID = Guid.Empty; + var cnWorkspace = GetCustomNodeWorkspace(pythonNode); + if (cnWorkspace != null) + { + workspaceGUID = cnWorkspace.Guid; + FocusCustomNodeWorkspace(cnWorkspace.CustomNodeId, true); + } + this.ExecuteCommand( + new DynamoModel.UpdateModelValueCommand( + workspaceGUID, pythonNode.GUID, nameof(pythonNode.EngineName), engine)); + pythonNode.OnNodeModified(); + } + catch(Exception ex) + { + Model.Logger.Log("Failed to update Python node engine: " + ex.Message, LogLevel.Console); + } + + } + internal void UpdateAllPythonEngine(object param) + { + var pNodes = GetSelectedPythonNodes(Model.CurrentWorkspace.Nodes); + if (pNodes.Count == 0) return; + var result = MessageBoxService.Show( + Owner, + string.Format(Resources.UpdateAllPythonEngineWarning, pNodes.Count, param.ToString()), + Resources.UpdateAllPythonEngineWarningTitle, + MessageBoxButton.YesNo, + MessageBoxImage.Exclamation); + if (result == MessageBoxResult.Yes) + { + pNodes.ForEach(x => UpdatePythonNodeEngine(x, param.ToString())); + } + } + internal bool CanUpdateAllPythonEngine(object param) + { + return true; + } + + /// + /// Adds the python engine to the menu items and subscribes to their click event for updating the engine. + /// + /// List of python nodes + /// context menu item to which the engines will be added to + /// Update event handler, to trigger engine update for the node + /// Python engine to be added + /// Should be set to true, if you require to bind the passed + /// NodeModel engine value with the menu item, works only when a single node is passed in the list. + internal void AddPythonEngineToMenuItems(List pythonNodeModel, + MenuItem pythonEngineVersionMenu, + RoutedEventHandler updateEngineDelegate, + string engineName, bool isBinding = false) + { + //if all nodes in the selection are set to a specific engine, then that engine will be checked in the list. + bool hasCommonEngine = pythonNodeModel.All(x => x.EngineName == engineName); + var currentItem = pythonEngineVersionMenu.Items.Cast().FirstOrDefault(x => x.Header as string == engineName); + if (currentItem != null) + { + if (pythonNodeModel.Count == 1) return; + currentItem.IsChecked = hasCommonEngine; + return; + } + MenuItem pythonEngineItem = null; + //if single node, then checked property is bound to the engine value, as python node context menu is not recreated + if (pythonNodeModel.Count == 1 && isBinding) + { + var pythonNode = pythonNodeModel.FirstOrDefault(); ; + pythonEngineItem = new MenuItem { Header = engineName, IsCheckable = false }; + pythonEngineItem.SetBinding(MenuItem.IsCheckedProperty, new System.Windows.Data.Binding(nameof(pythonNode.EngineName)) + { + Source = pythonNode, + Converter = new CompareToParameterConverter(), + ConverterParameter = engineName + }); + } + else + { + //when updating multiple nodes checked value is not bound to any specific node, + //rather takes into account all the selected nodes + pythonEngineItem = new MenuItem { Header = engineName, IsCheckable = true }; + pythonEngineItem.IsChecked = hasCommonEngine; + } + pythonEngineItem.Click += updateEngineDelegate; + pythonEngineVersionMenu.Items.Add(pythonEngineItem); + } + /// + /// Gets the Python nodes from the provided list, including python nodes inside custom nodes as well. + /// If no list is provided then the current selection will be considered. + /// + /// + internal List GetSelectedPythonNodes(IEnumerable nodes = null) + { + if (nodes == null) + { + nodes = DynamoSelection.Instance.Selection.OfType(); + } + var selectedPythonNodes = nodes.OfType().ToList(); + var customNodes = nodes.Where(x => x.IsCustomFunction).ToList(); + if (customNodes.Count > 0) + { + foreach (var cNode in customNodes) + { + var customNodeFunction = cNode as Function; + var pythonNodesInCN = customNodeFunction?.Definition.FunctionBody.OfType().ToList(); + if (pythonNodesInCN.Count > 0) + { + selectedPythonNodes.AddRange(pythonNodesInCN); + } + } + } + return selectedPythonNodes; + } + private CustomNodeWorkspaceModel GetCustomNodeWorkspace(NodeModel node) + { + var wg = model.CustomNodeManager.LoadedWorkspaces.Where(x => x.Nodes.Contains(node)).FirstOrDefault(); + return wg ?? null; + } /// /// After command framework is implemented, this method should now be only /// called from a menu item (i.e. Ctrl + W). It should not be used as a way @@ -2567,17 +2711,18 @@ internal bool CanShowPackageManager(object parameters) } /// - /// Change the currently visible workspace to a custom node's workspace + /// Change the currently visible workspace to a custom node's workspace, unless the silent flag is set to true. /// /// The function definition for the custom node workspace to be viewed - internal void FocusCustomNodeWorkspace(Guid symbol) + /// When true, the focus will not switch to the workspace, but it will be opened silently. + internal void FocusCustomNodeWorkspace(Guid symbol, bool silent = false) { if (symbol == null) { throw new Exception(Resources.MessageNodeWithNullFunction); } - - if (model.OpenCustomNodeWorkspace(symbol)) + var res = silent ? model.OpenCustomNodeWorkspaceSilent(symbol) : model.OpenCustomNodeWorkspace(symbol); + if (res) { //set the zoom and offsets events CurrentSpace.OnCurrentOffsetChanged(this, new PointEventArgs(new Point2D(CurrentSpace.X, CurrentSpace.Y))); diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModelDelegateCommands.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModelDelegateCommands.cs index f1c79c4ba57..9469d13eb63 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModelDelegateCommands.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModelDelegateCommands.cs @@ -51,7 +51,8 @@ private void InitializeDelegateCommands() ToggleFullscreenWatchShowingCommand = new DelegateCommand(ToggleFullscreenWatchShowing, CanToggleFullscreenWatchShowing); ToggleBackgroundGridVisibilityCommand = new DelegateCommand(ToggleBackgroundGridVisibility, CanToggleBackgroundGridVisibility); UpdateGraphicHelpersScaleCommand = new DelegateCommand(UpdateGraphicHelpersScale, CanUpdateGraphicHelpersScale); - AlignSelectedCommand = new DelegateCommand(AlignSelected, CanAlignSelected); ; + AlignSelectedCommand = new DelegateCommand(AlignSelected, CanAlignSelected); + UpdateAllPythonEngineCommand = new DelegateCommand(UpdateAllPythonEngine, CanUpdateAllPythonEngine); UndoCommand = new DelegateCommand(Undo, CanUndo); RedoCommand = new DelegateCommand(Redo, CanRedo); CopyCommand = new DelegateCommand(_ => model.Copy(), CanCopy); @@ -138,6 +139,7 @@ private void InitializeDelegateCommands() public DelegateCommand GoToWorkspaceCommand { get; set; } public DelegateCommand DeleteCommand { get; set; } public DelegateCommand AlignSelectedCommand { get; set; } + public DelegateCommand UpdateAllPythonEngineCommand { get; set; } public DelegateCommand PostUIActivationCommand { get; set; } public DelegateCommand ToggleFullscreenWatchShowingCommand { get; set; } public DelegateCommand ToggleBackgroundGridVisibilityCommand { get; set; } diff --git a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs index 213f58e9c3d..a3175672525 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs @@ -1780,7 +1780,8 @@ private void RefreshViewOnSelectionChange(object sender, NotifyCollectionChanged RaisePropertyChanged("HasSelection"); RaisePropertyChanged("IsGeometryOperationEnabled"); RaisePropertyChanged("AnyNodeVisible"); - RaisePropertyChanged("SelectionArgumentLacing"); + RaisePropertyChanged("SelectionArgumentLacing"); + RaisePropertyChanged("CanUpdatePythonEngine"); } /// diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml index 7ecc0b9f40d..0aa89dc4369 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml @@ -534,6 +534,8 @@ + + /// Populates the PythonEngineMenu in the main menu bar with currently available python engines. + /// + private void AddPythonEngineToMainMenu() + { + PythonEngineMenu.Items.Clear(); + var availablePythonEngines = PythonEngineManager.Instance.AvailableEngines.Select(x => x.Name).ToList(); + availablePythonEngines.Select(pythonEngine => new MenuItem + { + Header = pythonEngine, + Command = dynamoViewModel.UpdateAllPythonEngineCommand, + CommandParameter = pythonEngine + }).ToList().ForEach(x => PythonEngineMenu.Items.Add(x)); + } + private void OnWorkspaceHidden(WorkspaceModel workspace) { CalculateWindowMinWidth(); diff --git a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml index 8d8eee1d1f8..7d3f61daa72 100644 --- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml +++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml @@ -381,6 +381,7 @@ @@ -764,6 +765,11 @@ + + + + + ()) + { + item.Click -= UpdateSelectedPythonNodeEngines; + } + PythonEngineMenu.Items.Clear(); + } + + private void AddPythonEngineOptions(MenuItem contextMenuItem) + { + var pythonEngineVersionMenu = contextMenuItem; + var selectedNodes = ViewModel.DynamoViewModel.GetSelectedPythonNodes(); + PythonEngineManager.Instance.AvailableEngines.ToList().ForEach(engineName => ViewModel.DynamoViewModel.AddPythonEngineToMenuItems(selectedNodes, pythonEngineVersionMenu, UpdateSelectedPythonNodeEngines, engineName.Name)); + } + + private void UpdateSelectedPythonNodeEngines(object sender, EventArgs e) + { + if (sender is MenuItem menuItem) + { + var selectedNodes = ViewModel.DynamoViewModel.GetSelectedPythonNodes(); + selectedNodes.ForEach(pythonNodeModel => + { + ViewModel.DynamoViewModel.UpdatePythonNodeEngine(pythonNodeModel, (string)menuItem.Header); + }); + } } private void OnGeometryScaling_Click(object sender, RoutedEventArgs e) diff --git a/src/Libraries/PythonNodeModelsWpf/PythonNode.cs b/src/Libraries/PythonNodeModelsWpf/PythonNode.cs index fbbbf5b9822..459ffa2fa87 100644 --- a/src/Libraries/PythonNodeModelsWpf/PythonNode.cs +++ b/src/Libraries/PythonNodeModelsWpf/PythonNode.cs @@ -94,8 +94,8 @@ public void CustomizeView(PythonNode nodeModel, NodeView nodeView) learnMoreItem.Click += OpenPythonLearningMaterial; - PythonNodeUtils.GetEngineNames(nodeModel).ForEach(engineName => AddPythonEngineToMenuItems( - pythonNodeModel,pythonEngineVersionMenu,UpdateEngine,engineName)); + PythonNodeUtils.GetEngineNames(nodeModel).ForEach(engineName => dynamoViewModel.AddPythonEngineToMenuItems( + new List() { pythonNodeModel }, pythonEngineVersionMenu, UpdateEngine, engineName, true)); PythonEngineManager.Instance.AvailableEngines.CollectionChanged += PythonEnginesChanged; @@ -302,10 +302,7 @@ private void UpdateEngine(object sender, EventArgs e) { if (sender is MenuItem menuItem) { - dynamoViewModel.ExecuteCommand( - new DynamoModel.UpdateModelValueCommand( - Guid.Empty, pythonNodeModel.GUID, nameof(pythonNodeModel.EngineName), (string)menuItem.Header)); - pythonNodeModel.OnNodeModified(); + dynamoViewModel.UpdatePythonNodeEngine(pythonNodeModel, (string)menuItem.Header); } } @@ -317,34 +314,10 @@ private void PythonEnginesChanged(object sender, NotifyCollectionChangedEventArg { if(item is PythonEngine newEngine) { - AddPythonEngineToMenuItems(pythonNodeModel,pythonEngineVersionMenu,UpdateEngine,newEngine.Name); + dynamoViewModel.AddPythonEngineToMenuItems(new List() { pythonNodeModel }, pythonEngineVersionMenu, UpdateEngine, newEngine.Name, true); } } } } - - /// - /// Adds python engine to MenuItems, if that engine name is not already present. - /// - internal static void AddPythonEngineToMenuItems(PythonNodeBase pythonNodeModel, - MenuItem pythonEngineVersionMenu, - RoutedEventHandler updateEngineDelegate, - string engineName) - { - - if (pythonEngineVersionMenu.Items.Cast().Any(x => x.Header as string == engineName)) - { - return; - } - var pythonEngineItem = new MenuItem { Header = engineName, IsCheckable = false }; - pythonEngineItem.Click += updateEngineDelegate; - pythonEngineItem.SetBinding(MenuItem.IsCheckedProperty, new Binding(nameof(pythonNodeModel.EngineName)) - { - Source = pythonNodeModel, - Converter = new CompareToParameterConverter(), - ConverterParameter = engineName - }); - pythonEngineVersionMenu.Items.Add(pythonEngineItem); - } } } diff --git a/src/Libraries/PythonNodeModelsWpf/PythonStringNode.cs b/src/Libraries/PythonNodeModelsWpf/PythonStringNode.cs index 45ff31609ff..69f970a2129 100644 --- a/src/Libraries/PythonNodeModelsWpf/PythonStringNode.cs +++ b/src/Libraries/PythonNodeModelsWpf/PythonStringNode.cs @@ -1,9 +1,8 @@ using System; +using System.Collections.Generic; using System.Collections.Specialized; -using System.Linq; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; using Dynamo.Controls; using Dynamo.Models; using Dynamo.PythonServices; @@ -33,8 +32,8 @@ public void CustomizeView(PythonStringNode nodeModel, NodeView nodeView) pythonEngineVersionMenu = new MenuItem { Header = PythonNodeModels.Properties.Resources.PythonNodeContextMenuEngineSwitcher, IsCheckable = false }; nodeView.MainContextMenu.Items.Add(pythonEngineVersionMenu); - PythonNodeUtils.GetEngineNames(nodeModel).ForEach(engineName => PythonNodeViewCustomization.AddPythonEngineToMenuItems( - pythonStringNodeModel, pythonEngineVersionMenu, UpdateEngine, engineName)); + PythonNodeUtils.GetEngineNames(nodeModel).ForEach(engineName => dynamoViewModel.AddPythonEngineToMenuItems( + new List() { pythonStringNodeModel }, pythonEngineVersionMenu, UpdateEngine, engineName, true)); PythonEngineManager.Instance.AvailableEngines.CollectionChanged += PythonEnginesChanged; @@ -106,8 +105,8 @@ private void PythonEnginesChanged(object sender, NotifyCollectionChangedEventArg { if (item is PythonEngine newEngine) { - PythonNodeViewCustomization.AddPythonEngineToMenuItems( - pythonStringNodeModel,pythonEngineVersionMenu,UpdateEngine,newEngine.Name); + dynamoViewModel.AddPythonEngineToMenuItems( + new List() { pythonStringNodeModel }, pythonEngineVersionMenu,UpdateEngine,newEngine.Name); } } }