From 993587dc3cd04108a5b88dcf7abf60d9f751588f Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Wed, 17 May 2023 15:04:16 -0400 Subject: [PATCH] DYN-5862 Python editor docking improvements (#13984) * Python docking improvements * Update resources * update * Update ScriptEditorWindow.xaml.cs * update CachedEngine when editor engine is changed in docked state * Improvement python editor behavior inside a custom node. * Update DynamoViewModel.cs * Addressing comments * Update PythonNode.cs --- .../Properties/Resources.Designer.cs | 4 +- .../Properties/Resources.en-US.resx | 2 +- src/DynamoCoreWpf/Properties/Resources.resx | 2 +- .../UI/GuidedTour/GuidesValidationMethods.cs | 4 +- .../ViewModels/Core/DynamoViewModel.cs | 78 ++++++++++++++- .../ViewModels/Core/WorkspaceViewModel.cs | 10 +- src/DynamoCoreWpf/Views/Core/DynamoView.xaml | 8 +- .../Views/Core/DynamoView.xaml.cs | 98 ++++++++----------- src/Libraries/PythonNodeModels/PythonNode.cs | 11 +++ .../PythonNodeModelsWpf/PythonNode.cs | 54 +++++++++- .../ScriptEditorWindow.xaml | 4 +- .../ScriptEditorWindow.xaml.cs | 19 +++- .../PythonNodeCustomizationTests.cs | 18 ++-- .../DocumentationBrowserViewExtensionTests.cs | 42 ++++---- .../GraphNodeManagerViewExtensionTests.cs | 24 ++--- .../ViewExtensions/ViewExtensionTests.cs | 54 +++++----- .../WorkspaceDependencyViewExtensionTests.cs | 24 ++--- .../PythonMigrationViewExtensionTests.cs | 6 +- 18 files changed, 298 insertions(+), 164 deletions(-) diff --git a/src/DynamoCoreWpf/Properties/Resources.Designer.cs b/src/DynamoCoreWpf/Properties/Resources.Designer.cs index 2fa3cbce17d..ff5b86ab8ff 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 @@ -8407,7 +8407,7 @@ public static string ShowWiresPopupMenuItem { } /// - /// Looks up a localized string similar to SideBar Panel. + /// Looks up a localized string similar to Sidebar. /// public static string SideBarPanelViewTitle { get { diff --git a/src/DynamoCoreWpf/Properties/Resources.en-US.resx b/src/DynamoCoreWpf/Properties/Resources.en-US.resx index bdc3e99e651..31c422bfb9f 100644 --- a/src/DynamoCoreWpf/Properties/Resources.en-US.resx +++ b/src/DynamoCoreWpf/Properties/Resources.en-US.resx @@ -2143,7 +2143,7 @@ Do you want to install the latest Dynamo update? Write note here - SideBar Panel + Sidebar Extension tab added to the extensions side bar. diff --git a/src/DynamoCoreWpf/Properties/Resources.resx b/src/DynamoCoreWpf/Properties/Resources.resx index df931defe28..ad311a2c573 100644 --- a/src/DynamoCoreWpf/Properties/Resources.resx +++ b/src/DynamoCoreWpf/Properties/Resources.resx @@ -2367,7 +2367,7 @@ Want to publish a different package? Write note here - SideBar Panel + Sidebar Extension tab added to the extensions side bar. diff --git a/src/DynamoCoreWpf/UI/GuidedTour/GuidesValidationMethods.cs b/src/DynamoCoreWpf/UI/GuidedTour/GuidesValidationMethods.cs index 88475f157f0..a444a69e499 100644 --- a/src/DynamoCoreWpf/UI/GuidedTour/GuidesValidationMethods.cs +++ b/src/DynamoCoreWpf/UI/GuidedTour/GuidesValidationMethods.cs @@ -577,14 +577,14 @@ internal static void ExecuteViewDetailsSideBar(Step stepInfo, StepUIAutomation u if (packageDetailsWindow == null) return; //In order to close the Package Details tab we need first to get the Tab, then get the Close button and finally call the event to close it - TabItem tabitem = dynamoView.SideBarPanelTabItems.OfType().SingleOrDefault(n => n.Header.ToString() == packageDetailsName); + TabItem tabitem = stepInfo.DynamoViewModelStep.SideBarTabItems.OfType().SingleOrDefault(n => n.Header.ToString() == packageDetailsName); if (tabitem == null) return; //Get the Close button from the PackageDetailsView Button closeButton = GuideUtilities.FindChild(tabitem, closeButtonName) as Button; if (closeButton == null) return; - dynamoView.OnCloseRightSidePanelTab(closeButton, null); + dynamoView.OnCloseRightSideBarTab(closeButton, null); } } diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index 373843a3c29..30d9416d63d 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Reflection; using System.Windows; +using System.Windows.Controls; using System.Windows.Forms; using System.Windows.Media; using System.Windows.Threading; @@ -42,6 +43,8 @@ using Dynamo.Wpf.ViewModels.FileTrust; using Dynamo.Wpf.ViewModels.Watch3D; using DynamoUtilities; +using ICSharpCode.AvalonEdit; +using PythonNodeModels; using ISelectable = Dynamo.Selection.ISelectable; using WpfResources = Dynamo.Wpf.Properties.Resources; @@ -63,24 +66,40 @@ public partial class DynamoViewModel : ViewModelBase, IDynamoViewModel // Can the user run the graph private bool CanRunGraph => HomeSpace.RunSettings.RunEnabled && !HomeSpace.GraphRunInProgress; - private ObservableCollection watch3DViewModels = new ObservableCollection(); + private ObservableCollection sideBarTabItems = new ObservableCollection(); /// - /// An observable collection of workspace view models which tracks the model + /// An observable collection of workspace view models which tracks the model. /// private ObservableCollection workspaces = new ObservableCollection(); /// - /// Set of node window id's that are currently docked in right side sidebar + /// Set of node window id's that are currently docked in right side sidebar. /// - internal HashSet CurrentDockedWindows { get; set; } = new HashSet(); + internal HashSet DockedNodeWindows { get; set; } = new HashSet(); /// /// Node window's state, either DockRight or FloatingWindow. /// internal Dictionary NodeWindowsState { get; set; } = new Dictionary(); + /// + /// Collection of Right SideBar tab items: view extensions and docked windows. + /// + public ObservableCollection SideBarTabItems + { + get + { + return sideBarTabItems; + } + set + { + sideBarTabItems = value; + RaisePropertyChanged(nameof(SideBarTabItems)); + } + } + public ObservableCollection Workspaces { get { return workspaces; } @@ -1470,6 +1489,57 @@ internal void AddToRecentFiles(string path) } } + // Get the nodemodel if a node is present in any open workspace. + internal NodeModel GetDockedWindowNodeModel(string tabId) + { + var workspaces = Model.Workspaces; + NodeModel nodeModel = null; + + foreach (WorkspaceModel workspace in workspaces) + { + nodeModel = workspace.Nodes.FirstOrDefault(x => x.GUID.ToString() == tabId); + if (nodeModel != null) + { + return nodeModel; + } + } + return nodeModel; + } + + /// + /// Closes any docked python script windows if there are no unsaved changes. + /// Show warning message on the script editor if it has unsaved changes. + /// + /// Nodes in the workspace + internal bool CanCloseDockedNodeWindows(ObservableCollection nodes) + { + foreach (var node in nodes) + { + var id = node.NodeModel.GUID.ToString(); + if (DockedNodeWindows.Contains(id)) + { + var tabItem = SideBarTabItems.OfType().SingleOrDefault(n => n.Uid.ToString() == id); + NodeModel nodeModel = GetDockedWindowNodeModel(tabItem.Uid); + + if (nodeModel is PythonNode pythonNode) + { + var editor = (tabItem.Content as Grid).ChildOfType(); + if (editor != null && editor.IsModified) + { + pythonNode.OnWarnUserScript(); + tabItem.Focus(); + return false; + } + pythonNode.Dispose(); + } + + SideBarTabItems.Remove(tabItem); + DockedNodeWindows.Remove(id); + } + } + return true; + } + /// /// Returns the file-save dialog with customized file types of Dynamo. /// diff --git a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs index e3e9b459f41..4c63be9050b 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs @@ -1329,8 +1329,14 @@ private void Hide(object parameters) } else { - if (!Model.HasUnsavedChanges || DynamoViewModel.AskUserToSaveWorkspaceOrCancel(Model)) - DynamoViewModel.Model.RemoveWorkspace(Model); + // Close the custom workspace only if all docked node windows are saved and can be closed. + if (DynamoViewModel.CanCloseDockedNodeWindows(Nodes)) + { + if (!Model.HasUnsavedChanges || DynamoViewModel.AskUserToSaveWorkspaceOrCancel(Model)) + { + DynamoViewModel.Model.RemoveWorkspace(Model); + } + } } } diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml index 50bb96fe329..b80be8af064 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml @@ -1556,7 +1556,7 @@ Grid.Row="2" Grid.Column="4" Grid.RowSpan="2"> - +