// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "LocalizationDashboardPrivatePCH.h" #include "LocalizationTargetSetDetailCustomization.h" #include "DetailLayoutBuilder.h" #include "LocalizationTarget.h" #include "DetailWidgetRow.h" #include "SLocalizationDashboardTargetRow.h" #include "DetailCategoryBuilder.h" #include "IDetailsView.h" #include "LocalizationCommandletTasks.h" #include "ObjectEditorUtils.h" #define LOCTEXT_NAMESPACE "LocalizationDashboard" FLocalizationTargetSetDetailCustomization::FLocalizationTargetSetDetailCustomization() : DetailLayoutBuilder(nullptr) //, ServiceProviderCategoryBuilder(nullptr) , NewEntryIndexToBeInitialized(INDEX_NONE) { //TArray ActualProviders = ILocalizationDashboardModule::Get().GetLocalizationServiceProviders(); //for (ILocalizationServiceProvider* ActualProvider : ActualProviders) //{ // TSharedPtr Provider = MakeShareable(new FLocalizationServiceProviderWrapper(ActualProvider)); // Providers.Add(Provider); //} } //class FindProviderPredicate //{ //public: // FindProviderPredicate(ILocalizationServiceProvider* const InActualProvider) // : ActualProvider(InActualProvider) // { // } // bool operator()(const TSharedPtr& Provider) // { // return Provider->Provider == ActualProvider; // } //private: // ILocalizationServiceProvider* ActualProvider; //}; namespace { class FLocalizationDashboardCommands : public TCommands { public: FLocalizationDashboardCommands() : TCommands("LocalizationDashboard", NSLOCTEXT("Contexts", "LocalizationDashboard", "Localization Dashboard"), NAME_None, FEditorStyle::GetStyleSetName()) { } TSharedPtr GatherAllTargets; TSharedPtr ImportAllTargets; TSharedPtr ExportAllTargets; TSharedPtr CompileAllTargets; /** Initialize commands */ virtual void RegisterCommands() override; }; void FLocalizationDashboardCommands::RegisterCommands() { UI_COMMAND( GatherAllTargets, "Gather All", "Gathers text for all targets in the project.", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( ImportAllTargets, "Import All", "Imports translations for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( ExportAllTargets, "Export All", "Exports translations for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( CompileAllTargets, "Compile All", "Compiles translations for all targets in the project.", EUserInterfaceActionType::Button, FInputChord() ); } } void FLocalizationTargetSetDetailCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { DetailLayoutBuilder = &DetailBuilder; { TArray< TWeakObjectPtr > ObjectsBeingCustomized; DetailLayoutBuilder->GetObjectsBeingCustomized(ObjectsBeingCustomized); TargetSet = CastChecked(ObjectsBeingCustomized.Top().Get()); } { TargetObjectsPropertyHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ULocalizationTargetSet,TargetObjects)); if (TargetObjectsPropertyHandle->IsValidHandle()) { const FName CategoryName = FObjectEditorUtils::GetCategoryFName(TargetObjectsPropertyHandle->GetProperty()); IDetailCategoryBuilder& DetailCategoryBuilder = DetailBuilder.EditCategory(CategoryName); TargetObjectsPropertyHandle->MarkHiddenByCustomization(); TargetsArrayPropertyHandle_OnNumElementsChanged = FSimpleDelegate::CreateSP(this, &FLocalizationTargetSetDetailCustomization::RebuildTargetsList); TargetObjectsPropertyHandle->AsArray()->SetOnNumElementsChanged(TargetsArrayPropertyHandle_OnNumElementsChanged); FLocalizationDashboardCommands::Register(); const TSharedRef< FUICommandList > CommandList = MakeShareable(new FUICommandList); FToolBarBuilder ToolBarBuilder( CommandList, FMultiBoxCustomization::AllowCustomization("LocalizationDashboard") ); CommandList->MapAction( FLocalizationDashboardCommands::Get().GatherAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::GatherAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().GatherAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FEditorStyle::GetStyleSetName(), "LocalizationDashboard.GatherAllTargets")); CommandList->MapAction( FLocalizationDashboardCommands::Get().ImportAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ImportAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ImportAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FEditorStyle::GetStyleSetName(), "LocalizationDashboard.ImportForAllTargetsCultures")); CommandList->MapAction( FLocalizationDashboardCommands::Get().ExportAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ExportAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ExportAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FEditorStyle::GetStyleSetName(), "LocalizationDashboard.ExportForAllTargetsCultures")); CommandList->MapAction( FLocalizationDashboardCommands::Get().CompileAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CompileAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().CompileAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FEditorStyle::GetStyleSetName(), "LocalizationDashboard.CompileAllTargets")); BuildTargetsList(); DetailCategoryBuilder.AddCustomRow(TargetObjectsPropertyHandle->GetPropertyDisplayName()) .WholeRowContent() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ ToolBarBuilder.MakeWidget() ] +SVerticalBox::Slot() .AutoHeight() [ SAssignNew(TargetsListView, SListView< TSharedPtr >) .OnGenerateRow(this, &FLocalizationTargetSetDetailCustomization::OnGenerateRow) .ListItemsSource(&TargetsList) .SelectionMode(ESelectionMode::None) .HeaderRow ( SNew(SHeaderRow) +SHeaderRow::Column("Target") .DefaultLabel( LOCTEXT("TargetColumnLabel", "Target")) .HAlignHeader(HAlign_Left) .HAlignCell(HAlign_Left) .VAlignCell(VAlign_Center) +SHeaderRow::Column("Status") .DefaultLabel( LOCTEXT("StatusColumnLabel", "Status")) .HAlignHeader(HAlign_Center) .HAlignCell(HAlign_Center) .VAlignCell(VAlign_Center) +SHeaderRow::Column("Cultures") .DefaultLabel( LOCTEXT("CulturesColumnLabel", "Cultures")) .HAlignHeader(HAlign_Fill) .HAlignCell(HAlign_Fill) .VAlignCell(VAlign_Center) +SHeaderRow::Column("WordCount") .DefaultLabel( LOCTEXT("WordCountColumnLabel", "Word Count")) .HAlignHeader(HAlign_Center) .HAlignCell(HAlign_Center) .VAlignCell(VAlign_Center) +SHeaderRow::Column("Actions") .DefaultLabel( LOCTEXT("ActionsColumnLabel", "Actions")) .HAlignHeader(HAlign_Center) .HAlignCell(HAlign_Center) .VAlignCell(VAlign_Center) ) ] +SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Center) [ SNew(SButton) .Text(LOCTEXT("AddNewTargetButtonLabel", "Add New Target")) .OnClicked(this, &FLocalizationTargetSetDetailCustomization::OnNewTargetButtonClicked) ] ]; } } } void FLocalizationTargetSetDetailCustomization::BuildTargetsList() { const TSharedPtr TargetObjectsArrayPropertyHandle = TargetObjectsPropertyHandle->AsArray(); if (TargetObjectsArrayPropertyHandle.IsValid()) { uint32 ElementCount = 0; TargetObjectsArrayPropertyHandle->GetNumElements(ElementCount); for (uint32 i = 0; i < ElementCount; ++i) { const TSharedPtr TargetObjectPropertyHandle = TargetObjectsArrayPropertyHandle->GetElement(i); TargetsList.Add(TargetObjectPropertyHandle); } } } void FLocalizationTargetSetDetailCustomization::RebuildTargetsList() { const TSharedPtr TargetObjectsArrayPropertyHandle = TargetObjectsPropertyHandle->AsArray(); if (TargetObjectsArrayPropertyHandle.IsValid() && NewEntryIndexToBeInitialized != INDEX_NONE) { const TSharedPtr TargetObjectPropertyHandle = TargetObjectsArrayPropertyHandle->GetElement(NewEntryIndexToBeInitialized); if (TargetObjectPropertyHandle.IsValid() && TargetObjectPropertyHandle->IsValidHandle()) { ULocalizationTarget* const NewTarget = NewObject(TargetSet.Get()); TArray RawData; TargetObjectsPropertyHandle->AccessRawData(RawData); void* RawDatum = RawData.Top(); TArray& TargetObjectsArray = *(reinterpret_cast< TArray* >(RawDatum)); FString NewTargetName = "NewTarget"; auto TargetNameIsIdentical = [&](ULocalizationTarget* Target) -> bool { return (Target != NewTarget) && Target && (Target->Settings.Name == NewTargetName); }; for (uint32 i = 0; TargetObjectsArray.ContainsByPredicate(TargetNameIsIdentical); ++i) { NewTargetName = FString::Printf(TEXT("NewTarget%u"), i); } NewTarget->Settings.Name = NewTargetName; NewTarget->Settings.NativeCultureStatistics.CultureName = FInternationalization::Get().GetCurrentCulture()->GetName(); const UObject* SetValue = NewTarget; TargetObjectPropertyHandle->SetValue(SetValue); NewEntryIndexToBeInitialized = INDEX_NONE; } } TargetsList.Empty(); BuildTargetsList(); if (TargetsListView.IsValid()) { TargetsListView->RequestListRefresh(); } } //FText FLocalizationTargetSetDetailCustomization::GetCurrentServiceProviderDisplayName() const //{ // ILocalizationServiceProvider* const LSP = ILocalizationDashboardModule::Get().GetCurrentLocalizationServiceProvider(); // return LSP ? LSP->GetDisplayName() : LOCTEXT("NoServiceProviderName", "None"); //} // //TSharedRef FLocalizationTargetSetDetailCustomization::ServiceProviderComboBox_OnGenerateWidget(TSharedPtr LSPWrapper) const //{ // ILocalizationServiceProvider* const LSP = LSPWrapper->Provider; // return SNew(STextBlock) // .Text(LSP ? LSP->GetDisplayName() : LOCTEXT("NoServiceProviderName", "None")); //} // //void FLocalizationTargetSetDetailCustomization::ServiceProviderComboBox_OnSelectionChanged(TSharedPtr LSPWrapper, ESelectInfo::Type SelectInfo) //{ // ILocalizationServiceProvider* const LSP = LSPWrapper->Provider; // FString ServiceProviderName = LSP ? LSP->GetName().ToString() : TEXT("None"); // ServiceProviderPropertyHandle->SetValue(ServiceProviderName); // // if (LSP) // { // LSP->CustomizeSettingsDetails(*ServiceProviderCategoryBuilder); // } // DetailLayoutBuilder->ForceRefreshDetails(); //} void FLocalizationTargetSetDetailCustomization::GatherAllTargets() { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // Save unsaved packages. const bool bPromptUserToSave = true; const bool bSaveMapPackages = true; const bool bSaveContentPackages = true; const bool bFastSave = false; const bool bNotifyNoPackagesSaved = false; const bool bCanBeDeclined = true; bool DidPackagesNeedSaving; const bool WerePackagesSaved = FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved, bCanBeDeclined, &DidPackagesNeedSaving); if (DidPackagesNeedSaving && !WerePackagesSaved) { // Give warning dialog. const FText MessageText = NSLOCTEXT("LocalizationCultureActions", "UnsavedPackagesWarningDialogMessage", "There are unsaved changes. These changes may not be gathered from correctly."); const FText TitleText = NSLOCTEXT("LocalizationCultureActions", "UnsavedPackagesWarningDialogTitle", "Unsaved Changes Before Gather"); switch(FMessageDialog::Open(EAppMsgType::OkCancel, MessageText, &TitleText)) { case EAppReturnType::Cancel: { return; } break; } } } // Execute gather. const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsView().AsShared()); LocalizationCommandletTasks::GatherTargets(ParentWindow.ToSharedRef(), TargetSet->TargetObjects); for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { UpdateTargetFromReports(LocalizationTarget); } } void FLocalizationTargetSetDetailCustomization::ImportAllTargets() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsView().AsShared()); if (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = ParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultPath = FPaths::ConvertRelativePathToFull(FPaths::GameContentDir() / TEXT("Localization")); // Prompt the user for the directory FString OutputDirectory; if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("ImportAllTranslationsDialogTitle", "Import All Translations from Directory").ToString(), DefaultPath, OutputDirectory)) { LocalizationCommandletTasks::ImportTargets(ParentWindow.ToSharedRef(), TargetSet->TargetObjects, TOptional(OutputDirectory)); for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { UpdateTargetFromReports(LocalizationTarget); } } } } void FLocalizationTargetSetDetailCustomization::ExportAllTargets() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsView().AsShared()); if (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = ParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultPath = FPaths::ConvertRelativePathToFull(FPaths::GameContentDir() / TEXT("Localization")); // Prompt the user for the directory FString OutputDirectory; if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("ExportAllTranslationsDialogTitle", "Export All Translations to Directory").ToString(), DefaultPath, OutputDirectory)) { LocalizationCommandletTasks::ExportTargets(ParentWindow.ToSharedRef(), TargetSet->TargetObjects, TOptional(OutputDirectory)); } } } void FLocalizationTargetSetDetailCustomization::UpdateTargetFromReports(ULocalizationTarget* const LocalizationTarget) { //TArray< TSharedPtr > WordCountPropertyHandles; //const TSharedPtr TargetSettingsPropertyHandle = TargetEditor->GetTargetSettingsPropertyHandle(); //if (TargetSettingsPropertyHandle.IsValid() && TargetSettingsPropertyHandle->IsValidHandle()) //{ // const TSharedPtr NativeCultureStatisticsPropertyHandle = TargetSettingsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLocalizationTargetSettings, NativeCultureStatistics)); // if (NativeCultureStatisticsPropertyHandle.IsValid() && NativeCultureStatisticsPropertyHandle->IsValidHandle()) // { // const TSharedPtr WordCountPropertyHandle = NativeCultureStatisticsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FCultureStatistics, WordCount)); // if (WordCountPropertyHandle.IsValid() && WordCountPropertyHandle->IsValidHandle()) // { // WordCountPropertyHandles.Add(WordCountPropertyHandle); // } // } // const TSharedPtr SupportedCulturesStatisticsPropertyHandle = TargetSettingsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLocalizationTargetSettings, SupportedCulturesStatistics)); // if (SupportedCulturesStatisticsPropertyHandle.IsValid() && SupportedCulturesStatisticsPropertyHandle->IsValidHandle()) // { // uint32 SupportedCultureCount = 0; // SupportedCulturesStatisticsPropertyHandle->GetNumChildren(SupportedCultureCount); // for (uint32 i = 0; i < SupportedCultureCount; ++i) // { // const TSharedPtr ElementPropertyHandle = SupportedCulturesStatisticsPropertyHandle->GetChildHandle(i); // if (ElementPropertyHandle.IsValid() && ElementPropertyHandle->IsValidHandle()) // { // const TSharedPtr WordCountPropertyHandle = SupportedCulturesStatisticsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FCultureStatistics, WordCount)); // if (WordCountPropertyHandle.IsValid() && WordCountPropertyHandle->IsValidHandle()) // { // WordCountPropertyHandles.Add(WordCountPropertyHandle); // } // } // } // } //} //for (const TSharedPtr& WordCountPropertyHandle : WordCountPropertyHandles) //{ // WordCountPropertyHandle->NotifyPreChange(); //} LocalizationTarget->UpdateWordCountsFromCSV(); LocalizationTarget->UpdateStatusFromConflictReport(); //for (const TSharedPtr& WordCountPropertyHandle : WordCountPropertyHandles) //{ // WordCountPropertyHandle->NotifyPostChange(); //} } void FLocalizationTargetSetDetailCustomization::CompileAllTargets() { // Execute compile. const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsView().AsShared()); LocalizationCommandletTasks::CompileTargets(ParentWindow.ToSharedRef(), TargetSet->TargetObjects); } TSharedRef FLocalizationTargetSetDetailCustomization::OnGenerateRow(TSharedPtr TargetObjectPropertyHandle, const TSharedRef& Table) { return SNew(SLocalizationDashboardTargetRow, Table, DetailLayoutBuilder->GetPropertyUtilities(), TargetObjectPropertyHandle.ToSharedRef()); } FReply FLocalizationTargetSetDetailCustomization::OnNewTargetButtonClicked() { if(TargetObjectsPropertyHandle.IsValid() && TargetObjectsPropertyHandle->IsValidHandle()) { uint32 NewElementIndex; TargetObjectsPropertyHandle->AsArray()->GetNumElements(NewElementIndex); TargetObjectsPropertyHandle->AsArray()->AddItem(); NewEntryIndexToBeInitialized = NewElementIndex; } return FReply::Handled(); } #undef LOCTEXT_NAMESPACE