| | |
| | | using CommunityToolkit.Mvvm.ComponentModel; |
| | | using CommunityToolkit.Mvvm.Input; |
| | | using GongSolutions.Wpf.DragDrop; |
| | | using HMI.Core.Util; |
| | | using HMI.UI; |
| | | using HMI.UI.Util; |
| | |
| | | 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 |
| | | { |
| | |
| | | [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; |
| | |
| | | |
| | | 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) |
| | | { |
| | |
| | | this.control = control; |
| | | engine = new Engine(); |
| | | engine.LoadTypePaletteFilesEx(); |
| | | TargetType = string.Empty; |
| | | StepDropHandler = new TreeListViewHandler(this); |
| | | } |
| | | |
| | | ~SeqEditorViewModel() |
| | |
| | | |
| | | 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); |
| | |
| | | //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; |
| | | } |
| | |
| | | { |
| | | 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; |
| | | } |
| | |
| | | { |
| | | 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); |
| | | |
| | |
| | | //} |
| | | //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")); |
| | | } |
| | |
| | | [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] |
| | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | 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) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | [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) |
| | |
| | | control.editPanelContainer.Child = panel; |
| | | if (stepUI != null) |
| | | { |
| | | |
| | | //window.commonP.RefreshStep(stepUI); |
| | | } |
| | | } |
| | |
| | | if (seqUI != null) |
| | | { |
| | | CurrentStepUI = null; |
| | | AllSteps = LoadSteps(seqUI.sequence); |
| | | RefreshData(); |
| | | } |
| | | CurrentSeqTitle = $"{seqUI?.Name} {LangUtil.Get("se.steps")}"; |
| | | } |