// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "EditorSettingsViewerPrivatePCH.h" #include "Tests/AutomationTestSettings.h" #define LOCTEXT_NAMESPACE "FEditorSettingsViewerModule" static const FName EditorSettingsTabName("EditorSettings"); /** * Implements the EditorSettingsViewer module. */ class FEditorSettingsViewerModule : public IModuleInterface , public ISettingsViewer { public: // ISettingsViewer interface virtual void ShowSettings( const FName& CategoryName, const FName& SectionName ) override { FGlobalTabmanager::Get()->InvokeTab(EditorSettingsTabName); ISettingsEditorModelPtr SettingsEditorModel = SettingsEditorModelPtr.Pin(); if (SettingsEditorModel.IsValid()) { ISettingsCategoryPtr Category = SettingsEditorModel->GetSettingsContainer()->GetCategory(CategoryName); if (Category.IsValid()) { SettingsEditorModel->SelectSection(Category->GetSection(SectionName)); } } } public: // IModuleInterface interface virtual void StartupModule( ) override { ISettingsModule* SettingsModule = ISettingsModule::Get(); if (SettingsModule != nullptr) { RegisterGeneralSettings(*SettingsModule); RegisterLevelEditorSettings(*SettingsModule); RegisterContentEditorsSettings(*SettingsModule); SettingsModule->RegisterViewer("Editor", *this); } FGlobalTabmanager::Get()->RegisterNomadTabSpawner(EditorSettingsTabName, FOnSpawnTab::CreateRaw(this, &FEditorSettingsViewerModule::HandleSpawnSettingsTab)) .SetDisplayName(LOCTEXT("EditorSettingsTabTitle", "Editor Preferences")) .SetMenuType(ETabSpawnerMenuType::Hide); } virtual void ShutdownModule( ) override { FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(EditorSettingsTabName); UnregisterSettings(); } virtual bool SupportsDynamicReloading( ) override { return true; } protected: /** * Registers general Editor settings. */ void RegisterGeneralSettings( ISettingsModule& SettingsModule ) { // automation settings SettingsModule.RegisterSettings("Editor", "General", "AutomationTest", LOCTEXT("AutomationSettingsName", "Automation"), LOCTEXT("AutomationSettingsDescription", "Set up automation test assets."), GetMutableDefault() ); // input bindings FSettingsSectionDelegates InputBindingDelegates; InputBindingDelegates.ExportDelegate = FOnSettingsSectionExport::CreateRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsExport); InputBindingDelegates.ImportDelegate = FOnSettingsSectionImport::CreateRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsImport); InputBindingDelegates.ResetDefaultsDelegate = FOnSettingsSectionResetDefaults::CreateRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsResetToDefault); InputBindingDelegates.SaveDelegate = FOnSettingsSectionSave::CreateRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsSave); FSettingsSectionDelegates RegionAndLanguageDelegates; RegionAndLanguageDelegates.ExportDelegate = FOnSettingsSectionExport::CreateRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageExport); RegionAndLanguageDelegates.ImportDelegate = FOnSettingsSectionImport::CreateRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageImport); RegionAndLanguageDelegates.SaveDefaultsDelegate = FOnSettingsSectionSaveDefaults::CreateRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageSaveDefaults); RegionAndLanguageDelegates.ResetDefaultsDelegate = FOnSettingsSectionResetDefaults::CreateRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageResetToDefault); SettingsModule.RegisterSettings("Editor", "General", "Internationalization", LOCTEXT("InternationalizationSettingsModelName", "Region & Language"), LOCTEXT("InternationalizationSettingsModelDescription", "Configure the editor's behavior to use a language and fit a region's culture."), GetMutableDefault(), RegionAndLanguageDelegates ); TWeakPtr InputBindingEditorPanel = FModuleManager::LoadModuleChecked("InputBindingEditor").CreateInputBindingEditorPanel(); SettingsModule.RegisterSettings("Editor", "General", "InputBindings", LOCTEXT("InputBindingsSettingsName", "Keyboard Shortcuts"), LOCTEXT("InputBindingsSettingsDescription", "Configure keyboard shortcuts to quickly invoke operations."), InputBindingEditorPanel.Pin().ToSharedRef(), InputBindingDelegates ); // loading & saving features SettingsModule.RegisterSettings("Editor", "General", "LoadingSaving", LOCTEXT("LoadingSavingSettingsName", "Loading & Saving"), LOCTEXT("LoadingSavingSettingsDescription", "Change how the Editor loads and saves files."), GetMutableDefault() ); // @todo thomass: proper settings support for source control module GetMutableDefault()->SccHackInitialize(); // misc unsorted settings SettingsModule.RegisterSettings("Editor", "General", "UserSettings", LOCTEXT("UserSettingsName", "Miscellaneous"), LOCTEXT("UserSettingsDescription", "Customize the behavior, look and feel of the editor."), &GEditor->AccessEditorUserSettings() ); // experimental features SettingsModule.RegisterSettings("Editor", "General", "Experimental", LOCTEXT("ExperimentalettingsName", "Experimental"), LOCTEXT("ExperimentalSettingsDescription", "Enable and configure experimental Editor features."), GetMutableDefault() ); } /** * Registers Level Editor settings */ void RegisterLevelEditorSettings( ISettingsModule& SettingsModule ) { // play-in settings SettingsModule.RegisterSettings("Editor", "LevelEditor", "PlayIn", LOCTEXT("LevelEditorPlaySettingsName", "Play"), LOCTEXT("LevelEditorPlaySettingsDescription", "Set up window sizes and other options for the Play In Editor (PIE) feature."), GetMutableDefault() ); // view port settings SettingsModule.RegisterSettings("Editor", "LevelEditor", "Viewport", LOCTEXT("LevelEditorViewportSettingsName", "Viewports"), LOCTEXT("LevelEditorViewportSettingsDescription", "Configure the look and feel of the Level Editor view ports."), GetMutableDefault() ); // miscellaneous settings SettingsModule.RegisterSettings("Editor", "LevelEditor", "Misc", LOCTEXT("LevelEditorMiscSettingsName", "Miscellaneous"), LOCTEXT("LevelEditorMiscSettingsDescription", "Configure miscellaneous settings for the Level Editor."), GetMutableDefault() ); } /** * Registers Other Tools settings */ void RegisterContentEditorsSettings( ISettingsModule& SettingsModule ) { // content browser SettingsModule.RegisterSettings("Editor", "ContentEditors", "ContentBrowser", LOCTEXT("ContentEditorsContentBrowserSettingsName", "Content Browser"), LOCTEXT("ContentEditorsContentBrowserSettingsDescription", "Change the behavior of the Content Browser."), GetMutableDefault() ); // destructable mesh editor /* SettingsModule.RegisterSettings("Editor", "ContentEditors", "DestructableMeshEditor", LOCTEXT("ContentEditorsDestructableMeshEditorSettingsName", "Destructable Mesh Editor"), LOCTEXT("ContentEditorsDestructableMeshEditorSettingsDescription", "Change the behavior of the Destructable Mesh Editor."), GetMutableDefault() );*/ // graph editors SettingsModule.RegisterSettings("Editor", "ContentEditors", "GraphEditor", LOCTEXT("ContentEditorsGraphEditorSettingsName", "Graph Editors"), LOCTEXT("ContentEditorsGraphEditorSettingsDescription", "Customize Anim, Blueprint and Material Editor."), GetMutableDefault() ); } /** * Unregisters all settings. */ void UnregisterSettings( ) { ISettingsModule* SettingsModule = ISettingsModule::Get(); if (SettingsModule != nullptr) { SettingsModule->UnregisterViewer("Editor"); // general settings SettingsModule->UnregisterSettings("Editor", "General", "InputBindings"); SettingsModule->UnregisterSettings("Editor", "General", "LoadingSaving"); SettingsModule->UnregisterSettings("Editor", "General", "GameAgnostic"); SettingsModule->UnregisterSettings("Editor", "General", "UserSettings"); SettingsModule->UnregisterSettings("Editor", "General", "AutomationTest"); SettingsModule->UnregisterSettings("Editor", "General", "Experimental"); // level editor settings SettingsModule->UnregisterSettings("Editor", "LevelEditor", "PlayIn"); SettingsModule->UnregisterSettings("Editor", "LevelEditor", "Viewport"); // other tools SettingsModule->UnregisterSettings("Editor", "ContentEditors", "ContentBrowser"); // SettingsModule->UnregisterSettings("Editor", "ContentEditors", "DestructableMeshEditor"); SettingsModule->UnregisterSettings("Editor", "ContentEditors", "GraphEditor"); } } private: // Handles creating the editor settings tab. TSharedRef HandleSpawnSettingsTab( const FSpawnTabArgs& SpawnTabArgs ) { ISettingsModule* SettingsModule = ISettingsModule::Get(); TSharedRef SettingsEditor = SNullWidget::NullWidget; if (SettingsModule != nullptr) { ISettingsContainerPtr SettingsContainer = SettingsModule->GetContainer("Editor"); if (SettingsContainer.IsValid()) { ISettingsEditorModule& SettingsEditorModule = ISettingsEditorModule::GetRef(); ISettingsEditorModelRef SettingsEditorModel = SettingsEditorModule.CreateModel(SettingsContainer.ToSharedRef()); SettingsEditor = SettingsEditorModule.CreateEditor(SettingsEditorModel); SettingsEditorModelPtr = SettingsEditorModel; } } return SNew(SDockTab) .TabRole(ETabRole::NomadTab) [ SettingsEditor ]; } private: // Show a warning that the editor will require a restart and return its result EAppReturnType::Type ShowRestartWarning(const FText& Title) const { return OpenMsgDlgInt(EAppMsgType::OkCancel, LOCTEXT("ActionRestartMsg", "Imported settings won't be applied until the editor is restarted. Do you wish to restart now (you will be prompted to save any changes)?" ), Title); } // Backup a file bool BackupFile(const FString& SrcFilename, const FString& DstFilename) { if (IFileManager::Get().Copy(*DstFilename, *SrcFilename) == COPY_OK) { return true; } // log error FMessageLog EditorErrors("EditorErrors"); if(!FPaths::FileExists(SrcFilename)) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("FileName"), FText::FromString(SrcFilename)); EditorErrors.Warning(FText::Format(LOCTEXT("UnsuccessfulBackup_NoExist_Notification", "Unsuccessful backup! {FileName} does not exist!"), Arguments)); } else if(IFileManager::Get().IsReadOnly(*DstFilename)) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("FileName"), FText::FromString(DstFilename)); EditorErrors.Warning(FText::Format(LOCTEXT("UnsuccessfulBackup_ReadOnly_Notification", "Unsuccessful backup! {FileName} is read-only!"), Arguments)); } else { FFormatNamedArguments Arguments; Arguments.Add(TEXT("SourceFileName"), FText::FromString(SrcFilename)); Arguments.Add(TEXT("BackupFileName"), FText::FromString(DstFilename)); // We don't specifically know why it failed, this is a fallback. EditorErrors.Warning(FText::Format(LOCTEXT("UnsuccessfulBackup_Fallback_Notification", "Unsuccessful backup of {SourceFileName} to {BackupFileName}"), Arguments)); } EditorErrors.Notify(LOCTEXT("BackupUnsuccessful_Title", "Backup Unsuccessful!")); return false; } // Handles exporting input bindings to a file bool HandleInputBindingsExport( const FString& Filename ) { FInputBindingManager::Get().SaveInputBindings(); GConfig->Flush(false, GEditorKeyBindingsIni); return BackupFile(GEditorKeyBindingsIni, Filename); } // Handles importing input bindings from a file bool HandleInputBindingsImport( const FString& Filename ) { if( EAppReturnType::Ok == ShowRestartWarning(LOCTEXT("ImportKeyBindings_Title", "Import Key Bindings"))) { FUnrealEdMisc::Get().SetConfigRestoreFilename(Filename, GEditorKeyBindingsIni); FUnrealEdMisc::Get().RestartEditor(false); return true; } return false; } // Handles resetting input bindings back to the defaults bool HandleInputBindingsResetToDefault() { if( EAppReturnType::Ok == ShowRestartWarning(LOCTEXT("ResetKeyBindings_Title", "Reset Key Bindings"))) { FInputBindingManager::Get().RemoveUserDefinedGestures(); GConfig->Flush(false, GEditorKeyBindingsIni); FUnrealEdMisc::Get().RestartEditor(false); return true; } return false; } // Handles saving default input bindings. // This only gets called by SSettingsEditor::HandleImportButtonClicked when importing new settings, // and its implementation here is just to flush custom input bindings so that editor shutdown doesn't // overwrite the imported settings just copied across. bool HandleInputBindingsSave() { FInputBindingManager::Get().RemoveUserDefinedGestures(); GConfig->Flush(false, GEditorKeyBindingsIni); return true; } bool HandleRegionAndLanguageExport(const FString& FileName) { FString CultureName = GetMutableDefault()->GetCultureName(); GConfig->SetString( TEXT("Internationalization"), TEXT("Culture"), *CultureName, FileName ); GConfig->Flush( false, FileName ); return true; } bool HandleRegionAndLanguageImport(const FString& FileName) { FString CultureName; GConfig->LoadFile(FileName); GConfig->GetString( TEXT("Internationalization"), TEXT("Culture"), CultureName, FileName ); GetMutableDefault()->SetCultureName(CultureName); return true; } bool HandleRegionAndLanguageSaveDefaults() { GetMutableDefault()->SaveDefaults(); return true; } bool HandleRegionAndLanguageResetToDefault() { GetMutableDefault()->ResetToDefault(); return true; } private: // Holds a pointer to the settings editor's view model. TWeakPtr SettingsEditorModelPtr; }; IMPLEMENT_MODULE(FEditorSettingsViewerModule, EditorSettingsViewer); #undef LOCTEXT_NAMESPACE