using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Media; using System.Xml.Linq; using DTS.Common; using DTS.Common.Base; using DTS.Common.Classes.Viewer.TestMetadata; using DTS.Common.Enums.Sensors; using DTS.Common.Events; using DTS.Common.Interactivity; using DTS.Common.Interface; using DTS.Common.Interface.TestDefinition; using DTS.Common.Strings; using DTS.Common.Utilities.Logging; using DTS.Common.Utils; using Prism.Events; using Prism.Regions; using Unity; // ReSharper disable AutoPropertyCanBeMadeGetOnly.Local // ReSharper disable CheckNamespace // ReSharper disable NotAccessedField.Local // ReSharper disable InconsistentNaming // ReSharper disable UnusedMember.Local // ReSharper disable RedundantDefaultMemberInitializer // ReSharper disable RedundantAssignment namespace DTS.Viewer.GraphList { public class ExportGraphMainViewModel : BaseViewModel, IExportGraphMainViewModel { public IFilterView FilterView { get; private set; } public IExportGraphMainView View { get; set; } public IBaseViewModel Parent { get; set; } public bool SettingChildNodesToTrue { get; set; } public bool SettingOrResettingChildNodes { get; set; } public bool SettingPeerNodeToTrue { get; set; } public bool SettingItemsBetween { get; set; } public bool ResettingAllItems { get; set; } private IEventAggregator _eventAggregator { get; set; } private IUnityContainer _unityContainer { get; set; } private bool _showIsoCodes = false; public InteractionRequest NotificationRequest { get; private set; } public new InteractionRequest ConfirmationRequest { get; private set; } /// /// Creates a new instance of the ExportGraphMainViewModel. /// /// The ExportGraphMainView interface. /// The logical placeholder defined within the application's UI (in the shell or within views) into which views are displayed. /// The EventAggregator which allows different components to publish/subscribe to events without being coupled to each other. /// The unityContainer. public ExportGraphMainViewModel(IExportGraphMainView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer) : base(regionManager, eventAggregator, unityContainer) { View = view; View.DataContext = this; NotificationRequest = new InteractionRequest(); ConfirmationRequest = new InteractionRequest(); _eventAggregator = eventAggregator; _unityContainer = unityContainer; } #region Const private const string testChannels = "Test Channels"; private const string EventNumber = "Event Number"; private const string calculatedChannels = "Calculated Channels"; private const string graphChannels = "Graph Channels: "; #endregion #region Colors private readonly List _graphColors = new List { Colors.Transparent, Colors.Blue, Colors.Red, Colors.Green, Colors.BlueViolet, Colors.Brown, Colors.Aqua, Colors.Lime, Colors.Gray, Colors.YellowGreen, Colors.Black }; /// /// Assign unused color to selected/locked channel /// /// private Color GetNextColor() { var nextColor = Colors.Transparent; var channelCount = (LockedChannelList.Any() ? LockedChannelList.Count : 0) + (SelectedChannelList.Any() ? SelectedChannelList.Count : 0); if (channelCount >= _graphColors.Count) { var nextColorIndex = channelCount % _graphColors.Count + 1; if (nextColorIndex >= _graphColors.Count) { nextColorIndex = 1; } nextColor = _graphColors[nextColorIndex]; } else { var usedColors = new List(); usedColors.AddRange(LockedChannelList.Select(ch => ch.ChannelColor).ToList()); usedColors.AddRange(SelectedChannelList.Select(ch => ch.ChannelColor).ToList()); nextColor = _graphColors.Find(c1 => usedColors.TrueForAll(c2 => c2 != c1)); } return nextColor; } #endregion #region Methods public override void Initialize() { } private bool _lockedOnly = false; //only published locked channels public override void Initialize(object parameter) { Parent = (IBaseViewModel)parameter; if (Parent is IPSDReportMainViewModel) { _lockedOnly = true; } // only put checked channels in the report FilterView = GetFilterView(this); Subscribe(); } /// /// Reset all lists and publish changes /// private void CleanSelection() { LockedChannelList = new List(); ChannelList = new ObservableCollection(); FilteredChannelList = new ObservableCollection(); SelectedChannelList = new List(); _lastIndexChecked = 0; _eventAggregator.GetEvent().Publish(new GraphClearNotificationArg { GraphClear = true, ParentVM = Parent }); PublishSelectedChannels(); SelectedGroupName = string.Empty; GC.Collect(); } /// /// Format the Channel Display Name based on the isoCode setting /// /// /// /// /// private string FormatChannelDisplayName(string channelName2, string channelDescriptionString, string isoCode) { return _showIsoCodes ? $"{channelName2} {channelDescriptionString} {Environment.NewLine} {isoCode}" : $"{channelName2} {channelDescriptionString}"; } //hold onto the test summaries for reloads private List testSummaries; /// /// Read all graphs, calculated channels and channels for the selected test /// and select and display first group or channel /// /// private void OnTestSummaryChanged(TestSummaryChangeNotificationArg arg) { if (Parent != arg?.ParentVM) return; //43387 Don't build the TestId tree until all of the tests have been selected if (arg?.SummaryList.Count() != arg?.TotalSummaryCount) return; var list = arg?.SummaryList; testSummaries = list; CleanSelection(); //clean every time, otherwise channels weren't being removed on test deselection var total = 0; //this list will hold test setups we want to remove var listToRemove = new List(); if (list != null && list.Any()) { foreach (var l in list) { //for now if there are no modules, remove the test from the list if (l.TestMetadata == null || null == l.TestMetadata.TestRun || 0 == l.TestMetadata.TestRun.Modules.Count) { APILogger.Log($"Test {l.SetupName} - {l.TestMetadata.TestRun.FilePath} has no modules, skipping"); listToRemove.Add(l); continue; } if (l.Channels.Any() && l.Channels.FirstOrDefault() == null) { // LOAD NOW! Utils.SetChannelInfo(l.TestMetadata, Path.GetDirectoryName(l.TestMetadata.TestRun.FilePath), DTS.Serialization.SliceRaw.File.PersistentChannel.GetIsoCode); l.Channels = l.TestMetadata.TestRun.Channels; l.Graphs = l.TestMetadata.TestSetup.TestGraphs; l.CalculatedChannels = l.TestMetadata.TestRun.CalculatedChannels; } foreach (var graph in l.Graphs) { //12017 Viewer shows "Graphs 1/2" when there is only 1 channel //this issue was caused by an included graph with no channels. if (graph.ChannelIds.Any()) { total++; } } if (null != l.CalculatedChannels) { total += l.CalculatedChannels.Count; } } } if (listToRemove.Any()) { foreach( var l in listToRemove) { list?.Remove(l); } } if (list != null && list.Count <= 0) return; var summaryList = list.ToList(); foreach (var ts in summaryList) { var testName = ts.Id + " " + ts.SetupName + " " + ts.DataType + " " + Utils.FormatTimeStamp(ts.TimeStamp); if (ts.Graphs.Count > 0) { foreach (var graph in ts.Graphs) { foreach (var gch in graph.Channels.OrderBy(gch => gch.AbsoluteDisplayOrder).ThenBy(gch => gch.Number)) { if (ChannelList.Any(x => x.Equals(gch))) continue; gch.Group = testName; gch.SubGroup = graphChannels + graph.Name; gch.IsGraphChannel = true; gch.GraphName = graph.Name; gch.ChannelDisplayName = gch.ChannelName2 + " " + gch.ChannelDescriptionString; gch.Parent = this; gch.ChannelColor = Colors.Transparent; gch.CanSelectChannel = false; gch.IsSelected = false; gch.IsLocked = false; gch.CanSelectChannel = true; //Select first group if (ChannelList.Count == 0) { SelectedGroupName = gch.SubGroup.Trim(); } ChannelList.Add(gch); } } } if ((ts.CalculatedChannels != null) && (ts.CalculatedChannels.Count > 0)) { foreach (var cch in ts.CalculatedChannels.OrderBy(cch => cch.AbsoluteDisplayOrder).ThenBy(cch => cch.Number)) { if (ChannelList.Any(x => x.Equals(cch))) continue; cch.Group = testName; cch.SubGroup = calculatedChannels; cch.IsGraphChannel = false; cch.GraphName = string.Empty; cch.ChannelDisplayName = cch.ChannelName2 + " " + cch.ChannelDescriptionString; cch.IsCalculatedChannel = true; cch.Parent = this; cch.ChannelColor = Colors.Transparent; cch.CanSelectChannel = false; cch.IsSelected = false; cch.IsLocked = false; cch.CanSelectChannel = true; //Or select first calculated channel if (ChannelList.Count == 0) { cch.IsSelected = true; } ChannelList.Add(cch); } } if (ts.Channels.Count > 0) { var tsChannels = ts.Channels.OrderBy(ch => ch.AbsoluteDisplayOrder).ThenBy(ch => ch.Number).ToList(); for (int i = 0; i < tsChannels.Count - 1; i++) { if (tsChannels[i].AbsoluteDisplayOrder == tsChannels[i + 1].AbsoluteDisplayOrder && tsChannels[i].Number == tsChannels[i + 1].Number) { switch (calibrationBehaviorSetting) { case CalibrationBehaviors.LinearIfAvailable: tsChannels.RemoveAt(i); i--; break; case CalibrationBehaviors.NonLinearIfAvailable: tsChannels.RemoveAt(i + 1); break; case CalibrationBehaviors.UseBothIfAvailable: tsChannels[i].ChannelDescriptionString += " (NonLinear)"; tsChannels[i + 1].ChannelDescriptionString += " (Linear)"; break; } } } total += tsChannels.Count; foreach (var ch in tsChannels) { if (ChannelList.Any(x => x.Equals(ch))) continue; ch.Group = testName; ch.SubGroup = testChannels; ch.IsGraphChannel = false; ch.GraphName = string.Empty; var channelDescription = ch.ChannelDescriptionString; if (SensorConstants.IsTestSpecificEmbedded(channelDescription)) { channelDescription = Strings.Table_NA; } ch.ChannelDisplayName = FormatChannelDisplayName(ch.ChannelName2, channelDescription, ch.IsoCode); ch.Parent = this; ch.ChannelColor = Colors.Transparent; ch.CanSelectChannel = false; ch.IsSelected = false; ch.IsLocked = false; ch.CanSelectChannel = true; //Or select first channel if (ChannelList.Count == 0) { ch.IsSelected = true; } ChannelList.Add(ch); } } } ChannelList.CollectionChanged += GraphList_CollectionChanged; FilteredChannelList = new ObservableCollection(ChannelList); TestChannelsTree.CollectionChanged += TestChannelsTree_CollectionChanged; _eventAggregator.GetEvent().Publish(new GraphLoadedCountNotificationArg { LoadedCount = total, ParentVM = Parent }); if (ChannelList.Any()) { var treeChannels = ChannelList.ToList(); TestChannelsTree = GetTestChannelsTree(treeChannels); TestIdsTree = GetTestIdsTree(TestChannelsTree, summaryList); foreach (var treeViewChannels in TestChannelsTree) { treeViewChannels.IsExpanded = false; } //temp var parent = TestChannelsTree?.FirstOrDefault()?.Groups?.FirstOrDefault()?.Parent; foreach (var testId in TestIdsTree) { testId.Parent = parent; foreach (var group in testId.Events) { group.Parent = parent; } } if (!string.IsNullOrEmpty(SelectedGroupName)) { var group = (from t in TestChannelsTree from g in t.Groups where g.Name == SelectedGroupName.Replace(graphChannels, string.Empty) select g).FirstOrDefault(); if (group != null) { AddSelectedGroup(group); } } } IsFilterEnabled = _channelList.Count > 0; } /// /// Check changes to Test Modifications to see whether we need to withhold user input /// private void OnTestModificationsChanged(ITestModificationModel testModificationModel) { if (testModificationModel != null) { TestModified = testModificationModel.IsModified; } } /// /// Subscribe for events /// private void Subscribe() { _eventAggregator.GetEvent().Subscribe(OnRaiseNotification); _eventAggregator.GetEvent().Subscribe(OnFilterChanged); _eventAggregator.GetEvent().Subscribe(OnTestSummaryChanged); _eventAggregator.GetEvent().Subscribe(OnTestModificationsChanged); _eventAggregator.GetEvent().Subscribe(OnCalibrationBehaviorSettingChanged); _eventAggregator.GetEvent().Subscribe(OnCalibrationBehaviorSettableInViewerChanged); _eventAggregator.GetEvent().Subscribe(OnChannelCodesViewChangedEvent); _eventAggregator.GetEvent().Subscribe(OnClearSelectedExports); } private void OnCalibrationBehaviorSettableInViewerChanged(bool cbSettable) { } private void OnChannelCodesViewChangedEvent(DTS.Common.Enums.IsoViewMode viewMode) => _showIsoCodes = (viewMode == Common.Enums.IsoViewMode.ISOAndUserCode || viewMode == Common.Enums.IsoViewMode.ISOOnly); private CalibrationBehaviors calibrationBehaviorSetting { get; set; } = CalibrationBehaviors.NonLinearIfAvailable; private void OnCalibrationBehaviorSettingChanged(CalibrationBehaviors cb) { calibrationBehaviorSetting = cb; if (null != testSummaries) { OnTestSummaryChanged(new TestSummaryChangeNotificationArg { SummaryList = testSummaries, ParentVM = Parent }); } } #region Filter /// /// Filter Data Event /// /// Filter value public void OnFilterChanged(FilterParameterArgs args) { if (((IFilterViewModel)FilterView.DataContext).Parent == this) { FilteredTestIdsTree = string.IsNullOrEmpty(args.Param) ? new ObservableCollection(TestIdsTree) : new ObservableCollection((from x in TestIdsTree where x.Name.ToLower().Contains(args.Param.ToLower()) select x).ToList()); } } #endregion Filter #region Override /// /// Private Event handler for RaiseNotification event. /// private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle) { // Notification object expects a NotificationContentEventArgsWithoutTitle object and a Title string. var eventArgsWithoutTitle = new NotificationContentEventArgs(eventArgsWithTitle.Message, eventArgsWithTitle.MessageDetails, eventArgsWithTitle.Image); NotificationRequest.Raise(new Notification { Content = eventArgsWithoutTitle, Title = eventArgsWithTitle.Title }); } /// /// ? I thik it's not beed used /// public override void Activated() { var fp = new FilterParameterArgs { Param = string.Empty, Requester = this }; _eventAggregator.GetEvent().Publish(fp); } #endregion Override /// /// Publish Locked Channels /// /// /// Publish Selected and/or locked Channels /// public void PublishSelectedChannels() { var list = new List(); if (LockedChannelList.Any()) list.AddRange(LockedChannelList); if (!_lockedOnly && SelectedChannelList.Any()) list.AddRange(SelectedChannelList); var count = list.Count; _eventAggregator.GetEvent().Publish(new GraphSelectedChannelCountNotificationArg { SelectedChannelCount = count, ParentVM = Parent }); _eventAggregator.GetEvent().Publish(new GraphSelectedChannelsNotificationArg { SelectedChannels = list, ParentVM = Parent }); } /// /// Publish Selected and/or locked Events /// public void PublishSelectedEvents() { var list = new BindingList(); if (!_lockedOnly && SelectedEventList.Any()) { foreach (var sel in SelectedEventList) { list.Add(sel); } } var count = list.Count; _eventAggregator.GetEvent().Publish(new GraphSelectedEventCountNotificationArg { SelectedEventCount = count, ParentVM = Parent }); _eventAggregator.GetEvent().Publish(new GraphSelectedEventsNotificationArg { SelectedEvents = list, ParentVM = Parent }); } /// /// Load Filter View /// /// /// private IFilterView GetFilterView(IBaseViewModel parent) { var view = _unityContainer.Resolve(); var viewModel = _unityContainer.Resolve(); view.DataContext = viewModel; viewModel.Initialize(parent); return view; } #endregion #region Reset Functions private void ResetSelectedChannelColor() { foreach (var ch in SelectedChannelList) { if (ch.IsLocked) continue; ch.ChannelColor = Colors.Transparent; ch.CanSelectChannel = true; } } /// /// Reset all selected channels prior to selecting new channel or group /// private void ResetSelected() { ResetSelected(string.Empty); } private void ResetSelected(string eventName) { foreach (var test in TestIdsTree) { foreach (var e in test.Events) { if (!string.IsNullOrEmpty(eventName) && e.Name == eventName) continue; e.IsSelected = false; } } } #endregion Reset Functions #region Add Selected/Locked Channel #region Locked Channel public void AddLockedGroupChannels(string testName, string groupName, List channels, bool isLocked) { _eventAggregator.GetEvent().Publish(true); foreach (var channel in channels) { if (isLocked) { if (SelectedChannelList.Contains(channel)) { SelectedChannelList.Remove(channel); } if (LockedChannelList.Contains(channel)) continue; channel.CanSelectChannel = false; channel.IsLocked = true; channel.CanSelectChannel = true; LockedChannelList.Add(channel); if (channel.ChannelColor == Colors.Transparent) { channel.ChannelColor = GetNextColor(); } } else { if (!LockedChannelList.Contains(channel)) continue; LockedChannelList.Remove(channel); } } PublishSelectedChannels(); if (!LockedChannelList.Any() && !SelectedChannelList.Any()) { var group = (from t in TestChannelsTree from g in t.Groups where g.TestName == testName && g.Name == groupName select g).FirstOrDefault(); if (group != null) { group.IsSelected = true; } } else { if (SelectedChannelList.Any()) { PublishSelectedChannels(); } } UpdateChannelLocks(); _eventAggregator.GetEvent().Publish(false); } public void AddLockedChannel(ITestChannel channel, bool isLocked) { _eventAggregator.GetEvent().Publish(true); if (isLocked) { if (SelectedChannelList.Contains(channel)) { SelectedChannelList.Remove(channel); } if (!LockedChannelList.Contains(channel)) { channel.CanSelectChannel = false; channel.IsLocked = true; channel.CanSelectChannel = true; LockedChannelList.Add(channel); if (channel.ChannelColor == Colors.Transparent) { channel.ChannelColor = GetNextColor(); } } } else { if (LockedChannelList.Contains(channel)) { LockedChannelList.Remove(channel); } // if there are no selected or locked channels add unlocked channel to selected list if (!SelectedChannelList.Any()) { if (!LockedChannelList.Exists(x => x.IsSelected)) { AddSelectedChannel(channel, true); } } } UpdateChannelLocks(); PublishSelectedChannels(); _eventAggregator.GetEvent().Publish(false); } private const int MAX_LOCKED_CHANNELS = 8; private void UpdateChannelLocks() { var canLock = LockedChannelList.Count < MAX_LOCKED_CHANNELS; foreach (var treeChannel in TestChannelsTree) { foreach (var group in treeChannel.Groups) { if (group.IsGraph) { if (group.IsLocked) { continue; } group.CanLock = group.Channels.Count + LockedChannelList.Count <= MAX_LOCKED_CHANNELS; } foreach (var channel in group.Channels) { if (channel.IsLocked) { continue; } channel.CanLock = canLock; } } } } #endregion Locked Channel #region Selected Channel public void AddSelectedGroupChannels(string groupName, List channels) { _eventAggregator.GetEvent().Publish(true); ResetSelectedChannelColor(); ResetSelected(groupName); SelectedChannelList = new List(); foreach (var channel in channels) { SelectedChannelList.Add(channel); if (channel.ChannelColor == Colors.Transparent) { channel.ChannelColor = GetNextColor(); } } PublishSelectedChannels(); _eventAggregator.GetEvent().Publish(false); } public void AddSelectedGroup(TestGroup group) { _eventAggregator.GetEvent().Publish(true); group.IsSelected = true; _eventAggregator.GetEvent().Publish(false); } /// /// Add selected channel to the list or select a group (graph) of channels /// /// /// public void AddSelectedChannel(ITestChannel channel, bool reset) { if (channel.IsLocked && LockedChannelList.Contains(channel)) { ResetSelectedChannelColor(); SelectedChannelList = new List(); PublishSelectedChannels(); return; } if (channel.IsSelected && SelectedChannelList.Contains(channel)) return; if (channel.IsGraphChannel) { var group = (from t in TestChannelsTree from g in t.Groups where g.TestName == channel.Group && g.Name == channel.GraphName select g).FirstOrDefault(); if (group != null) { AddSelectedGroup(group); } } else { _eventAggregator.GetEvent().Publish(true); if (reset) { SelectedChannelList = new List(); ResetSelected(); SelectedGroupName = string.Empty; } SelectedChannelList.Add(channel); if (channel.ChannelColor == Colors.Transparent) { channel.ChannelColor = GetNextColor(); } PublishSelectedChannels(); _eventAggregator.GetEvent().Publish(false); } } public void AddSelectedChannel(ITestChannel channel) { if (channel.IsLocked && LockedChannelList.Contains(channel)) { //ResetSelected(); SelectedChannelList = new List(); PublishSelectedChannels(); return; } if (channel.IsSelected && SelectedChannelList.Contains(channel)) return; if (channel.IsGraphChannel) { var group = (from t in TestChannelsTree from g in t.Groups where g.TestName == channel.Group && g.Name == channel.GraphName select g).FirstOrDefault(); if (group != null) { AddSelectedGroup(group); } } else { _eventAggregator.GetEvent().Publish(true); SelectedChannelList = new List(); ResetSelected(); SelectedGroupName = string.Empty; SelectedChannelList.Add(channel); if (channel.ChannelColor == Colors.Transparent) { channel.ChannelColor = GetNextColor(); } PublishSelectedChannels(); _eventAggregator.GetEvent().Publish(false); } } #endregion Selected Channel #region Locked Event public void AddLockedEvents(string testName, string groupName, List events, bool isLocked) { _eventAggregator.GetEvent().Publish(true); foreach (var evnt in events) { if (isLocked) { if (SelectedEventList.Contains(evnt)) { SelectedEventList.Remove(evnt); } if (LockedEventList.Contains(evnt)) continue; //evnt.CanSelectEvent = false; evnt.IsLocked = true; //evnt.CanSelectEvent = true; LockedEventList.Add(evnt); //if (evnt.EventColor == Colors.Transparent) { evnt.EventColor = GetNextColor(); } } else { if (!LockedEventList.Contains(evnt)) continue; LockedEventList.Remove(evnt); } } PublishSelectedEvents(); if (!LockedEventList.Any() && !SelectedEventList.Any()) { var group = (from t in TestChannelsTree from g in t.Groups where g.TestName == testName && g.Name == groupName select g).FirstOrDefault(); if (group != null) { group.IsSelected = true; } } else { if (SelectedEventList.Any()) { PublishSelectedEvents(); } } _eventAggregator.GetEvent().Publish(false); } #endregion Locked Event #region Id Event private void OnClearSelectedExports(ClearSelectedExportsArg arg) { SelectedEventList.Clear(); } public void AddToSelectedEvents(string groupName, List events) { _eventAggregator.GetEvent().Publish(true); foreach (var e in events) { if (!SelectedEventList.Exists(item => item.TestItem == e.TestItem && item.Name == e.Name)) { SelectedEventList.Add(e); } } PublishSelectedEvents(); _eventAggregator.GetEvent().Publish(false); } public void RemoveFromSelectedEvents(string groupName, List events) { _eventAggregator.GetEvent().Publish(true); foreach (var e in events) { var match = SelectedEventList.Find(item => item.TestItem == e.TestItem && item.Name == e.Name); if (null != match) { SelectedEventList.Remove(match); } } PublishSelectedEvents(); _eventAggregator.GetEvent().Publish(false); } public void SetItemsBetween(int startTreeIndex, int endTreeIndex) { foreach (var testId in TestIdsTree) { foreach (var e in testId.Events) { if (((e.TreeIndex >= startTreeIndex) && (e.TreeIndex <= endTreeIndex)) || ((e.TreeIndex <= startTreeIndex) && (e.TreeIndex >= endTreeIndex))) { e.IsSelected = true; } } } } public void ResetAllItems() { foreach (var testId in TestIdsTree) { foreach (var e in testId.Events) { //Don't bother setting it to False if it is already if (e.IsSelected) { e.IsSelected = false; } } } } public void SetLastIndexChecked(int index) { _lastIndexChecked = index; } #endregion Id Event #endregion Add Selected/Locked Channel #region ContextRegion public object ContextGraphMainRegion { get => ((ExportGraphMainView)View).GraphMainRegion.DataContext; set { ((ExportGraphMainView)View).GraphMainRegion.DataContext = value; OnPropertyChanged("ContextGraphMainRegion"); } } #endregion #region Properties private bool _isFilterEnabled = false; public bool IsFilterEnabled { get => _isFilterEnabled; set { _isFilterEnabled = value; OnPropertyChanged("IsFilterEnabled"); } } #region Selected/Locked Group private string _selectedGroupName = string.Empty; public string SelectedGroupName { get => _selectedGroupName; set { _selectedGroupName = value; OnPropertyChanged("SelectedGroupName"); } } private string _lockedGroupName = string.Empty; public string LockedGroupName { get => _lockedGroupName; set { _lockedGroupName = value; OnPropertyChanged("LockedGroupName"); } } #endregion Selected/Locked Group #region Lists private List _lockedChannelList = new List(); public List LockedChannelList { get => _lockedChannelList; set { _lockedChannelList = value; OnPropertyChanged("LockedChannelList"); } } private List _lockedEventList = new List(); public List LockedEventList { get => _lockedEventList; set { _lockedEventList = value; OnPropertyChanged("LockedEventList"); } } private List _selectedChannelList = new List(); public List SelectedChannelList { get => _selectedChannelList; set { _selectedChannelList = value; OnPropertyChanged("SelectedChannelList"); } } private List _selectedEventList = new List(); public List SelectedEventList { get => _selectedEventList; set { _selectedEventList = value; OnPropertyChanged("SelectedEventList"); } } private int _lastIndexChecked = 0; public int LastIndexChecked { get { return _lastIndexChecked; } } #endregion Lists #region ObservableCollection private ObservableCollection _channelList = new ObservableCollection(); public ObservableCollection ChannelList { get => _channelList; set { _channelList = value; IsFilterEnabled = _channelList.Count > 0; FilteredChannelList = new ObservableCollection(_channelList); OnPropertyChanged("ChannelList"); } } private ObservableCollection _filteredChannelList = new ObservableCollection(); public ObservableCollection FilteredChannelList { get => _filteredChannelList; set { _filteredChannelList = value; TestChannelsTree = GetTestChannelsTree(_filteredChannelList.ToList()); OnPropertyChanged("FilteredChannelList"); } } private ObservableCollection _testChannelsTree = new ObservableCollection(); /// /// Main treeview object /// public ObservableCollection TestChannelsTree { get => _testChannelsTree; set { _testChannelsTree = value; OnPropertyChanged("TestChannelsTree"); } } private ObservableCollection _testIdsTree = new ObservableCollection(); /// /// Main treeview object /// public ObservableCollection TestIdsTree { get => _testIdsTree; set { _testIdsTree = value; FilteredTestIdsTree = _testIdsTree; OnPropertyChanged("TestIdsTree"); } } private ObservableCollection _filteredTestIdsTree = new ObservableCollection(); public ObservableCollection FilteredTestIdsTree { get => _filteredTestIdsTree; set { _filteredTestIdsTree = value; OnPropertyChanged("FilteredTestIdsTree"); } } #endregion ObservableCollection #region ObservableCollection Extension public void TestChannelsTree_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (INotifyPropertyChanged item in e.OldItems) item.PropertyChanged -= TestChannelsTree_PropertyChanged; } if (e.NewItems != null) { foreach (INotifyPropertyChanged item in e.NewItems) { item.PropertyChanged += TestChannelsTree_PropertyChanged; } } } private void TestChannelsTree_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != "TestChannelsTree") { } } public void GraphList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (INotifyPropertyChanged item in e.OldItems) item.PropertyChanged -= GraphList_PropertyChanged; } if (e.NewItems != null) { foreach (INotifyPropertyChanged item in e.NewItems) { item.PropertyChanged += GraphList_PropertyChanged; } } } private void GraphList_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != "ChannelList") { } } #endregion ObservableCollection Extension #region PropertyChanged /// ///Occurs when a property value changes. /// public new event PropertyChangedEventHandler PropertyChanged; private new void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion PropertyChanged /// /// Gets the HeaderInfo. /// public string HeaderInfo => "GraphRegion"; public new bool IsBusy { get; set; } public new bool IsDirty { get; set; } private bool _testModified = false; public bool TestModified { get => _testModified; set { _testModified = value; OnPropertyChanged("TestModified"); } } #endregion /// /// Build the tree form list /// /// Test Channel list /// tree private ObservableCollection GetTestChannelsTree(List list) { if (!list.Any()) return new ObservableCollection(); var result = (from t in list group t.TestSetupName by t.Group into test select new TreeViewChannels { Name = test.Key, Groups = new ObservableCollection(from t in list where t.Group == test.Key group t.Group by t.SubGroup into g select new TestGroup { TestName = test.Key, DisplayName = g.Key + " [ " + list.Count(ch => ch.Group == test.Key && ch.SubGroup == g.Key) + " Channels]", Path = test.Key + "|" + g.Key + " [ " + list.Count(ch => ch.Group == test.Key && ch.SubGroup == g.Key) + " Channels]", Name = g.Key.Replace(graphChannels, string.Empty), IsGraph = g.Key.StartsWith("Graph"), Channels = new ObservableCollection(list.Where(ch => ch.Group == test.Key && ch.SubGroup == g.Key).OrderBy(ch => ch.AbsoluteDisplayOrder).ThenBy(ch => ch.Number)), Parent = this }) }).ToList(); foreach (var tvc in result) { foreach (var g in tvc.Groups) { g.DTSFile = $"{g.Channels[0].BinaryFilePath}\\{g.Channels[0].TestId}.dts"; } } return new ObservableCollection(result); } private ObservableCollection GetTestIdsTree(ObservableCollection treeViewChannelsList, List summaryList) { if (!treeViewChannelsList.Any()) return new ObservableCollection(); var result = new ObservableCollection(); var orderedTreeViewChannelsList = treeViewChannelsList.OrderBy(c => c.Name); var treeIndex = 0; double eventLength = 0; foreach (var testId in orderedTreeViewChannelsList) { var testIdEnd = testId.Name.LastIndexOf(EventNumber) - 1; var testIdName = testId.Name.Substring(0, testIdEnd); //See if we already have an event with this TestId var testIdFound = false; foreach (var element in result) { if ((element.Events[0].TestId == testIdName)) { testIdFound = true; AddEvent(testId, element, treeIndex, eventLength); treeIndex++; break; } } if (!testIdFound) { var tvi = new TreeViewIds(); tvi.TreeIndex = treeIndex; treeIndex++; var numEvents = orderedTreeViewChannelsList.Count(n => (n.Name.LastIndexOf(EventNumber) - 1 == testIdName.Length) && n.Name.StartsWith(testIdName)); tvi.Name = $"{testIdName} ({numEvents} events)"; //This is a new TestId, so re-calculate the event length eventLength = CalculateEventLength(testIdName, summaryList); AddEvent(testId, tvi, treeIndex, eventLength); treeIndex++; result.Add(tvi); tvi.IsExpanded = false; } } return new ObservableCollection(result); } private static double CalculateEventLength(string testIdName, List summaryList) { double eventLength = 0.0D; try { var testMetaData = summaryList.Where(t => t.Id.StartsWith(testIdName)); if (null == testMetaData) { return eventLength; } var meta = testMetaData.FirstOrDefault(); if (null == meta || null == meta.TestMetadata || null == meta.TestMetadata.TestRun || null == meta.TestMetadata.TestRun.Modules || 0 == meta.TestMetadata.TestRun.Modules.Count) { return eventLength; } var module = testMetaData.FirstOrDefault().TestMetadata.TestRun.Modules[0]; double numberOfSamplesStr = module.NumberOfSamples; double samplesPerSecondStr = module.SampleRateHz; if (samplesPerSecondStr.Equals(0D)) { return eventLength; } eventLength = Convert.ToDouble(numberOfSamplesStr) / Convert.ToDouble(samplesPerSecondStr); } catch( Exception ex) { APILogger.Log(ex); } return eventLength; } private static string ParseTestSetupName(string name) { var result = string.Empty; var splitUpName = name.Split(' '); var index = 0; foreach (var word in splitUpName) { if (word == "ROI" || word == "ALL") { result = splitUpName[index - 1]; //It's the one before ROI or ALL } index++; } return result; } private string ParseROIOrAll(string name) { var result = string.Empty; var splitUpName = name.Split(' '); foreach (var word in splitUpName) { if (word == "ROI" || word == "ALL") { result = word; break; } } return result; } private static string ParseTestId(string name) { var result = string.Empty; var testIdLength = name.IndexOf(Constants.EventNumber); result = name.Substring(0, testIdLength); return result; } private void AddEvent(TreeViewChannels testId, TreeViewIds tvi, int treeIndex, double eventLength) { foreach (var group in testId.Groups) { var e = new TestEvent(); e.TreeIndex = treeIndex; var eventNumberStart = testId.Name.IndexOf(EventNumber); var actualEventNumberStart = eventNumberStart + EventNumber.Length + 1; var actualEventNumberEnd = 0; actualEventNumberEnd = testId.Name.IndexOf(' ', actualEventNumberStart); //Look for space after "Event Number 0001" (TSR AIR Go) var actualEventNumberLength = actualEventNumberEnd - actualEventNumberStart; var eventLengthStr = new DateTime(TimeSpan.FromSeconds(eventLength).Ticks).ToString("HH:mm:ss.fff"); e.Name = $"{testId.Name.Substring(eventNumberStart, EventNumber.Length + 1 + actualEventNumberLength)} {eventLengthStr}"; e.TestId = ParseTestId(testId.Name); e.TestSetupName = ParseTestSetupName(testId.Name); e.DataType = ParseROIOrAll(testId.Name); var roiSuffixString = string.Empty; e.TestItem = $"{e.TestSetupName}:{ e.TestId}:({e.DataType}){roiSuffixString}"; e.DTSFile = group.DTSFile; e.IsExpanded = false; tvi.Events.Add(e); } } #region Commands #endregion Commands } }