using AddInPlugin; using AddInPlugin.Setting; using AddInPlugin.Util; using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.Win32; using OpenTap; using OpenTap.Addin; using OpenTap.Addin.Listener; using OpenTap.Addin.Reader; using OpenTap.Addin.Util; using OpenTap.Diagnostic; using OpenTap.Plugins.BasicSteps; using SeqEditor.UI; using SeqEditor.Util; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using UtilLib; using ViHelper; namespace OpenTapEditor; /// /// Interaction logic for MainWindow.xaml /// [ObservableObject] public partial class SeqEditorUI : UserControl, IUserInputInterface, IUserInterface { public static readonly TraceSource Log = OpenTap.Log.CreateSource("Editor"); [ObservableProperty] private ObservableCollection fileItems; [ObservableProperty] private ObservableCollection tabItems = new ObservableCollection(); [ObservableProperty] private ObservableCollection fileMenuItems = new ObservableCollection(); [ObservableProperty] private TabItemData selectedTab; public static SeqEditorUI Instance { get; private set; } public LogControl LogControl { get => logControl; } public PostUIMessageHandler uiMessageHandler { get; private set; } public SeqEditorUI() { InitializeComponent(); RefreshFileMenuItems(); OpenTap.Log.AddListener(logControl); uiMessageHandler = PostUIMessageHandler.Get(); uiMessageHandler.OnPostUIMsg += PostUIMsgHandler_OnPostUIMsg; //PostUIMsgHandler.OnPostUIMsg += PostUIMsgHandler_OnPostUIMsg; StationGlobalsManager.Register(UIStationGlobalsManager.Instance); VariableResolverFactory.Register(new DefaultVariableResolverFactory()); PropertyInfoCache.Refresh(typeof(LabViHelper), typeof(MethodVariable)); ResultSettings.Current.Add(uiMessageHandler); UserInput.SetInterface(this); Instance = this; } public void PostUIMsgHandler_OnPostUIMsg(object? sender, PostUIMsg e) { logControl.EventsLogged(new List { new Event{ Message = $"string:{e.StringData} bool:{e.BoolData} number:{e.NumberData}" } }); } private void LoadRecentFiles() { historyFile.Clear(); try { var list = XmlHelper.DeserializeFromXml>(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", "RecentFiles.xml")); if (list != null) { foreach (var file in list) { historyFile.Enqueue(file); } } } catch { historyFile = new Queue(10); } } private void RefreshFileMenuItems() { FileMenuItems.Clear(); var child = new MenuItem() { Tag = "新建" }; child.SetValue(MenuItem.HeaderProperty, new DynamicResourceExtension("新建").ProvideValue(null)); child.Click += (sender, e) => { var testPlan = new TestPlan() { VisualPath = new Guid().ToString() }; var tabItem = new TabItemData { Content = new SequencePanel(testPlan) { HasChanged = true }, TestPlan = testPlan }; TabItems.Add(tabItem); SelectedTab = tabItem; }; FileMenuItems.Add(child); child = new MenuItem() { Tag = "打开" }; child.SetValue(MenuItem.HeaderProperty, new DynamicResourceExtension("打开").ProvideValue(null)); child.Click += MenuItem_Click; FileMenuItems.Add(child); var panel = SelectedTab?.Content as SequencePanel; if (panel != null) { child = new MenuItem() { Header = $"保存{panel.TabName}", InputGestureText = "Ctrl + S" }; child.Click += (sender, e) => { if (panel.TrySaveTestStep(this.CheckCanSaveAs)) { } StationGlobalsManager.WriteToLocal(UIStationGlobalsManager.Instance.Datasource); }; FileMenuItems.Add(child); } else { child = new MenuItem() { Header = $"保存", IsEnabled = false }; } if (panel != null) { child = new MenuItem() { Header = $"另存{panel.TabName}", }; child.Click += (sender, e) => { panel.TrySaveAs(this.CheckCanSaveAs); StationGlobalsManager.WriteToLocal(UIStationGlobalsManager.Instance.Datasource); }; FileMenuItems.Add(child); } else { child = new MenuItem() { Header = $"另存", IsEnabled = false }; } } private bool CheckCanSaveAs(string fileName) { var item = TabItems.FirstOrDefault(i => i.TestPlan.Path == fileName); if (item != null) { MessageBox.Show($"文件 {fileName} 已经打开,无法另存为同名文件", "错误", MessageBoxButton.OK, MessageBoxImage.Error); return false; } return true; } private void SaveRecentFiles() { var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config"); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var path = Path.Combine(dir, "RecentFiles.xml"); XmlHelper.SerializeToXml(path, historyFile); } private Queue historyFile = new Queue(10); public static Type GetEnumerableElementType(Type enumType) { if (enumType.IsArray) return enumType.GetElementType(); var ienumInterface = enumType.GetInterface("IEnumerable`1") ?? enumType; if (ienumInterface != null) return ienumInterface.GetGenericArguments().FirstOrDefault(); return typeof(object); } private void OpenStepSettingWin() { var win = new StepWindow() { Owner = Window.GetWindow(this) }; if (win.ShowDialog() == true) { } } private void RefreshUI() { Application.Current.Resources["GlobalFontSize"] = StationSettings.Current.FontSize; LangUtil.LoadLang(); } private void TryOpenStationSetting() { try { var setting = TypeData.GetDerivedTypes() .Where(x => x.CanCreateInstance && (x.GetAttribute()?.Browsable ?? true)) .OfType() .FirstOrDefault(x => x.Name == typeof(StationSettings).FullName); if (setting == null) { return; } ComponentSettings obj = null; obj = ComponentSettings.GetCurrent(setting.Load()); setting = TypeData.GetDerivedTypes() .Where(x => x.CanCreateInstance && (x.GetAttribute()?.Browsable ?? true)) .OfType() .FirstOrDefault(x => x.Name == typeof(StationGlobalsSetting).FullName); var sss = ComponentSettings.GetCurrent(setting.Load()); var setgroup = setting.GetAttribute()?.GroupName ?? "Settings"; var name = setting.GetDisplayAttribute().Name; StationSettingWin win = new StationSettingWin { Owner = Window.GetWindow(this) }; if (win.Open(obj) == true) { ComponentSettings.SaveAllCurrentSettings(); RefreshUI(); } } catch (Exception ex) { MessageBox.Show(ex.Message); } //UISettiingWin win = new UISettiingWin //{ // Owner = this //}; //win.ShowDialog(); } private void MenuItem_Click(object sender, RoutedEventArgs e) { var item = sender as MenuItem; if (item?.Tag?.ToString() == "UISetting") { TryOpenStationSetting(); return; } switch (item?.Tag) { case "打开": TryOpenTestPlanNew(); break; case "保存": // TrySaveTestStep(); break; case "另存": break; case "自定义测试步骤": OpenStepSettingWin(); break; case "openSetting": var setting = new SettingWin() { Owner = Window.GetWindow(this) }; setting.ShowDialog(); break; default: break; } } private void self_Closing(object sender, System.ComponentModel.CancelEventArgs e) { /// 保存一下StationGlobals变量 UIStationGlobalsManager.Instance.WriteToLocal(UIStationGlobalsManager.Instance.Datasource); } private void CloseTabItem_Click(object sender, RoutedEventArgs e) { try { if (sender is Button button && button.Tag is TabItemData tabItem) { if (tabItem.Content is SequencePanel editor) { if (editor.HasChanged) { if (SelectedTab != tabItem) { SelectedTab = tabItem; } var res = MessageBox.Show("是否保存?", "提示", MessageBoxButton.YesNoCancel); if (res == MessageBoxResult.Cancel) { return; } if (res == MessageBoxResult.Yes) { if (!editor.TrySaveTestStep(this.CheckCanSaveAs)) { return; } } } editor.Close(); TabItems.Remove(tabItem); } else if (tabItem.Content is ExecutionPanel executiion) { if (executiion.IsRunning) { if (SelectedTab != tabItem) { SelectedTab = tabItem; } var res = MessageBox.Show("运行中是否终止?", "提示", MessageBoxButton.YesNo); if (res == MessageBoxResult.No) { return; } if (res == MessageBoxResult.Yes) { executiion.StopRunTestPlan(); } } executiion.Close(); TabItems.Remove(tabItem); } } } catch (Exception ex) { } } //private Dictionary OpendPlanItem = new Dictionary(); private void TryOpenTestPlanNew() { OpenFileDialog ofd = new OpenFileDialog() { Filter = "Test Plan|*.TapPlan", DefaultExt = ".TapPlan" }; if (ofd.ShowDialog() == true) { try { var item = TabItems.FirstOrDefault(i => i.TestPlan.Path == ofd.FileName); if (item != null) { SelectedTab = item; } else { //var testPlan = TestPlan.Load(ofd.FileName); var testPlan = TestPlanReader.ReadTestPlan(ofd.FileName); BreakConditionProperty.SetBreakCondition(testPlan, BreakCondition.BreakOnFail); var tabItem = new TabItemData { Content = new SequencePanel(testPlan), TestPlan = testPlan }; TabItems.Add(tabItem); SelectedTab = tabItem; } // historyFile.Enqueue(ofd.FileName); // SaveRecentFiles(); } catch (Exception ex) { Log.Error("Open TestPlan Error! {0}", ex); MessageBox.Show($"打开测试计划失败: {ex.Message} {ex.StackTrace}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } } partial void OnSelectedTabChanged(TabItemData value) { RefreshFileMenuItems(); } public void RequestUserInput(object dataObject, TimeSpan Timeout, bool modal) { if (dataObject is DialogRequest req) { Dispatcher.BeginInvoke(() => { if (req.Buttons == InputButtons.OkCancel) { var res = MessageBox.Show(req.Message, req.Name, MessageBoxButton.OKCancel); req.Input2 = res == MessageBoxResult.OK ? WaitForInputResult2.Ok : WaitForInputResult2.Cancel; } else { var res = MessageBox.Show(req.Message, req.Name, MessageBoxButton.YesNo); req.Input1 = res == MessageBoxResult.Yes ? WaitForInputResult1.Yes : WaitForInputResult1.No; } }).Wait(); } else if (dataObject is OpenTap.TestPlan.PlanLoadError err) { Dispatcher.BeginInvoke(() => { var res = MessageBox.Show(err.Message, err.Name, MessageBoxButton.OKCancel); err.Response = res == MessageBoxResult.OK ? TestPlan.PlanLoadErrorResponse.Ignore : TestPlan.PlanLoadErrorResponse.Abort; }).Wait(); } } public void NotifyChanged(object obj, string property) { Dispatcher.BeginInvoke(() => { if (obj is TestPlan plan) { if (SelectedTab?.Content is SequencePanel currentTab && plan == currentTab.Plan && property != "Path" && property != "Name") { currentTab.HasChanged = true; } } else if (obj is ITestStep step) { if (SelectedTab?.Content is SequencePanel currentTab && step == currentTab.settingView.Step) { currentTab.HasChanged = true; } } }); } public void RunTestPlan(TestPlan plan, string seqName, RuningMode mode) { var runningPlan = plan.DeepClone(); var exe = new ExecutionPanel(runningPlan, seqName); var tabItem = new TabItemData { Content = exe, TestPlan = runningPlan }; TabItems.Add(tabItem); SelectedTab = tabItem; exe.RunTestPlan(mode); } private void self_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) { if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.S) { if (SelectedTab?.Content is SequencePanel panel && panel.TrySaveTestStep(this.CheckCanSaveAs)) { StationGlobalsManager.WriteToLocal(UIStationGlobalsManager.Instance.Datasource); } } } private void self_Loaded(object sender, RoutedEventArgs e) { try { LvlibpLoader.PreLoad(); Log.Debug("PreLoad completed."); } catch (Exception ex) { Log.Error("PreLoad error. {0}", ex); } } private void MenuItem_Click_1(object sender, RoutedEventArgs e) { GC.Collect(); } }