Files
UnrealEngineUWP/Engine/Source/Developer/InternationalizationSettings/Private/InternationalizationSettingsModelDetails.cpp

424 lines
13 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "InternationalizationSettingsModulePrivatePCH.h"
#define LOCTEXT_NAMESPACE "InternationalizationSettingsModelDetails"
/** Functions for sorting the languages */
struct FCompareCultureByNativeLanguage
{
static FText GetCultureNativeLanguageText( const TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture )
{
check( Culture.IsValid() );
const FString Language = Culture->GetNativeLanguage();
return FText::FromString(Language);
}
FORCEINLINE bool operator()( const TSharedPtr<FCulture, ESPMode::ThreadSafe> A, const TSharedPtr<FCulture, ESPMode::ThreadSafe> B ) const
{
check( A.IsValid() );
check( B.IsValid() );
return( GetCultureNativeLanguageText( A ).CompareToCaseIgnored( GetCultureNativeLanguageText( B ) ) ) < 0;
}
};
/** Functions for sorting the regions */
struct FCompareCultureByNativeRegion
{
static FText GetCultureNativeRegionText( const TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture )
{
check( Culture.IsValid() );
FString Region = Culture->GetNativeRegion();
if ( Region.IsEmpty() )
{
// Fallback to displaying the language, if no region is available
return LOCTEXT("NoSpecificRegionOption", "Non-Specific Region");
}
return FText::FromString(Region);
}
FORCEINLINE bool operator()( const TSharedPtr<FCulture, ESPMode::ThreadSafe> A, const TSharedPtr<FCulture, ESPMode::ThreadSafe> B ) const
{
check( A.IsValid() );
check( B.IsValid() );
// Non-Specific Region should appear before all else.
if(A->GetNativeRegion().IsEmpty())
{
return true;
}
// Non-Specific Region should appear before all else.
if(B->GetNativeRegion().IsEmpty())
{
return false;
}
// Compare native region strings.
return( GetCultureNativeRegionText( A ).CompareToCaseIgnored( GetCultureNativeRegionText( B ) ) ) < 0;
}
};
TSharedRef<IDetailCustomization> FInternationalizationSettingsModelDetails::MakeInstance()
{
TSharedRef<FInternationalizationSettingsModelDetails> InternationalizationSettingsModelDetails = MakeShareable(new FInternationalizationSettingsModelDetails());
return InternationalizationSettingsModelDetails;
}
FInternationalizationSettingsModelDetails::~FInternationalizationSettingsModelDetails()
{
check(Model.IsValid());
Model->OnSettingChanged().RemoveAll(this);
}
void FInternationalizationSettingsModelDetails::OnSettingsChanged()
{
FInternationalization& I18N = FInternationalization::Get();
check(Model.IsValid());
FString SavedCultureName = Model->GetCultureName();
if ( !SavedCultureName.IsEmpty() && SavedCultureName != I18N.GetCurrentCulture()->GetName() )
{
SelectedCulture = I18N.GetCulture(SavedCultureName);
RequiresRestart = true;
}
else
{
SelectedCulture = I18N.GetCurrentCulture();
RequiresRestart = false;
}
RefreshAvailableLanguages();
LanguageComboBox->SetSelectedItem(SelectedLanguage);
RefreshAvailableRegions();
RegionComboBox->SetSelectedItem(SelectedCulture);
}
void FInternationalizationSettingsModelDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
FInternationalization& I18N = FInternationalization::Get();
TArray< TWeakObjectPtr<UObject> > ObjectsBeingCustomized;
DetailBuilder.GetObjectsBeingCustomized(ObjectsBeingCustomized);
check(ObjectsBeingCustomized.Num() == 1);
if(ObjectsBeingCustomized[0].IsValid())
{
Model = Cast<UInternationalizationSettingsModel>(ObjectsBeingCustomized[0].Get());
}
check(Model.IsValid());
Model->OnSettingChanged().AddRaw(this, &FInternationalizationSettingsModelDetails::OnSettingsChanged);
// If the saved culture is not the same as the actual current culture, a restart is needed to sync them fully and properly.
FString SavedCultureName = Model->GetCultureName();
if ( !SavedCultureName.IsEmpty() && SavedCultureName != I18N.GetCurrentCulture()->GetName() )
{
SelectedCulture = I18N.GetCulture(SavedCultureName);
RequiresRestart = true;
}
else
{
SelectedCulture = I18N.GetCurrentCulture();
RequiresRestart = false;
}
// Populate all our cultures
RefreshAvailableCultures();
IDetailCategoryBuilder& CategoryBuilder = DetailBuilder.EditCategory("Internationalization");
const FText LanguageToolTipText = LOCTEXT("EditorLanguageTooltip", "Change the Editor language (requires restart to take effect)");
// For use in the Slate macros below, the type must be typedef'd to compile.
typedef TSharedPtr<FCulture, ESPMode::ThreadSafe> ThreadSafeCulturePtr;
CategoryBuilder.AddCustomRow("Language")
.NameContent()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.Padding( FMargin( 0, 1, 0, 1 ) )
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("EditorLanguageLabel", "Language"))
.Font(DetailBuilder.GetDetailFont())
.ToolTipText(LanguageToolTipText)
]
]
.ValueContent()
.MaxDesiredWidth(300.0f)
[
SAssignNew(LanguageComboBox, SComboBox< ThreadSafeCulturePtr > )
.OptionsSource( &AvailableLanguages )
.InitiallySelectedItem(SelectedLanguage)
.OnGenerateWidget(this, &FInternationalizationSettingsModelDetails::OnLanguageGenerateWidget, &DetailBuilder)
.ToolTipText(LanguageToolTipText)
.OnSelectionChanged(this, &FInternationalizationSettingsModelDetails::OnLanguageSelectionChanged)
.Content()
[
SNew(STextBlock)
.Text(this, &FInternationalizationSettingsModelDetails::GetCurrentLanguageText)
.Font(DetailBuilder.GetDetailFont())
]
];
const FText RegionToolTipText = LOCTEXT("EditorRegionTooltip", "Change the Editor region (requires restart to take effect)");
CategoryBuilder.AddCustomRow("Region")
.NameContent()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.Padding( FMargin( 0, 1, 0, 1 ) )
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("EditorRegionLabel", "Region"))
.Font(DetailBuilder.GetDetailFont())
.ToolTipText(RegionToolTipText)
]
]
.ValueContent()
.MaxDesiredWidth(300.0f)
[
SAssignNew(RegionComboBox, SComboBox< ThreadSafeCulturePtr > )
.OptionsSource( &AvailableRegions )
.InitiallySelectedItem(SelectedCulture)
.OnGenerateWidget(this, &FInternationalizationSettingsModelDetails::OnRegionGenerateWidget, &DetailBuilder)
.ToolTipText(RegionToolTipText)
.OnSelectionChanged(this, &FInternationalizationSettingsModelDetails::OnRegionSelectionChanged)
.IsEnabled(this, &FInternationalizationSettingsModelDetails::IsRegionSelectionAllowed)
.Content()
[
SNew(STextBlock)
.Text(this, &FInternationalizationSettingsModelDetails::GetCurrentRegionText)
.Font(DetailBuilder.GetDetailFont())
]
];
const FText FieldNamesToolTipText = LOCTEXT("EditorFieldNamesTooltip", "Toggle showing localized field names (requires restart to take effect)");
CategoryBuilder.AddCustomRow("FieldNames")
.NameContent()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.Padding( FMargin( 0, 1, 0, 1 ) )
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("EditorFieldNamesLabel", "Use Localized Field Names"))
.Font(DetailBuilder.GetDetailFont())
.ToolTipText(FieldNamesToolTipText)
]
]
.ValueContent()
.MaxDesiredWidth(300.0f)
[
SAssignNew(FieldNamesCheckBox, SCheckBox)
.IsChecked(Model->ShouldLoadLocalizedPropertyNames() ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked)
.ToolTipText(FieldNamesToolTipText)
.OnCheckStateChanged(this, &FInternationalizationSettingsModelDetails::ShoudLoadLocalizedFieldNamesCheckChanged)
];
CategoryBuilder.AddCustomRow("RestartWarning")
.Visibility( TAttribute<EVisibility>(this, &FInternationalizationSettingsModelDetails::GetInternationalizationRestartRowVisibility) )
.WholeRowContent()
.HAlign(HAlign_Center)
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(2.0f, 0.0f)
[
SNew( SImage )
.Image( FCoreStyle::Get().GetBrush("Icons.Warning") )
]
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
[
SNew( STextBlock )
.Text( LOCTEXT("RestartWarningText", "Changes require restart to take effect.") )
.Font(DetailBuilder.GetDetailFont())
]
];
}
void FInternationalizationSettingsModelDetails::RefreshAvailableCultures()
{
AvailableCultures.Empty();
FInternationalization::Get().GetCulturesWithAvailableLocalization(FPaths::GetEditorLocalizationPaths(), AvailableCultures, true);
// Update our selected culture based on the available choices
if ( !AvailableCultures.Contains( SelectedCulture ) )
{
SelectedCulture = NULL;
}
RefreshAvailableLanguages();
}
void FInternationalizationSettingsModelDetails::RefreshAvailableLanguages()
{
AvailableLanguages.Empty();
FString SelectedLanguageName;
if ( SelectedCulture.IsValid() )
{
SelectedLanguageName = SelectedCulture->GetNativeLanguage();
}
// Setup the language list
for( const auto& Culture : AvailableCultures )
{
const FString CultureRegionName = Culture->GetNativeRegion();
if ( CultureRegionName.IsEmpty() )
{
AvailableLanguages.Add( Culture );
// Do we have a match for the base language
const FString CultureLanguageName = Culture->GetNativeLanguage();
if ( SelectedLanguageName == CultureLanguageName)
{
SelectedLanguage = Culture;
}
}
}
AvailableLanguages.Sort( FCompareCultureByNativeLanguage() );
RefreshAvailableRegions();
}
void FInternationalizationSettingsModelDetails::RefreshAvailableRegions()
{
AvailableRegions.Empty();
TSharedPtr<FCulture, ESPMode::ThreadSafe> DefaultCulture = NULL;
if ( SelectedLanguage.IsValid() )
{
const FString SelectedLanguageName = SelectedLanguage->GetNativeLanguage();
// Setup the region list
for( const auto& Culture : AvailableCultures )
{
const FString CultureLanguageName = Culture->GetNativeLanguage();
if ( SelectedLanguageName == CultureLanguageName)
{
AvailableRegions.Add( Culture );
// If this doesn't have a valid region... assume it's the default
const FString CultureRegionName = Culture->GetNativeRegion();
if ( CultureRegionName.IsEmpty() )
{
DefaultCulture = Culture;
}
}
}
AvailableRegions.Sort( FCompareCultureByNativeRegion() );
}
// If we have a preferred default (or there's only one in the list), select that now
if ( DefaultCulture.IsValid() || AvailableCultures.Num() == 1 )
{
TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture = DefaultCulture.IsValid() ? DefaultCulture : AvailableCultures.Last();
// Set it as our default region, if one hasn't already been chosen
if ( !SelectedCulture.IsValid() && RegionComboBox.IsValid() )
{
// We have to update the combo box like this, otherwise it'll do a null selection when we next click on it
RegionComboBox->SetSelectedItem( Culture );
}
}
if ( RegionComboBox.IsValid() )
{
RegionComboBox->RefreshOptions();
}
}
FText FInternationalizationSettingsModelDetails::GetCurrentLanguageText() const
{
if( SelectedLanguage.IsValid() )
{
return FCompareCultureByNativeLanguage::GetCultureNativeLanguageText(SelectedLanguage);
}
return FText::GetEmpty();
}
TSharedRef<SWidget> FInternationalizationSettingsModelDetails::OnLanguageGenerateWidget( TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture, IDetailLayoutBuilder* DetailBuilder ) const
{
return SNew(STextBlock)
.Text(FCompareCultureByNativeLanguage::GetCultureNativeLanguageText(Culture))
.Font(DetailBuilder->GetDetailFont());
}
void FInternationalizationSettingsModelDetails::OnLanguageSelectionChanged( TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture, ESelectInfo::Type SelectionType )
{
SelectedLanguage = Culture;
SelectedCulture = NULL;
RegionComboBox->ClearSelection();
RefreshAvailableRegions();
}
FText FInternationalizationSettingsModelDetails::GetCurrentRegionText() const
{
if( SelectedCulture.IsValid() )
{
return FCompareCultureByNativeRegion::GetCultureNativeRegionText(SelectedCulture);
}
return FText::GetEmpty();
}
TSharedRef<SWidget> FInternationalizationSettingsModelDetails::OnRegionGenerateWidget( TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture, IDetailLayoutBuilder* DetailBuilder ) const
{
return SNew(STextBlock)
.Text(FCompareCultureByNativeRegion::GetCultureNativeRegionText(Culture))
.Font(DetailBuilder->GetDetailFont());
}
void FInternationalizationSettingsModelDetails::OnRegionSelectionChanged( TSharedPtr<FCulture, ESPMode::ThreadSafe> Culture, ESelectInfo::Type SelectionType )
{
SelectedCulture = Culture;
HandleShutdownPostPackagesSaved();
}
bool FInternationalizationSettingsModelDetails::IsRegionSelectionAllowed() const
{
return SelectedLanguage.IsValid();
}
EVisibility FInternationalizationSettingsModelDetails::GetInternationalizationRestartRowVisibility() const
{
return RequiresRestart ? EVisibility::Visible : EVisibility::Collapsed;
}
void FInternationalizationSettingsModelDetails::ShoudLoadLocalizedFieldNamesCheckChanged(ESlateCheckBoxState::Type CheckState)
{
HandleShutdownPostPackagesSaved();
}
void FInternationalizationSettingsModelDetails::HandleShutdownPostPackagesSaved()
{
if ( SelectedCulture.IsValid() )
{
check(Model.IsValid());
Model->SetCultureName(SelectedCulture->GetName());
Model->ShouldLoadLocalizedPropertyNames(FieldNamesCheckBox->IsChecked());
if(SelectedCulture != FInternationalization::Get().GetCurrentCulture())
{
RequiresRestart = true;
}
else
{
RequiresRestart = false;
}
}
}
#undef LOCTEXT_NAMESPACE