alielie
2025-07-04 0940f31b7eba1cf6b6a8c1fca72d97cf686e79f2
Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
@@ -1,5 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using GongSolutions.Wpf.DragDrop;
using HMI.Core.Util;
using HMI.UI;
using HMI.UI.Util;
@@ -11,6 +12,11 @@
using Plugin.SeqEditor.Util;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace Plugin.SeqEditor.ViewModel
{
@@ -44,8 +50,14 @@
        [ObservableProperty]
        private string targetType = null;
        [ObservableProperty]
        private string currentFilePath;
        [ObservableProperty]
        private bool canDrop = true;
        public IDropTarget StepDropHandler { get; set; }
        private Engine engine;
        private SequenceFile sequenceFile;
        private bool isLoaded;
@@ -54,15 +66,8 @@
        public List<ItemData> Types = FilterTypeData.ItemSource;
        private HashSet<string> edits = new HashSet<string> {
            StepTypeStr.PassFailTest,
            StepTypeStr.NumericLimitTest,
            StepTypeStr.NI_MultipleNumericLimitTest,
            StepTypeStr.StringValueTest,
            StepTypeStr.Action,
            StepTypeStr.NI_Wait,
            StepTypeStr.SequenceCall,
        };
        private HashSet<string> edits = new HashSet<string>();
        public Dictionary<Sequence, ObservableCollection<StepUI>> sequenceCache { get; private set; } = new();
        public SeqEditorViewModel(SeqEditor control, ILog log)
        {
@@ -70,6 +75,8 @@
            this.control = control;
            engine = new Engine();
            engine.LoadTypePaletteFilesEx();
            TargetType = string.Empty;
            StepDropHandler = new TreeListViewHandler(this);
        }
        ~SeqEditorViewModel()
@@ -88,6 +95,10 @@
        private ObservableCollection<StepUI> LoadSteps(Sequence seq, string group = null)
        {
            if (sequenceCache.ContainsKey(seq))
            {
                return sequenceCache[seq];
            }
            //setupSteps.Clear();
            //var steps = new ObservableCollection<StepUI>();
            //int num = seq.GetNumSteps(StepGroups.StepGroup_Setup);
@@ -133,46 +144,51 @@
            //CurrentStepUI = null;
            var steps = new ObservableCollection<StepUI>();
            StepGroups[] groups = new StepGroups[] { StepGroups.StepGroup_Setup, StepGroups.StepGroup_Main, StepGroups.StepGroup_Cleanup };
            int num = seq.GetNumSteps(StepGroups.StepGroup_Setup);
            foreach (var stepGroup in groups)
            {
                int num = seq.GetNumSteps(stepGroup);
            for (int i = 0; i < num; i++)
            {
                Step step = seq.GetStep(i, StepGroups.StepGroup_Setup);
                var ui = Convert2StepUI(step, group);
                    Step step = seq.GetStep(i, stepGroup);
                    var ui = Convert2StepUI(i, step, seq, group);
                if (ui != null)
                {
                    steps.Add(ui);
                }
            }
            num = seq.GetNumSteps(StepGroups.StepGroup_Main);
            for (int i = 0; i < num; i++)
            {
                Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
                var ui = Convert2StepUI(step, group);
                if (ui != null)
                {
                    steps.Add(ui);
                }
            }
            num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
            for (int i = 0; i < num; i++)
            {
                Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
                var ui = Convert2StepUI(step, group);
                if (ui != null)
                {
                    steps.Add(ui);
                }
            }
            //int num = seq.GetNumSteps(StepGroups.StepGroup_Main);
            //for (int i = 0; i < num; i++)
            //{
            //    Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
            //    var ui = Convert2StepUI(step, seq, group);
            //    if (ui != null)
            //    {
            //        steps.Add(ui);
            //    }
            //}
            //num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
            //for (int i = 0; i < num; i++)
            //{
            //    Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
            //    var ui = Convert2StepUI(step, seq, group);
            //    if (ui != null)
            //    {
            //        steps.Add(ui);
            //    }
            //}
            sequenceCache[seq] = steps;
            return steps;
        }
        private StepUI Convert2StepUI(Step step, string group)
        private StepUI Convert2StepUI(int index, Step step, Sequence sequence, string group)
        {
            var ui = new StepUI(step);
            if (!edits.Contains(ui.Type))
            var ui = new StepUI(step, sequence);
            if (edits != null && edits.Count > 0 && !edits.Contains(ui.Type))
            {
                return null;
            }
@@ -202,16 +218,21 @@
            {
                var po = step.Module.AsPropertyObject();
                bool useCurFile = po.GetValBoolean("UseCurFile", 0);
                if (useCurFile)
                string sfPath = po.GetValString("SFPath", 0);
                if (useCurFile || Path.GetFileName(currentFilePath).Equals(sfPath, StringComparison.CurrentCultureIgnoreCase))
                {
                    string seqName = po.GetValString("SeqName", 0);
                    Sequence sequence = sequenceFile.GetSequenceByName(seqName);
                    if (sequence == null)
                    Sequence sunSequence = sequenceFile.GetSequenceByName(seqName);
                    if (sunSequence == null)
                    {
                        return ui;
                    }
                    ui.Children = LoadSteps(sequence, group);
                    ui.Children = LoadSteps(sunSequence, group);
                }
            }
            if (CurrentSeqUI != null)
            {
                ui.SettingChanged += CurrentSeqUI.OnStepSettingChanged;
            }
            return ui;
        }
@@ -232,20 +253,19 @@
            {
                Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
            };
            if (ofd.ShowDialog() == true)
            if (ofd.ShowDialog() == true && DoClose())
            {
                control.BackgroundAction(() =>
                {
                    try
                    {
                        var start = DateTime.Now;
                        currentFilePath = ofd.FileName;
                        CurrentFileName = $"{LangUtil.Get("se.currentFile")}{Path.GetFileName(currentFilePath)}";
                        CurrentFilePath = ofd.FileName;
                        if (sequenceFile != null)
                        {
                            engine.ReleaseSequenceFileEx(sequenceFile);
                        }
                        sequenceFile = engine.GetSequenceFileEx(currentFilePath);
                        sequenceFile = engine.GetSequenceFileEx(CurrentFilePath);
                        Sequence main = sequenceFile.GetSequenceByName("MainSequence");
                        CurrentSeqUI = new SeqUI(main);
@@ -257,15 +277,19 @@
                        //}
                        //Sequences = seqs;
                        if (Sequences != null && Sequences.Count > 0)
                        {
                            CurrentSeqUI = Sequences[0];
                        }
                        log.Info($"Open File [{currentFilePath}] In {(DateTime.Now - start).TotalMilliseconds}ms");
                        //if (Sequences != null && Sequences.Count > 0)
                        //{
                        //    CurrentSeqUI = Sequences[0];
                        //}
                        log.Info($"Open File [{CurrentFilePath}] In {(DateTime.Now - start).TotalMilliseconds}ms");
                    }
                    catch (Exception ex)
                    {
                        log.Error($"Open Sequence Failed.", ex);
                        control.Dispatcher.Invoke(() =>
                        {
                            MsgBoxHelper2.Error(ex.Message);
                        });
                    }
                }, LangUtil.Get("se.seqIsLoading"));
            }
@@ -274,54 +298,92 @@
        [RelayCommand]
        private void SaveSeqFile()
        {
            sequenceFile?.Save(currentFilePath);
            if (sequenceFile == null) return;
            try
            {
                sequenceFile?.Save(CurrentFilePath);
                CurrentSeqUI.IsChanged = false;
                ToastHelper.Success(LangUtil.Get("App.SaveSuccess"));
            }
            catch (Exception ex)
            {
                log.Error("Save Sequence File Error.", ex);
                ToastHelper.Error($"{LangUtil.Get("App.SaveFailed")}: {ex.Message}");
            }
        }
        [RelayCommand]
        private void SaveToFile()
        {
            if (sequenceFile == null) return;
            try
            {
                SaveFileDialog sfd = new SaveFileDialog()
                {
                    Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
                };
                if (sfd.ShowDialog() == true)
                {
                    sequenceFile.Save(sfd.FileName);
                    CurrentFilePath = sfd.FileName;
                    ToastHelper.Success(LangUtil.Get("App.SaveSuccess"));
                    CurrentSeqUI.IsChanged = false;
                }
            }
            catch (Exception ex)
            {
                log.Error("Save Sequence File Error.", ex);
                ToastHelper.Error($"{LangUtil.Get("App.SaveFailed")}: {ex.Message}");
            }
        }
        [RelayCommand]
        private void Refresh()
        {
            if (CurrentSeqUI == null) return;
            if (string.IsNullOrEmpty(TargetType))
            RefreshData();
        }
        private bool DoClose()
            {
                edits = new HashSet<string> {
                    StepTypeStr.PassFailTest,
                    StepTypeStr.NumericLimitTest,
                    StepTypeStr.NI_MultipleNumericLimitTest,
                    StepTypeStr.StringValueTest,
                    StepTypeStr.Action,
                    StepTypeStr.NI_Wait,
                    StepTypeStr.SequenceCall,
                };
            if (CurrentSeqUI?.IsChanged == true)
            {
                if (MsgBoxHelper2.WarnChoose(LangUtil.Get("se.makeSureClose"))
                    == System.Windows.MessageBoxResult.OK)
                {
                    goto DoClose;
            }
            else
            {
                edits = new HashSet<string>(TargetType.Split(','))
                {
                    StepTypeStr.SequenceCall
                };
                    return false;
            }
            AllSteps = LoadSteps(CurrentSeqUI.sequence);
        }
        [RelayCommand]
        private void CloseSeqFile()
        {
            //AllSteps = new ObservableCollection<StepUI>();
        DoClose:
            if (engine != null && sequenceFile != null)
            {
                engine.ReleaseSequenceFileEx(sequenceFile);
                sequenceFile = null;
            }
            setupSteps.Clear();
            mainSteps.Clear();
            cleanupSteps.Clear();
            AllSteps = new();
            Sequences.Clear();
            currentFilePath = string.Empty;
            CurrentFilePath = string.Empty;
            CurrentFileName = string.Empty;
            CurrentSeqUI = null;
            CurrentStepUI = null;
            CurrentSeqTitle = LangUtil.Get("se.steps");
            sequenceCache.Clear();
            return true;
        }
        [RelayCommand]
        private void CloseSeqFile()
        {
            DoClose();
        }
        [RelayCommand]
@@ -330,21 +392,22 @@
            try
            {
                var group = CurrentStepUI.step.StepGroup;
                var targetSequence = CurrentStepUI.sequence;
                ObservableCollection<StepUI> source;
                if (group == StepGroups.StepGroup_Setup)
                {
                    source = setupSteps;
                }
                else if (group == StepGroups.StepGroup_Main)
                {
                    source = mainSteps;
                }
                else
                {
                    source = cleanupSteps;
                }
                int index = source.IndexOf(CurrentStepUI);
                ObservableCollection<StepUI> source = sequenceCache[targetSequence];
                //if (group == StepGroups.StepGroup_Setup)
                //{
                //    source = setupSteps;
                //}
                //else if (group == StepGroups.StepGroup_Main)
                //{
                //    source = mainSteps;
                //}
                //else
                //{
                //    source = cleanupSteps;
                //}
                int index = CurrentStepUI.IndexInSequence;
                if (index < 0)
                {
                    return;
@@ -355,14 +418,6 @@
                    case "Tests.PassFail":
                        newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.PassFailTest);
                        newStep.Name = DefaultStepName.PassFailTest;
                        var p = newStep.AsPropertyObject();
                        string name = p.Name;
                        var ps = p.GetSubProperties("", 0);
                        foreach (var pp in ps)
                        {
                            string sname = pp.Name;
                        }
                        break;
                    case "Tests.NumericLimitTest":
                        newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NumericLimitTest);
@@ -408,12 +463,37 @@
                        newStep = engine.NewStep(AdapterKeyNames.PythonAdapterKeyName, StepTypeStr.Action);
                        newStep.Name = DefaultStepName.Action;
                        break;
                    default:
                        return;
                }
                CurrentSeqUI.sequence.InsertStep(newStep, index + 1, group);
                AllSteps = LoadSteps(CurrentSeqUI.sequence);
                var newUI = new StepUI(newStep, targetSequence);
                targetSequence.InsertStep(newStep, index + 1, group);
                ObservableCollection<StepUI> datasource = sequenceCache[targetSequence];
                int uiIndex = datasource.IndexOf(CurrentStepUI);
                datasource.Insert(uiIndex + 1, newUI);
                //var newItem = new TreeItemData
                //{
                //    Level = TreeItemData.Level,
                //    ParentItem = TreeItemData.ParentItem,
                //    ParentItems = TreeItemData.ParentItems,
                //    Data = newUI
                //};
                //var parentItem = TreeItemData.ParentItem;
                //if (parentItem != null)
                //{
                //    var items = parentItem.Items;
                //    int innerIndex = items.IndexOf(TreeItemData);
                //    items.Insert(innerIndex + 1, newItem);
                //    TreeItemDataCollection.ResetSubItems(items);
                //}
                //int itemIndex = TreeCollection.IndexOf(TreeItemData);
                //TreeCollection.Insert(itemIndex + TreeItemData.AllSubCount + 1, newItem);
            }
            catch (Exception ex)
            {
@@ -422,12 +502,96 @@
            }
        }
        [RelayCommand]
        private void Sb(RoutedPropertyChangedEventArgs<object> e)
        {
            CurrentStepUI = e.NewValue as StepUI;
        }
        static TreeListViewItem VisualUpwardSearch(DependencyObject source)
        {
            while (source != null && !(source is TreeViewItem))
                source = VisualTreeHelper.GetParent(source);
            return source as TreeListViewItem;
        }
        [RelayCommand]
        private void Sb2(MouseButtonEventArgs e)
        {
            var item = VisualUpwardSearch(e.OriginalSource as DependencyObject);
            if (item != null)
            {
                item.Focus();
                e.Handled = true;
            }
        }
        [ObservableProperty]
        private TreeItemData treeItemData;
        public void RefreshView()
        {
            CollectionViewSource cvs = control.Resources["TreeGridFilter"] as CollectionViewSource;
            control.Dispatcher.Invoke(() =>
            {
                cvs.View.Refresh();
            });
        }
        [ObservableProperty]
        private TreeItemDataCollection treeCollection = new TreeItemDataCollection();
        public void RefreshData()
        {
            sequenceCache.Clear();
            AllSteps = LoadSteps(CurrentSeqUI.sequence);
        }
        partial void OnAllStepsChanged(ObservableCollection<StepUI> data)
        {
            TreeCollection = new TreeItemDataCollection(AllSteps, "Children", true);
        }
        partial void OnTreeItemDataChanged(TreeItemData data)
        {
            CurrentStepUI = data?.Data as StepUI;
        }
        partial void OnTargetTypeChanged(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                edits = new HashSet<string>
                {
                    //StepTypeStr.PassFailTest,
                    //StepTypeStr.NumericLimitTest,
                    //StepTypeStr.NI_MultipleNumericLimitTest,
                    //StepTypeStr.StringValueTest,
                    //StepTypeStr.Action,
                    //StepTypeStr.NI_Wait,
                    //StepTypeStr.SequenceCall,
                };
            }
            else
            {
                edits = new HashSet<string>(value.Split(MultiComboBox.splits, StringSplitOptions.RemoveEmptyEntries))
                {
                    StepTypeStr.SequenceCall
                };
            }
        }
        partial void OnCurrentFilePathChanged(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                CurrentFileName = string.Empty;
            }
            else
            {
                CurrentFileName = $"{LangUtil.Get("se.currentFile")}{Path.GetFileName(value)}";
            }
        }
        partial void OnCurrentStepUIChanged(StepUI stepUI)
@@ -436,7 +600,6 @@
            control.editPanelContainer.Child = panel;
            if (stepUI != null)
            {
                //window.commonP.RefreshStep(stepUI);
            }
        }
@@ -446,7 +609,7 @@
            if (seqUI != null)
            {
                CurrentStepUI = null;
                AllSteps = LoadSteps(seqUI.sequence);
                RefreshData();
            }
            CurrentSeqTitle = $"{seqUI?.Name} {LangUtil.Get("se.steps")}";
        }