public SessionServiceViewModel(ISessionService sessionService, IInputBoxService inputBoxService, IMessageBoxService messageBoxService, IWindowManager windowManager, Lazy <IDocumentManager> documentManager, ITextDocumentService textDocumentService, IHistoryManager historyManager) { this.SessionService = sessionService; this.inputBoxService = inputBoxService; this.messageBoxService = messageBoxService; this.windowManager = windowManager; this.History = historyManager; History.AddHandler(this); Undo = new DelegateCommand(() => History.Undo(), () => History.CanUndo).ObservesProperty(() => History.CanUndo); Redo = new DelegateCommand(() => History.Redo(), () => History.CanRedo).ObservesProperty(() => History.CanRedo); NewSessionCommand = new AsyncAutoCommand(NewSession); var save = new AsyncAutoCommand(SaveCurrent, _ => sessionService.IsNonEmpty); SaveCurrentCurrent = save; var forget = new AsyncAutoCommand(ForgetCurrent, _ => sessionService.IsOpened); ForgetCurrentCurrent = forget; DeleteItem = new DelegateCommand <ISolutionItem>(sessionService.RemoveItem, _ => sessionService.IsOpened).ObservesProperty(() => this.SessionService.IsOpened); var preview = new DelegateCommand(() => { var sql = sessionService.GenerateCurrentQuery(); if (sql == null) { return; } documentManager.Value.OpenDocument(textDocumentService.CreateDocument($"Preview of " + sessionService.CurrentSession !.Name, sql, "sql")); }, () => sessionService.IsNonEmpty); PreviewCurrentCommand = preview; sessionService.ToObservable(o => o.IsNonEmpty) .SubscribeAction(_ => { preview.RaiseCanExecuteChanged(); forget.RaiseCanExecuteChanged(); save.RaiseCanExecuteChanged(); }); History.ToObservable(h => h.IsSaved) .SubscribeAction(_ => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsModified))); }); }
public PacketDocumentViewModel(PacketDocumentSolutionItem solutionItem, IMainThread mainThread, MostRecentlySearchedService mostRecentlySearchedService, IDatabaseProvider databaseProvider, Func <INativeTextDocument> nativeTextDocumentCreator, IMessageBoxService messageBoxService, IPacketFilteringService filteringService, IDocumentManager documentManager, ITextDocumentService textDocumentService, IWindowManager windowManager, IPacketViewerSettings packetSettings, IEnumerable <IPacketDumperProvider> dumperProviders, IInputBoxService inputBoxService, IHistoryManager history, IPacketFilterDialogService filterDialogService, IActionReactionProcessorCreator actionReactionProcessorCreator, IRelatedPacketsFinder relatedPacketsFinder, ITeachingTipService teachingTipService, PacketDocumentSolutionNameProvider solutionNameProvider, ISniffLoader sniffLoader, ISpellStore spellStore, PrettyFlagParameter prettyFlagParameter, Func <IUpdateFieldsHistory> historyCreator) { this.solutionItem = solutionItem; this.mainThread = mainThread; this.messageBoxService = messageBoxService; this.filteringService = filteringService; this.actionReactionProcessorCreator = actionReactionProcessorCreator; this.relatedPacketsFinder = relatedPacketsFinder; this.sniffLoader = sniffLoader; History = history; history.LimitStack(20); packetViewModelCreator = new PacketViewModelFactory(databaseProvider, spellStore); MostRecentlySearched = mostRecentlySearchedService.MostRecentlySearched; Title = solutionNameProvider.GetName(this.solutionItem); SolutionItem = solutionItem; FilterText = nativeTextDocumentCreator(); SelectedPacketPreview = nativeTextDocumentCreator(); SelectedPacketPreview.DisableUndo(); Watch(this, t => t.FilteringProgress, nameof(ProgressUnknown)); AutoDispose(history.AddHandler(new SelectedPacketHistory(this))); filteredPackets = visiblePackets = AllPackets; ApplyFilterCommand = new AsyncCommand(async() => { if (inApplyFilterCommand) { return; } inApplyFilterCommand = true; MostRecentlySearchedItem = FilterText.ToString(); inApplyFilterCommand = false; if (!string.IsNullOrEmpty(FilterText.ToString())) { mostRecentlySearchedService.Add(FilterText.ToString()); } if (currentActionToken != filteringToken) { throw new Exception("Invalid concurrent access!"); } filteringToken?.Cancel(); filteringToken = null; currentActionToken = null; await FilterPackets(FilterText.ToString()); }); SaveToFileCommand = new AsyncCommand(async() => { var path = await windowManager.ShowSaveFileDialog("Text file|txt"); if (path == null) { return; } LoadingInProgress = true; FilteringInProgress = true; try { await using StreamWriter writer = File.CreateText(path); int i = 0; int count = FilteredPackets.Count; foreach (var packet in FilteredPackets) { await writer.WriteLineAsync(packet.Text); if ((i % 100) == 0) { Report(i * 1.0f / count); } } } catch (Exception e) { Console.WriteLine(e); await this.messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetTitle("Fatal error") .SetMainInstruction("Fatal error during saving file") .SetContent(e.Message) .WithOkButton(false) .Build()); } LoadingInProgress = false; FilteringInProgress = false; }); OpenHelpCommand = new DelegateCommand(() => windowManager.OpenUrl("https://github.com/BAndysc/WoWDatabaseEditor/wiki/Packet-Viewer")); On(() => SelectedPacket, doc => { if (doc != null) { SelectedPacketPreview.FromString(doc.Text); } }); On(() => SplitUpdate, _ => { SplitPacketsIfNeededAsync().Wait(); ((ICommand)ApplyFilterCommand).Execute(null); }); On(() => HidePlayerMove, _ => { ((ICommand)ApplyFilterCommand).Execute(null); }); On(() => DisableFilters, _ => { ((ICommand)ApplyFilterCommand).Execute(null); }); foreach (var dumper in dumperProviders) { Processors.Add(new(dumper)); } QuickRunProcessor = new AsyncAutoCommand <ProcessorViewModel>(async(processor) => { LoadingInProgress = true; FilteringInProgress = true; try { var tokenSource = new CancellationTokenSource(); AssertNoOnGoingTask(); currentActionToken = tokenSource; var output = await RunProcessorsThreaded(new List <ProcessorViewModel>() { processor }, tokenSource.Token).ConfigureAwait(true); if (output != null && !tokenSource.IsCancellationRequested) { documentManager.OpenDocument(textDocumentService.CreateDocument($"{processor.Name} ({Title})", output, processor.Extension, true)); } } catch (Exception e) { Console.WriteLine(e); await messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetIcon(MessageBoxIcon.Error) .SetTitle("Fatal error") .SetMainInstruction("Fatal error during processing") .SetContent( "Sorry, fatal error occured, this is probably a bug in processors, please report it in github\n\n" + e) .WithOkButton(true) .Build()); } LoadingInProgress = false; FilteringInProgress = false; currentActionToken = null; }); RunProcessors = new AsyncAutoCommand(async() => { var processors = Processors.Where(s => s.IsChecked).ToList(); if (processors.Count == 0) { return; } LoadingInProgress = true; FilteringInProgress = true; try { var tokenSource = new CancellationTokenSource(); AssertNoOnGoingTask(); currentActionToken = tokenSource; var output = await RunProcessorsThreaded(processors, tokenSource.Token).ConfigureAwait(true); if (output != null && !tokenSource.IsCancellationRequested) { var extension = processors.Select(p => p.Extension).Distinct().Count() == 1 ? processors[0].Extension : "txt"; documentManager.OpenDocument(textDocumentService.CreateDocument($"{processors[0].Name} ({Title})", output, extension, true)); } } catch (Exception e) { Console.WriteLine(e); await messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetIcon(MessageBoxIcon.Error) .SetTitle("Fatal error") .SetMainInstruction("Fatal error during processing") .SetContent( "Sorry, fatal error occured, this is probably a bug in processors, please report it in github\n\n" + e) .WithOkButton(true) .Build()); } LoadingInProgress = false; FilteringInProgress = false; currentActionToken = null; }, () => Processors.Any(c => c.IsChecked)); foreach (var proc in Processors) { AutoDispose(proc.ToObservable(p => p.IsChecked) .SubscribeAction(_ => RunProcessors.RaiseCanExecuteChanged())); } UndoCommand = new DelegateCommand(history.Undo, () => history.CanUndo); RedoCommand = new DelegateCommand(history.Redo, () => history.CanRedo); History.PropertyChanged += (_, _) => { UndoCommand.RaiseCanExecuteChanged(); RedoCommand.RaiseCanExecuteChanged(); }; IEnumerable <int> GetFindEnumerator(int start, int count, int direction, bool wrap) { for (int i = start + direction; i >= 0 && i < count; i += direction) { yield return(i); } if (wrap) { if (direction > 0) { for (int i = 0; i < start; ++i) { yield return(i); } } else { for (int i = count - 1; i > start; --i) { yield return(i); } } } } async Task Find(string searchText, int start, int direction) { var count = VisiblePackets.Count; var searchToLower = searchText.ToLower(); foreach (var i in GetFindEnumerator(start, count, direction, true)) { if (VisiblePackets[i].Text.Contains(searchToLower, StringComparison.InvariantCultureIgnoreCase)) { SelectedPacket = VisiblePackets[i]; return; } } await messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetTitle("Find") .SetMainInstruction("Not found") .SetContent("Cannot find text: " + searchText) .WithOkButton(true) .Build()); } ToggleFindCommand = new DelegateCommand(() => FindPanelEnabled = !FindPanelEnabled); CloseFindCommand = new DelegateCommand(() => FindPanelEnabled = false); FindPreviousCommand = new AsyncAutoCommand <string>(async searchText => { var start = SelectedPacket != null ? VisiblePackets.IndexOf(SelectedPacket) : 0; await Find(searchText, start, -1); }, str => str is string s && !string.IsNullOrEmpty(s)); FindNextCommand = new AsyncAutoCommand <string>(async searchText => { var start = SelectedPacket != null ? VisiblePackets.IndexOf(SelectedPacket) : 0; await Find(searchText, start, 1); }, str => str is string s && !string.IsNullOrEmpty(s)); FindRelatedPacketsCommands = new AsyncAutoCommand(async() => { if (selectedPacket == null) { return; } if (!await EnsureSplitOrDismiss()) { return; } FilteringInProgress = true; FilteringProgress = -1; var tokenSource = new CancellationTokenSource(); AssertNoOnGoingTask(); currentActionToken = tokenSource; IFilterData?newFilterData = await GetRelatedFilters(selectedPacket.Packet.BaseData.Number, tokenSource.Token); FilteringInProgress = false; currentActionToken = null; if (newFilterData == null) { return; } if (!FilterData.IsEmpty) { if (await messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetTitle("Find related packets") .SetMainInstruction("Your current filter data is not empty") .SetContent("Do you want to override current filter data?") .WithButton("Override", true) .WithButton("Merge", false) .Build())) { FilterData = newFilterData; } else { FilterData.SetMinMax(Min(FilterData.MinPacketNumber, newFilterData.MinPacketNumber), Max(FilterData.MaxPacketNumber, newFilterData.MaxPacketNumber)); if (newFilterData.IncludedGuids != null) { foreach (var guid in newFilterData.IncludedGuids) { FilterData.IncludeGuid(guid); } } if (newFilterData.ForceIncludePacketNumbers != null) { foreach (var packet in newFilterData.ForceIncludePacketNumbers) { FilterData.IncludePacketNumber(packet); } } } } else { FilterData = newFilterData; } await ApplyFilterCommand.ExecuteAsync(); }); ExcludeEntryCommand = new AsyncAutoCommand <PacketViewModel?>(async vm => { if (vm == null || vm.Entry == 0) { return; } FilterData.ExcludeEntry(vm.Entry); await ApplyFilterCommand.ExecuteAsync(); }, vm => vm is PacketViewModel pvm && pvm.Entry != 0); IncludeEntryCommand = new AsyncAutoCommand <PacketViewModel?>(async vm => { if (vm == null || vm.Entry == 0) { return; } FilterData.IncludeEntry(vm.Entry); await ApplyFilterCommand.ExecuteAsync(); }, vm => vm is PacketViewModel pvm && pvm.Entry != 0); ExcludeGuidCommand = new AsyncAutoCommand <PacketViewModel?>(async vm => { if (vm == null || vm.MainActor == null) { return; } FilterData.ExcludeGuid(vm.MainActor); await ApplyFilterCommand.ExecuteAsync(); }, vm => vm is PacketViewModel pvm && pvm.MainActor != null); IncludeGuidCommand = new AsyncAutoCommand <PacketViewModel?>(async vm => { if (vm == null || vm.MainActor == null) { return; } FilterData.IncludeGuid(vm.MainActor); await ApplyFilterCommand.ExecuteAsync(); }, vm => vm is PacketViewModel pvm && pvm.MainActor != null); ExcludeOpcodeCommand = new AsyncAutoCommand <PacketViewModel?>(async vm => { if (vm == null) { return; } FilterData.ExcludeOpcode(vm.Opcode); await ApplyFilterCommand.ExecuteAsync(); }, vm => vm != null); IncludeOpcodeCommand = new AsyncAutoCommand <PacketViewModel?>(async vm => { if (vm == null) { return; } FilterData.IncludeOpcode(vm.Opcode); await ApplyFilterCommand.ExecuteAsync(); }, vm => vm != null); AutoDispose(this.ToObservable(o => o.SelectedPacket).SubscribeAction(_ => { ExcludeEntryCommand.RaiseCanExecuteChanged(); IncludeEntryCommand.RaiseCanExecuteChanged(); ExcludeGuidCommand.RaiseCanExecuteChanged(); IncludeGuidCommand.RaiseCanExecuteChanged(); ExcludeOpcodeCommand.RaiseCanExecuteChanged(); IncludeOpcodeCommand.RaiseCanExecuteChanged(); })); ExplainSelectedPacketCommand = new AsyncAutoCommand(async() => { if (!reasonPanelVisibility || actionReactionProcessor == null) { return; } if (selectedPacket == null) { return; } DetectedActions.Clear(); var detected = actionReactionProcessor.GetAllActions(selectedPacket.Id); if (detected != null) { DetectedActions.AddRange(detected.Select(s => new DetectedActionViewModel(s))); } DetectedEvents.Clear(); var events = actionReactionProcessor.GetAllEvents(selectedPacket.Id); if (events != null) { DetectedEvents.AddRange(events.Select(s => new DetectedEventViewModel(s))); } var reasons = actionReactionProcessor.GetPossibleEventsForAction(selectedPacket.Packet.BaseData); Predictions.Clear(); foreach (var reason in reasons) { Predictions.Add(new ActionReasonPredictionViewModel(selectedPacket.Packet.BaseData, reason.rate.Value, reason.rate.Explain, reason.@event)); } PossibleActions.Clear(); var actions = actionReactionProcessor.GetPossibleActionsForEvent(selectedPacket.Packet.BaseData.Number); foreach (var action in actions) { var actionHappened = actionReactionProcessor.GetAction(action.packetId); if (actionHappened == null) { continue; } PossibleActions.Add(new PossibleActionViewModel(selectedPacket.Packet.BaseData, action.chance, "", actionHappened.Value)); } }, () => ReasonPanelVisibility); On(() => ReasonPanelVisibility, isVisible => { if (!isVisible) { return; } ApplyFilterCommand.ExecuteAsync().ContinueWith(_ => { ExplainSelectedPacketCommand.Execute(null); }, TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.NotOnFaulted).ListenErrors(); }); AutoDispose(this.ToObservable(o => o.SelectedPacket) .CombineLatest(this.ToObservable(o => o.ReasonPanelVisibility)) .SubscribeAction( _ => { ExplainSelectedPacketCommand.Execute(null); })); OpenFilterDialogCommand = new AsyncAutoCommand(async() => { var newData = await filterDialogService.OpenFilterDialog(FilterData); if (newData != null) { FilterData = newData; await ApplyFilterCommand.ExecuteAsync(); } }); JumpToPacketCommand = new DelegateCommand <int?>(packetId => { if (!packetId.HasValue) { return; } var packet = filteredPackets.FirstOrDefault(p => p.Id == packetId.Value); if (packet != null) { SelectedPacket = packet; } }); GoToPacketCommand = new AsyncAutoCommand(async() => { var min = filteredPackets[0].Id; var max = filteredPackets[^ 1].Id;
public SolutionExplorerViewModel(ISolutionItemNameRegistry itemNameRegistry, ISolutionManager solutionManager, IEventAggregator ea, ISolutionSqlService solutionSqlService, INewItemService newItemService, ISolutionTasksService solutionTasksService, IStatusBar statusBar, ISolutionItemIconRegistry solutionItemIconRegistry, ISolutionItemProvideService provider, IInputBoxService inputBoxService, IMessageBoxService messageBoxService) { this.itemNameRegistry = itemNameRegistry; this.solutionManager = solutionManager; this.ea = ea; this.statusBar = statusBar; this.solutionItemIconRegistry = solutionItemIconRegistry; this.inputBoxService = inputBoxService; Root = new ObservableCollection <SolutionItemViewModel>(); itemToViewmodel = new Dictionary <ISolutionItem, SolutionItemViewModel>(); foreach (ISolutionItem item in this.solutionManager.Items) { AddItemToRoot(item); } this.solutionManager.Items.CollectionChanged += (sender, args) => { if (args.NewItems != null) { var i = 0; foreach (ISolutionItem obj in args.NewItems) { AddItemToRoot(obj, args.NewStartingIndex + i); i++; } } if (args.OldItems != null) { foreach (ISolutionItem obj in args.OldItems) { ISolutionItem solutionItem = obj; Root.Remove(itemToViewmodel[solutionItem]); itemToViewmodel.Remove(solutionItem); } } }; solutionManager.RefreshRequest += item => { foreach (var root in Root) { root.Refresh(); } }; Dictionary <string, AddItemCategoryMenuViewModel> byNameCategories = new(); Func <ISolutionItemProvider, Task> insertItemCommand = async provider => { ISolutionItem?item = null; if (provider is INamedSolutionItemProvider namedProvider) { var name = await this.inputBoxService.GetString("New", "Please provide a name for " + namedProvider.GetName(), ""); if (name == null || name.Length < 3) { await messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetTitle("New") .SetMainInstruction("Name is too short") .SetContent("Name can't be shorter than 3 characters") .WithOkButton(true) .Build()); return; } item = await namedProvider.CreateSolutionItem(name); } else { item = await provider.CreateSolutionItem(); } if (item != null) { DoAddItem(item); } }; foreach (var item in provider.AllCompatible) { if (!byNameCategories.TryGetValue(item.GetGroupName(), out var category)) { category = new AddItemCategoryMenuViewModel(item.GetGroupName()); byNameCategories.Add(category.Name, category); AddItems.Add(category); } category.Items.Add(new SolutionItemMenuViewModel(item, insertItemCommand)); } AddItem = new DelegateCommand(async() => { ISolutionItem?item = await newItemService.GetNewSolutionItem(); if (item != null) { DoAddItem(item); } }, () => (SelectedItem == null || SelectedItem.IsContainer) && SelectedItems.Count <= 1) .ObservesProperty(() => SelectedItem) .ObservesProperty(() => SelectedItems.Count); RemoveItem = new DelegateCommand <SolutionItemViewModel>(vm => { if (SelectedItems.Count > 0) { foreach (var item in SelectedItems.ToList()) { DeleteSolutionItem(item); } SelectedItems.Clear(); } else if (vm != null) { DeleteSolutionItem(vm); } }, vm => vm != null || SelectedItems.Count > 0) .ObservesProperty(() => SelectedItems.Count); RenameItem = new AsyncAutoCommand <SolutionItemViewModel>(async vm => { if (vm.Item is IRenameableSolutionItem renameable) { var newName = await inputBoxService.GetString("Rename", "Please provide a new name", vm.Name); if (newName != null) { if (newName.Length < 3) { await messageBoxService.ShowDialog(new MessageBoxFactory <bool>() .SetTitle("Rename") .SetMainInstruction("Name too short") .SetContent("The name can't be shorter than 3 characters") .SetIcon(MessageBoxIcon.Warning) .WithOkButton(true) .Build()); return; } renameable.Rename(newName); solutionManager.Refresh(vm.Item); } } }, o => o is SolutionItemViewModel vm && vm.Item is IRenameableSolutionItem); SelectedItemChangedCommand = new DelegateCommand <SolutionItemViewModel>(ob => { selected = ob; }); RequestOpenItem = new DelegateCommand <SolutionItemViewModel>(item => { if (item != null && !item.IsContainer) { this.ea.GetEvent <EventRequestOpenItem>().Publish(item.Item); } }); GenerateSQL = new DelegateCommand <SolutionItemViewModel>(vm => { if (vm != null) { solutionSqlService.OpenDocumentWithSqlFor(vm.Item); } }, vm => vm != null); UpdateDatabase = new DelegateCommand <SolutionItemViewModel>(vm => { if (vm != null) { solutionTasksService.SaveSolutionToDatabaseTask(vm.Item); } }, vm => vm != null && solutionTasksService.CanSaveToDatabase); ExportToServer = new DelegateCommand <SolutionItemViewModel>(vm => { if (vm != null) { solutionTasksService.SaveAndReloadSolutionTask(vm.Item); } }, vm => vm != null && solutionTasksService.CanSaveAndReloadRemotely); ExportToServerItem = new DelegateCommand <object>(item => { if (item is SolutionItemViewModel si) { solutionTasksService.SaveAndReloadSolutionTask(si.Item); } }, item => solutionTasksService.CanSaveAndReloadRemotely); }