JD2022-TU1/main/tools/modules/JD.Oasis.Module/ViewModel/OasisViewModel.cs

417 lines
No EOL
18 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using JD.Localization.Core.Model;
using JD.Localization.Core.Model.Attributes;
using JD.LocalizationExport.Service.API;
using JD.LocalizationExport.Service.Model;
using JD.LocalizationExport.Service.Model.Options;
using JD.Oasis.Module.ViewModel.TreeViewModel;
using JD.Oasis.Service.API;
using JD.Reflection;
using Plume.Core.Logging;
using Plume.Interfaces.WPF.Notifications;
using Plume.Interfaces.WPF.StatusBar;
using Plume.Perforce.Service.Api;
using Plume.WPF.Commands;
using Plume.WPF.Mvvm;
using ExportLanguage = JD.LocalizationExport.Service.Model.Language;
using ExportLine = JD.LocalizationExport.Service.Model.Line;
namespace JD.Oasis.Module.ViewModel
{
public class OasisViewModel : BindableBase
{
private readonly IOasisService _oasisService;
private readonly ILocalizationExportService _exportService;
private readonly IStatusBarManager _statusBarManager;
private readonly INotificationManager _notificationManager;
private readonly ILogger _logger;
private readonly ExportServiceEventsHandler _exportEventsHandler;
#region Initialization
private OasisViewModel(IOasisService oasisService, ILocalizationExportService exportService, IPerforceService perforceService, string dataServer, string codeServer, IStatusBarManager statusBarManager, INotificationManager notificationManager, ILogger logger)
{
_oasisService = oasisService;
_exportService = exportService;
_statusBarManager = statusBarManager;
_notificationManager = notificationManager;
_logger = logger;
_progressCallback = new Progress<string>(msg =>
{
_statusBarManager.SetMessage(msg);
_logger.Info(msg);
});
_progressWithValueCallback = new Progress<Tuple<string, int>>(t =>
{
_logger.Info(t.Item1);
ShowProgress(t.Item1, t.Item2);
});
RefreshLocalisationDataCommand = new DelegateCommand(RefreshLocalisationData).ObservesCanExecute(() => IsUIEnabled);
_exportEventsHandler =
new ExportServiceEventsHandler(_exportService, perforceService, dataServer, codeServer, _logger);
}
public static Task<OasisViewModel> CreateAsync(IOasisService oasisService,
ILocalizationExportService exportService,
IPerforceService perforceService,
string dataServer, string codeServer,
IStatusBarManager statusBarManager,
INotificationManager notificationManager,
ILogger logger)
{
return new OasisViewModel(oasisService, exportService, perforceService, dataServer, codeServer, statusBarManager, notificationManager, logger).InitializeAsync();
}
private async Task<OasisViewModel> InitializeAsync()
{
await RefreshLocalizationDataAsync().ConfigureAwait(false);
return this;
}
#endregion
#region Commands
public DelegateCommand RefreshLocalisationDataCommand { get; }
#endregion
#region Properties
private FolderTreeNodeViewModel _rootNode;
public FolderTreeNodeViewModel RootNode
{
get => _rootNode;
set => SetProperty(ref _rootNode, value);
}
public List<FileTreeNodeViewModel> NodeList { get; private set; }
private bool _isUIEnabled = true;
public bool IsUIEnabled
{
get => _isUIEnabled;
set => SetProperty(ref _isUIEnabled, value);
}
#endregion
#region Event handlers
public async Task OnLocalizationExportLaunched(IDictionary<ExportType, ExportOptionsModel> exportTypesAndOptionsToExecute, IEnumerable<UafLanguage> languagesToExport)
{
IsUIEnabled = false;
bool hasExportSucceeded = true;
IEnumerable<ExportLine> allLines = NodeList.Select(n => new ExportLine(n.LineId, n.MasterText, n.Translations, n.IsLineForPhone));
IEnumerable<ExportLine> selectedLines = NodeList.Where(n => n.IsChecked == true).Select(n => new ExportLine(n.LineId, n.MasterText, n.Translations, n.IsLineForPhone)).ToArray();
if (!selectedLines.Any())
{
string noLinesSelectedMessage = "Please select some lines in the tree before launching an export";
ShowFailure(noLinesSelectedMessage);
_logger.Error(noLinesSelectedMessage);
MessageBox.Show(noLinesSelectedMessage, "No lines selected", MessageBoxButton.OK, MessageBoxImage.Error);
IsUIEnabled = true;
return;
}
ExportType[] exportTypesToExecute = exportTypesAndOptionsToExecute.Keys.ToArray();
if (exportTypesToExecute.Length == 0)
{
string noExportsSelectedMessage = "Please select some types of exports and try again";
ShowFailure(noExportsSelectedMessage);
_logger.Error(noExportsSelectedMessage);
MessageBox.Show(noExportsSelectedMessage, "No exports selected", MessageBoxButton.OK, MessageBoxImage.Error);
IsUIEnabled = true;
return;
}
UafLanguage[] languagesToExportArray = languagesToExport.ToArray();
Dictionary<UafLanguage, string> oasisNamesForLanguagesToExport = await OasisHelpers.GetOasisNamesForLanguagesAsync(_oasisService, languagesToExportArray);
if (languagesToExportArray.Length == 0)
{
string noLanguagesSelectedMessage = "Please select some languages and try again";
ShowFailure(noLanguagesSelectedMessage);
_logger.Error(noLanguagesSelectedMessage);
MessageBox.Show(noLanguagesSelectedMessage, "No languages selected", MessageBoxButton.OK, MessageBoxImage.Error);
IsUIEnabled = true;
return;
}
UafLanguage[] allUafLanguagesArray = UafLanguageMethods.GetAllLanguages().ToArray();
Dictionary<UafLanguage, string> oasisNamesForLanguages = await OasisHelpers.GetOasisNamesForLanguagesAsync(_oasisService, allUafLanguagesArray);
ExportLanguage[] allLanguages = allUafLanguagesArray.Select(l => new ExportLanguage(oasisNamesForLanguages[l],
l.ToString(),
ReflectionHelper.GetEnumDescription(l),
ReflectionHelper.GetEnumAttribute<CultureNameAttribute>(l).Values,
(int)ReflectionHelper.GetEnumAttribute<RegionsAttribute>(l).Value,
l == UafLanguage.ITF_LANGUAGE_DEV_REFERENCE))
.ToArray();
ExportLanguage[] selectedLanguages = allLanguages.Where(l => oasisNamesForLanguagesToExport.ContainsValue(l.OasisName)).ToArray();
string exportMessage = "Exporting localization...";
ShowInitialization(exportMessage);
_logger.Info(exportMessage);
_logger.Info($"Selected exports : {Environment.NewLine + string.Join(Environment.NewLine, exportTypesToExecute)}");
_logger.Info($"Selected languages : {Environment.NewLine + string.Join(Environment.NewLine, selectedLanguages.Select(l => l.Description))}");
try
{
DataToExport dataToExport = new DataToExport(allLines, selectedLines, allLanguages, selectedLanguages);
foreach (ExportType exportType in exportTypesToExecute)
{
exportMessage = $"Exporting {exportType} localization...";
_statusBarManager.SetMessage(exportMessage);
_logger.Info(exportMessage);
ExportRepositoryType repositoryType = _exportService.ExportConfigs[exportType].RepositoryType;
switch (exportType)
{
case ExportType.Console:
ConsoleExportOptions consoleExportOptions = exportTypesAndOptionsToExecute[exportType] as ConsoleExportOptions;
string consoleRepositoryRoot = _exportEventsHandler.RegisterExportTypeAndGetRootPath(exportType, consoleExportOptions, repositoryType);
hasExportSucceeded &= await _exportService.ExportConsoleLocalizationAsync(dataToExport, consoleExportOptions, consoleRepositoryRoot, _progressWithValueCallback);
break;
case ExportType.MCA:
MCAExportOptions mcaExportOptions = exportTypesAndOptionsToExecute[exportType] as MCAExportOptions;
string mcaRepositoryRoot = _exportEventsHandler.RegisterExportTypeAndGetRootPath(exportType, mcaExportOptions, repositoryType);
hasExportSucceeded &= await _exportService.ExportMCALocalizationAsync(dataToExport, mcaExportOptions, mcaRepositoryRoot, _progressWithValueCallback);
break;
case ExportType.Online:
OnlineExportOptions onlineExportOptions = exportTypesAndOptionsToExecute[exportType] as OnlineExportOptions;
string onlineRepositoryRoot = _exportEventsHandler.RegisterExportTypeAndGetRootPath(exportType, onlineExportOptions, repositoryType);
hasExportSucceeded &= await _exportService.ExportOnlineLocalizationAsync(dataToExport, onlineExportOptions, onlineRepositoryRoot, _progressWithValueCallback);
break;
default:
_logger.Error($"Unknown export type '{exportType}': check {_exportService.ConfigPath}");
hasExportSucceeded = false;
break;
}
if (!hasExportSucceeded)
{
break;
}
}
}
catch (Exception e)
{
_logger.Error("Error during the export");
_logger.Error(e.Message);
_logger.Error(e.StackTrace);
hasExportSucceeded = false;
}
if (hasExportSucceeded)
{
string successfulExportMessage = "Export successful";
ShowSuccess(successfulExportMessage);
_logger.Info(successfulExportMessage);
}
else
{
ShowFailure("Export failed: read the Output logs for more details");
}
IsUIEnabled = true;
}
#endregion
#region Command implementation
private async void RefreshLocalisationData()
{
await RefreshLocalizationDataAsync().ConfigureAwait(false);
}
private async Task RefreshLocalizationDataAsync()
{
string loadingMessage = _rootNode != null ? "Refreshing localization data..." : "Loading localization data...";
ShowInitialization(loadingMessage);
_logger.Info(loadingMessage);
IsUIEnabled = false;
RootNode = null; // Resets the tree UI
IEnumerable<LocalizedLine> localizedLines = null;
bool hasRefreshedOasisDataSuccessfully = true;
try
{
localizedLines = await _oasisService.GetLocalizedLinesAsync(_progressCallback).ConfigureAwait(false);
}
catch (Exception e)
{
_logger.Error("Error while loading Oasis data:");
_logger.Error(e.Message);
_logger.Error(e.StackTrace);
hasRefreshedOasisDataSuccessfully = false;
}
if (hasRefreshedOasisDataSuccessfully)
{
try
{
_progressCallback.Report("Updating tree display...");
await Task.Run(() => GenerateTreeFromLines(localizedLines)).ConfigureAwait(false);
}
catch (Exception e)
{
_logger.Error("Error while generating tree display from Oasis data:");
_logger.Error(e.Message);
_logger.Error(e.StackTrace);
hasRefreshedOasisDataSuccessfully = false;
}
}
if (hasRefreshedOasisDataSuccessfully)
{
RootNode.IsExpanded = true;
string successfulLoadingMessage = "Localization data loaded successfully";
ShowSuccess(successfulLoadingMessage);
_logger.Info(successfulLoadingMessage);
}
else
{
ShowFailure("Localization data load failed: read the Output logs for more details");
}
IsUIEnabled = true;
}
private void GenerateTreeFromLines(IEnumerable<LocalizedLine> lines, bool areLinesChecked = true)
{
string rootNodePath = string.Empty;
FolderTreeNodeViewModel tempRootNode = new FolderTreeNodeViewModel("Check/Uncheck All", rootNodePath, areLinesChecked);
Dictionary<string, OasisTreeNodeViewModel> nodeByPaths = new Dictionary<string, OasisTreeNodeViewModel>();
nodeByPaths[tempRootNode.Path] = tempRootNode;
LocalizedLine[] lineArray = lines.OrderBy(l => l.Path).ToArray();
NodeList = new List<FileTreeNodeViewModel>(lineArray.Length);
char separator = '/';
char[] separators = { separator };
foreach (LocalizedLine line in lines.OrderBy(l => l.Path))
{
string[] pathTokens = line.Path.Split(separators);
string partialPath = rootNodePath;
for (int i = 0; i < pathTokens.Length - 1; ++i)
{
string previousPartialPath = partialPath;
string folderName = pathTokens[i];
partialPath += separator + folderName;
if (!nodeByPaths.ContainsKey(partialPath))
{
FolderTreeNodeViewModel newFolderNode = new FolderTreeNodeViewModel(pathTokens[i], partialPath, areLinesChecked);
nodeByPaths[partialPath] = newFolderNode;
nodeByPaths[previousPartialPath].Children.Add(newFolderNode);
}
}
FileTreeNodeViewModel newLineNode = new FileTreeNodeViewModel(line, pathTokens[pathTokens.Length - 1], areLinesChecked);
nodeByPaths[line.Path] = newLineNode;
nodeByPaths[partialPath].Children.Add(newLineNode);
NodeList.Add(newLineNode);
}
RootNode = tempRootNode;
}
#endregion
// TODO: Update TaskManager with these methods to use it instead of letting them here
#region Status Bar
private static readonly TimeSpan TemporaryMessageDuration = TimeSpan.FromSeconds(4);
private const string IdleMessage = "Ready";
private void ShowInitialization(string message)
{
_statusBarManager.ResetDefaultBackgroundColor();
_statusBarManager.SetMessage(message);
_statusBarManager.SetProgressVisible(true);
_statusBarManager.SetProgressIndeterminate(true);
}
private void ShowSuccess(string successMessage)
{
_statusBarManager.SetProgressVisible(false);
_statusBarManager.ResetDefaultBackgroundColor();
_statusBarManager.SetMessage(IdleMessage);
_statusBarManager.SetMessage(successMessage, TemporaryMessageDuration, Colors.Green);
_notificationManager.ShowSuccess(successMessage);
}
private void ShowFailure(string errorMessage)
{
_statusBarManager.SetProgressVisible(false);
_statusBarManager.ResetDefaultBackgroundColor();
_statusBarManager.SetMessage(IdleMessage);
_statusBarManager.SetMessage(errorMessage, TemporaryMessageDuration, Colors.Red);
_notificationManager.ShowError(errorMessage);
}
private void ShowProgress(string progressMessage, int progressValue)
{
_statusBarManager.SetProgressVisible(true);
if (progressValue < 0)
{
_statusBarManager.SetProgressIndeterminate(true);
}
else
{
_statusBarManager.SetProgressIndeterminate(false);
_statusBarManager.SetProgress(progressValue);
}
_statusBarManager.SetMessage(progressMessage);
}
private readonly IProgress<string> _progressCallback;
private readonly IProgress<Tuple<string, int>> _progressWithValueCallback;
#endregion
}
}