using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.Input;
|
using GongSolutions.Wpf.DragDrop;
|
using HMI.Core.Util;
|
using HMI.UI;
|
using HMI.UI.Util;
|
using log4net;
|
using Microsoft.Win32;
|
using NationalInstruments.TestStand.Interop.API;
|
using Plugin.SeqEditor.Constant;
|
using Plugin.SeqEditor.Entity;
|
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
|
{
|
|
public partial class SeqEditorViewModel : ObservableObject
|
{
|
private ObservableCollection<StepUI> setupSteps = new ObservableCollection<StepUI>();
|
|
private ObservableCollection<StepUI> mainSteps = new ObservableCollection<StepUI>();
|
|
private ObservableCollection<StepUI> cleanupSteps = new ObservableCollection<StepUI>();
|
|
[ObservableProperty]
|
private ObservableCollection<StepUI> allSteps = new ObservableCollection<StepUI>();
|
|
[ObservableProperty]
|
private ObservableCollection<SeqUI> sequences = new ObservableCollection<SeqUI>();
|
|
[ObservableProperty]
|
private SeqUI currentSeqUI;
|
|
[ObservableProperty]
|
private StepUI currentStepUI;
|
|
[ObservableProperty]
|
private string currentFileName;
|
|
[ObservableProperty]
|
private string currentSeqTitle = LangUtil.Get("se.steps");
|
|
[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;
|
private ILog log;
|
public SeqEditor control { get; private set; }
|
|
public List<ItemData> Types = FilterTypeData.ItemSource;
|
|
private HashSet<string> edits = new HashSet<string>();
|
public Dictionary<Sequence, ObservableCollection<StepUI>> sequenceCache { get; private set; } = new();
|
|
public SeqEditorViewModel(SeqEditor control, ILog log)
|
{
|
this.log = log;
|
this.control = control;
|
engine = new Engine();
|
engine.LoadTypePaletteFilesEx();
|
TargetType = string.Empty;
|
StepDropHandler = new TreeListViewHandler(this);
|
}
|
|
~SeqEditorViewModel()
|
{
|
if (engine != null)
|
{
|
if (sequenceFile != null)
|
{
|
engine.ReleaseSequenceFileEx(sequenceFile);
|
}
|
engine.ShutDown(true);
|
// 不加延时会弹窗md
|
System.Threading.Thread.Sleep(2500);
|
}
|
}
|
|
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);
|
//for (int i = 0; i < num; i++)
|
//{
|
// Step step = seq.GetStep(i, StepGroups.StepGroup_Setup);
|
// var ui = new StepUI(step);
|
// if (edits.Contains(ui.Type))
|
// {
|
// setupSteps.Add(ui);
|
// steps.Add(ui);
|
// }
|
//}
|
////SetupSteps = steps;
|
////steps = new ObservableCollection<StepUI>();
|
//mainSteps.Clear();
|
//num = seq.GetNumSteps(StepGroups.StepGroup_Main);
|
//for (int i = 0; i < num; i++)
|
//{
|
// Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
|
// var ui = new StepUI(step);
|
// if (edits.Contains(ui.Type))
|
// {
|
// mainSteps.Add(ui);
|
// steps.Add(ui);
|
// }
|
//}
|
////MainSteps = steps;
|
////steps = new ObservableCollection<StepUI>();
|
//cleanupSteps.Clear();
|
//num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
|
//for (int i = 0; i < num; i++)
|
//{
|
// Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
|
// var ui = new StepUI(step);
|
// if (edits.Contains(ui.Type))
|
// {
|
// cleanupSteps.Add(ui);
|
// steps.Add(ui);
|
// }
|
//}
|
//AllSteps = steps;
|
//CurrentStepUI = null;
|
|
var steps = new ObservableCollection<StepUI>();
|
StepGroups[] groups = new StepGroups[] { StepGroups.StepGroup_Setup, StepGroups.StepGroup_Main, StepGroups.StepGroup_Cleanup };
|
|
foreach (var stepGroup in groups)
|
{
|
int num = seq.GetNumSteps(stepGroup);
|
for (int i = 0; i < num; i++)
|
{
|
Step step = seq.GetStep(i, stepGroup);
|
var ui = Convert2StepUI(i, step, seq, 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(int index, Step step, Sequence sequence, string group)
|
{
|
var ui = new StepUI(step, sequence);
|
if (edits != null && edits.Count > 0 && !edits.Contains(ui.Type))
|
{
|
return null;
|
}
|
|
if (string.IsNullOrEmpty(group))
|
{
|
if (ui.StepGroup == StepGroups.StepGroup_Setup)
|
{
|
group = "Setup";
|
}
|
else if (ui.StepGroup == StepGroups.StepGroup_Main)
|
{
|
group = "Main";
|
}
|
else if (ui.StepGroup == StepGroups.StepGroup_Cleanup)
|
{
|
group = "Cleanup";
|
}
|
else
|
{
|
group = "Unkown";
|
}
|
}
|
ui.Group = group;
|
|
if (ui.Type == StepTypeStr.SequenceCall)
|
{
|
var po = step.Module.AsPropertyObject();
|
bool useCurFile = po.GetValBoolean("UseCurFile", 0);
|
string sfPath = po.GetValString("SFPath", 0);
|
if (useCurFile || Path.GetFileName(currentFilePath).Equals(sfPath, StringComparison.CurrentCultureIgnoreCase))
|
{
|
string seqName = po.GetValString("SeqName", 0);
|
Sequence sunSequence = sequenceFile.GetSequenceByName(seqName);
|
if (sunSequence == null)
|
{
|
return ui;
|
}
|
ui.Children = LoadSteps(sunSequence, group);
|
}
|
}
|
if (CurrentSeqUI != null)
|
{
|
ui.SettingChanged += CurrentSeqUI.OnStepSettingChanged;
|
}
|
return ui;
|
}
|
|
|
[RelayCommand]
|
private void Loaded()
|
{
|
if (!isLoaded)
|
{
|
}
|
}
|
|
[RelayCommand]
|
private void OpenSeqFile()
|
{
|
OpenFileDialog ofd = new OpenFileDialog()
|
{
|
Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
|
};
|
if (ofd.ShowDialog() == true && DoClose())
|
{
|
control.BackgroundAction(() =>
|
{
|
try
|
{
|
var start = DateTime.Now;
|
CurrentFilePath = ofd.FileName;
|
if (sequenceFile != null)
|
{
|
engine.ReleaseSequenceFileEx(sequenceFile);
|
}
|
sequenceFile = engine.GetSequenceFileEx(CurrentFilePath);
|
Sequence main = sequenceFile.GetSequenceByName("MainSequence");
|
CurrentSeqUI = new SeqUI(main);
|
|
//var seqs = new ObservableCollection<SeqUI>();
|
//for (int i = 0; i < sequenceFile.NumSequences; i++)
|
//{
|
// var tsSequence = sequenceFile.GetSequence(i);
|
// seqs.Add(new SeqUI(tsSequence));
|
//}
|
//Sequences = seqs;
|
|
//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()
|
{
|
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;
|
RefreshData();
|
}
|
|
private bool DoClose()
|
{
|
if (CurrentSeqUI?.IsChanged == true)
|
{
|
if (MsgBoxHelper2.WarnChoose(LangUtil.Get("se.makeSureClose"))
|
== System.Windows.MessageBoxResult.OK)
|
{
|
goto DoClose;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
DoClose:
|
if (engine != null && sequenceFile != null)
|
{
|
engine.ReleaseSequenceFileEx(sequenceFile);
|
sequenceFile = null;
|
}
|
|
setupSteps.Clear();
|
mainSteps.Clear();
|
cleanupSteps.Clear();
|
AllSteps = new();
|
Sequences.Clear();
|
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]
|
private void AddStep(string type)
|
{
|
try
|
{
|
var group = CurrentStepUI.step.StepGroup;
|
var targetSequence = CurrentStepUI.sequence;
|
|
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;
|
}
|
Step newStep;
|
switch (type)
|
{
|
case "Tests.PassFail":
|
newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.PassFailTest);
|
newStep.Name = DefaultStepName.PassFailTest;
|
break;
|
case "Tests.NumericLimitTest":
|
newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NumericLimitTest);
|
newStep.Name = DefaultStepName.NumericLimitTest;
|
break;
|
case "Tests.NI_MultipleNumericLimitTest":
|
newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NI_MultipleNumericLimitTest);
|
newStep.Name = DefaultStepName.NI_MultipleNumericLimitTest;
|
break;
|
case "Tests.StringValueTest":
|
newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.StringValueTest);
|
newStep.Name = DefaultStepName.StringValueTest;
|
break;
|
case "Actions.LabVIEW":
|
newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions.LabWindows/CVI":
|
newStep = engine.NewStep(AdapterKeyNames.FlexCVIAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions.C/C++ DLL":
|
newStep = engine.NewStep(AdapterKeyNames.FlexCAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions..NET":
|
newStep = engine.NewStep(AdapterKeyNames.DotNetAdapterKeyname, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions.ActiveX/COM":
|
newStep = engine.NewStep(AdapterKeyNames.AutomationAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions.None":
|
newStep = engine.NewStep(AdapterKeyNames.NoneAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions.LabVIEW NXG":
|
newStep = engine.NewStep(AdapterKeyNames.LabVIEWNXGAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
case "Actions.Python":
|
newStep = engine.NewStep(AdapterKeyNames.PythonAdapterKeyName, StepTypeStr.Action);
|
newStep.Name = DefaultStepName.Action;
|
break;
|
default:
|
return;
|
}
|
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)
|
{
|
log.Error("Insert Step Error.", ex);
|
MsgBoxHelper2.Error(ex.Message);
|
}
|
}
|
|
[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)
|
{
|
var panel = StepUI2EPO.Convert2EditPanel(stepUI);
|
control.editPanelContainer.Child = panel;
|
if (stepUI != null)
|
{
|
//window.commonP.RefreshStep(stepUI);
|
}
|
}
|
|
partial void OnCurrentSeqUIChanged(SeqUI seqUI)
|
{
|
if (seqUI != null)
|
{
|
CurrentStepUI = null;
|
RefreshData();
|
}
|
CurrentSeqTitle = $"{seqUI?.Name} {LangUtil.Get("se.steps")}";
|
}
|
}
|
}
|