// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "MainFramePrivatePCH.h" #define LOCTEXT_NAMESPACE "MainFrameActions" DEFINE_LOG_CATEGORY_STATIC(MainFrameActions, Log, All); TSharedRef< FUICommandList > FMainFrameCommands::ActionList( new FUICommandList() ); TWeakPtr FMainFrameActionCallbacks::ChoosePackagesToCheckInNotification; FMainFrameCommands::FMainFrameCommands() : TCommands( TEXT("MainFrame"), // Context name for fast lookup LOCTEXT( "MainFrame", "Main Frame" ), // Localized context name for displaying NAME_None, // No parent context FEditorStyle::GetStyleSetName() ), // Icon Style Set ToggleFullscreenConsoleCommand( TEXT( "MainFrame.ToggleFullscreen" ), TEXT( "Toggles the editor between \"full screen\" mode and \"normal\" mode. In full screen mode, the task bar and window title area are hidden." ), FConsoleCommandDelegate::CreateStatic( &FMainFrameActionCallbacks::ToggleFullscreen_Execute ) ) { } void FMainFrameCommands::RegisterCommands() { // The global action list was created at static initialization time. Create a handler for otherwise unhandled keyboard input to route key commands through this list. FSlateApplication::Get().SetUnhandledKeyDownEventHandler( FOnKeyboardEvent::CreateStatic( &FMainFrameActionCallbacks::OnUnhandledKeyDownEvent ) ); // Make a default can execute action that disables input when in debug mode FCanExecuteAction DefaultExecuteAction = FCanExecuteAction::CreateStatic( &FMainFrameActionCallbacks::DefaultCanExecuteAction ); UI_COMMAND( SaveAll, "Save All", "Saves all unsaved levels and assets to disk", EUserInterfaceActionType::Button, FInputGesture( EModifierKey::Control, EKeys::S ) ); ActionList->MapAction( SaveAll, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::SaveAll ), DefaultExecuteAction ); UI_COMMAND( ChooseFilesToSave, "Choose Files to Save...", "Opens a dialog with save options for content and levels", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( ChooseFilesToSave, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ChoosePackagesToSave ), DefaultExecuteAction ); UI_COMMAND( ChooseFilesToCheckIn, "Submit to Source Control...", "Opens a dialog with check in options for content and levels", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( ChooseFilesToCheckIn, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ChoosePackagesToCheckIn ), FCanExecuteAction::CreateStatic( &FMainFrameActionCallbacks::CanChoosePackagesToCheckIn ) ); UI_COMMAND( ConnectToSourceControl, "Connect To Source Control...", "Connect to source control to allow source control operations to be performed on content and levels.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( ConnectToSourceControl, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ConnectToSourceControl ), DefaultExecuteAction ); UI_COMMAND( NewProject, "New Project...", "Opens a dialog to create a new game project", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( NewProject, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::NewProject, false, true), DefaultExecuteAction ); UI_COMMAND( OpenProject, "Open Project...", "Opens a dialog to choose a game project to open", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( OpenProject, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::NewProject, true, false), DefaultExecuteAction ); UI_COMMAND( AddCodeToProject, "Add Code to Project...", "Adds C++ code to the project. The code can only be compiled if you have an appropriate C++ compiler installed.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( AddCodeToProject, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::AddCodeToProject ), FCanExecuteAction::CreateStatic( &FSourceCodeNavigation::IsCompilerAvailable ) ); UI_COMMAND( RefreshCodeProject, "Refresh code project", "Refreshes your C++ code project.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( RefreshCodeProject, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::RefreshCodeProject ), DefaultExecuteAction ); UI_COMMAND( OpenIDE, "Open IDE", "Opens your C++ code in an integrated development environment.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( OpenIDE, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::OpenIDE ), DefaultExecuteAction ); UI_COMMAND( PackagingSettings, "Packaging Settings...", "Opens the settings for project packaging", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( PackagingSettings, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::PackagingSettings ), DefaultExecuteAction ); const int32 MaxProjects = 20; for( int32 CurProjectIndex = 0; CurProjectIndex < MaxProjects; ++CurProjectIndex ) { // NOTE: The actual label and tool-tip will be overridden at runtime when the command is bound to a menu item, however // we still need to set one here so that the key bindings UI can function properly FFormatNamedArguments Arguments; Arguments.Add(TEXT("CurrentProjectIndex"), CurProjectIndex); const FText Message = FText::Format( LOCTEXT( "SwitchProject", "Switch Project {CurrentProjectIndex}" ), Arguments ); TSharedRef< FUICommandInfo > SwitchProject = FUICommandInfoDecl( this->AsShared(), FName( *FString::Printf( TEXT( "SwitchProject%i" ), CurProjectIndex ) ), Message, LOCTEXT( "SwitchProjectToolTip", "Restarts the editor and switches to selected project" ) ) .UserInterfaceType( EUserInterfaceActionType::Button ) .DefaultGesture( FInputGesture() ); SwitchProjectCommands.Add( SwitchProject ); ActionList->MapAction( SwitchProjectCommands[ CurProjectIndex ], FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::SwitchProjectByIndex, CurProjectIndex ), FCanExecuteAction::CreateStatic( &FMainFrameActionCallbacks::CanSwitchToProject, CurProjectIndex ), FIsActionChecked::CreateStatic( &FMainFrameActionCallbacks::IsSwitchProjectChecked, CurProjectIndex ) ); } UI_COMMAND( Exit, "Exit", "Exits the application", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( Exit, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::Exit ), DefaultExecuteAction ); ActionList->MapAction( FGenericCommands::Get().Undo, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ExecuteExecCommand, FString( TEXT("TRANSACTION UNDO") ) ), FCanExecuteAction::CreateStatic( &FMainFrameActionCallbacks::Undo_CanExecute ) ); ActionList->MapAction( FGenericCommands::Get().Redo, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ExecuteExecCommand, FString( TEXT("TRANSACTION REDO") ) ), FCanExecuteAction::CreateStatic( &FMainFrameActionCallbacks::Redo_CanExecute ) ); UI_COMMAND( OpenDeviceManagerApp, "Device Manager", "Opens up the device manager app", EUserInterfaceActionType::Check, FInputGesture() ); ActionList->MapAction( OpenDeviceManagerApp, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::OpenSlateApp, FName( TEXT( "DeviceManager" ) ) ), FCanExecuteAction(), FIsActionChecked::CreateStatic( &FMainFrameActionCallbacks::OpenSlateApp_IsChecked, FName( TEXT( "DeviceManager" ) ) ) ); UI_COMMAND( OpenSessionManagerApp, "Session Manager", "Opens up the session manager app", EUserInterfaceActionType::Check, FInputGesture() ); ActionList->MapAction( OpenSessionManagerApp, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::OpenSlateApp, FName( "SessionFrontend" ) ), FCanExecuteAction(), FIsActionChecked::CreateStatic( &FMainFrameActionCallbacks::OpenSlateApp_IsChecked, FName("SessionFrontend" ) ) ); UI_COMMAND(VisitWiki, "Wiki...", "Go to the Unreal Engine Wiki page", EUserInterfaceActionType::Button, FInputGesture()); ActionList->MapAction(VisitWiki, FExecuteAction::CreateStatic(&FMainFrameActionCallbacks::VisitWiki)); UI_COMMAND(VisitForums, "Forums...", "Go to the Unreal Engine forums", EUserInterfaceActionType::Button, FInputGesture()); ActionList->MapAction(VisitForums, FExecuteAction::CreateStatic(&FMainFrameActionCallbacks::VisitForums)); UI_COMMAND( VisitAskAQuestionPage, "Ask a Question...", "Have a question? Go here to ask about anything and everything related to Unreal.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( VisitAskAQuestionPage, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::VisitAskAQuestionPage ) ); UI_COMMAND( VisitSearchForAnswersPage, "Answer Hub...", "Searches for useful answers on UDN provided by other users and experts.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( VisitSearchForAnswersPage, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::VisitSearchForAnswersPage ) ); UI_COMMAND( VisitSupportWebSite, "Unreal Engine Support Web Site...", "Navigates to the Unreal Engine Support web site's main page.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( VisitSupportWebSite, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::VisitSupportWebSite ) ); UI_COMMAND( VisitEpicGamesDotCom, "Visit UnrealEngine.com...", "Navigates to UnrealEngine.com where you can learn more about Unreal Technology.", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( VisitEpicGamesDotCom, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::VisitEpicGamesDotCom ) ); UI_COMMAND( AboutUnrealEd, "About Editor...", "Displays application credits and copyright information", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( AboutUnrealEd, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::AboutUnrealEd_Execute ) ); UI_COMMAND( ResetLayout, "Reset Layout...", "Make a backup of your user settings and reset the layout customizations", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( ResetLayout, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ResetLayout) ); UI_COMMAND( SaveLayout, "Save Layout", "Save the layout customizations", EUserInterfaceActionType::Button, FInputGesture() ); ActionList->MapAction( SaveLayout, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::SaveLayout) ); UI_COMMAND( ToggleFullscreen, "Enable Fullscreen", "Enables fullscreen mode for the application, expanding across the entire monitor", EUserInterfaceActionType::ToggleButton, FInputGesture(EModifierKey::Shift, EKeys::F11) ); ActionList->MapAction( ToggleFullscreen, FExecuteAction::CreateStatic( &FMainFrameActionCallbacks::ToggleFullscreen_Execute ), FCanExecuteAction(), FIsActionChecked::CreateStatic( &FMainFrameActionCallbacks::FullScreen_IsChecked ) ); UI_COMMAND(OpenWidgetReflector, "Open Widget Reflector", "Opens the Widget Reflector", EUserInterfaceActionType::Button, FInputGesture(EModifierKey::Shift | EModifierKey::Control , EKeys::W)); ActionList->MapAction(OpenWidgetReflector, FExecuteAction::CreateStatic(&FMainFrameActionCallbacks::OpenWidgetReflector_Execute)); FGlobalEditorCommonCommands::MapActions(ActionList); } FReply FMainFrameActionCallbacks::OnUnhandledKeyDownEvent(const FKeyboardEvent& InKeyboardEvent) { if ( FMainFrameCommands::ActionList->ProcessCommandBindings( InKeyboardEvent ) ) { return FReply::Handled(); } else if( GEditor->PlayWorld && InKeyboardEvent.GetKey() == EKeys::Escape ) { FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked< FLevelEditorModule >(TEXT("LevelEditor")); if( LevelEditor.GetLevelEditorTab()->IsForeground() ) { // Escape that gets this far should end the play map if we have one // We have to do this here because nothing else has focus and escape should always end the active PIE session. GEditor->RequestEndPlayMap(); } } return FReply::Unhandled(); } bool FMainFrameActionCallbacks::DefaultCanExecuteAction() { return FSlateApplication::Get().IsNormalExecution(); } void FMainFrameActionCallbacks::ChoosePackagesToSave() { const bool bPromptUserToSave = true; const bool bSaveMapPackages = true; const bool bSaveContentPackages = true; const bool bFastSave = false; const bool bClosingEditor = false; const bool bNotifyNoPackagesSaved = true; FEditorFileUtils::SaveDirtyPackages( bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved ); } void FMainFrameActionCallbacks::ChoosePackagesToCheckInCompleted(TArray LoadedPackages, TArray PackageNames) { if (ChoosePackagesToCheckInNotification.IsValid()) { ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout(); } ChoosePackagesToCheckInNotification.Reset(); check(PackageNames.Num() > 0); // Prompt the user to ask if they would like to first save any dirty packages they are trying to check-in const FEditorFileUtils::EPromptReturnCode UserResponse = FEditorFileUtils::PromptForCheckoutAndSave( LoadedPackages, true, true ); // If the user elected to save dirty packages, but one or more of the packages failed to save properly OR if the user // canceled out of the prompt, don't follow through on the check-in process const bool bShouldProceed = ( UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Success || UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Declined ); if ( bShouldProceed ) { FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked(TEXT("AssetTools")); FSourceControlWindows::PromptForCheckin(PackageNames); } else { // If a failure occurred, alert the user that the check-in was aborted. This warning shouldn't be necessary if the user cancelled // from the dialog, because they obviously intended to cancel the whole operation. if ( UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Failure ) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "SCC_Checkin_Aborted", "Check-in aborted as a result of save failure.") ); } } } void FMainFrameActionCallbacks::ChoosePackagesToCheckInCancelled(FSourceControlOperationRef InOperation) { ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); SourceControlProvider.CancelOperation(InOperation); if (ChoosePackagesToCheckInNotification.IsValid()) { ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout(); } ChoosePackagesToCheckInNotification.Reset(); } void FMainFrameActionCallbacks::ChoosePackagesToCheckInCallback(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult) { if (ChoosePackagesToCheckInNotification.IsValid()) { ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout(); } ChoosePackagesToCheckInNotification.Reset(); if(InResult == ECommandResult::Succeeded) { // Get a list of all the checked out packages int32 NumSelectedNames = 0; int32 NumSelectedPackages = 0; TArray PackageNames; TArray LoadedPackages; TMap PackageStates; FEditorFileUtils::FindAllSubmittablePackageFiles( PackageStates, true ); for (TMap::TConstIterator PackageIter(PackageStates); PackageIter; ++PackageIter) { const FString Filename = *PackageIter.Key(); const FString PackageName = FPackageName::FilenameToLongPackageName(Filename); const FSourceControlStatePtr CurPackageSCCState = PackageIter.Value(); UPackage* Package = FindPackage(NULL, *PackageName); // Put pre-selected items at the start of the list if (CurPackageSCCState.IsValid() && CurPackageSCCState->IsSourceControlled()) { if (Package != NULL) { LoadedPackages.Insert(Package, NumSelectedPackages++); } PackageNames.Insert(PackageName, NumSelectedNames++); } else { if (Package != NULL) { LoadedPackages.Add(Package); } PackageNames.Add(PackageName); } } if ( PackageNames.Num() > 0 ) { ChoosePackagesToCheckInCompleted(LoadedPackages, PackageNames); } else { FMessageLog EditorErrors("EditorErrors"); EditorErrors.Warning(LOCTEXT( "NoAssetsToCheckIn", "No assets to check in!")); EditorErrors.Notify(); } } else if(InResult == ECommandResult::Failed) { FMessageLog EditorErrors("EditorErrors"); EditorErrors.Warning(LOCTEXT( "CheckInOperationFailed", "Failed checking source control status!")); EditorErrors.Notify(); } } void FMainFrameActionCallbacks::ChoosePackagesToCheckIn() { if ( ISourceControlModule::Get().IsEnabled() ) { if( ISourceControlModule::Get().GetProvider().IsAvailable() ) { // make sure we update the SCC status of all packages (this could take a long time, so we will run it as a background task) TArray Packages; FEditorFileUtils::FindAllPackageFiles(Packages); ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); FSourceControlOperationRef Operation = ISourceControlOperation::Create(); SourceControlProvider.Execute(Operation, SourceControlHelpers::PackageFilenames(Packages), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateStatic(&FMainFrameActionCallbacks::ChoosePackagesToCheckInCallback)); if (ChoosePackagesToCheckInNotification.IsValid()) { ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout(); } FNotificationInfo Info(LOCTEXT("ChooseAssetsToCheckInIndicator", "Checking for assets to check in...")); Info.bFireAndForget = false; Info.ExpireDuration = 0.0f; Info.FadeOutDuration = 1.0f; if(SourceControlProvider.CanCancelOperation(Operation)) { Info.ButtonDetails.Add(FNotificationButtonInfo( LOCTEXT("ChoosePackagesToCheckIn_CancelButton", "Cancel"), LOCTEXT("ChoosePackagesToCheckIn_CancelButtonTooltip", "Cancel the check in operation."), FSimpleDelegate::CreateStatic(&FMainFrameActionCallbacks::ChoosePackagesToCheckInCancelled, Operation) )); } ChoosePackagesToCheckInNotification = FSlateNotificationManager::Get().AddNotification(Info); if (ChoosePackagesToCheckInNotification.IsValid()) { ChoosePackagesToCheckInNotification.Pin()->SetCompletionState(SNotificationItem::CS_Pending); } } else { FMessageLog EditorErrors("EditorErrors"); EditorErrors.Warning(LOCTEXT( "NoSCCConnection", "No connection to source control available!")); EditorErrors.Notify(); } } } bool FMainFrameActionCallbacks::CanChoosePackagesToCheckIn() { return !ChoosePackagesToCheckInNotification.IsValid(); } void FMainFrameActionCallbacks::ConnectToSourceControl() { ISourceControlModule::Get().ShowLoginDialog(FSourceControlLoginClosed(), ELoginWindowMode::Modeless); } void FMainFrameActionCallbacks::SaveAll() { const bool bPromptUserToSave = false; const bool bSaveMapPackages = true; const bool bSaveContentPackages = true; const bool bFastSave = false; FEditorFileUtils::SaveDirtyPackages( bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave ); } TArray FMainFrameActionCallbacks::ProjectNames; void FMainFrameActionCallbacks::CacheProjectNames() { ProjectNames.Empty(); // The switch project menu is filled with recently opened project files ProjectNames = GEditor->GetGameAgnosticSettings().RecentlyOpenedProjectFiles; } void FMainFrameActionCallbacks::NewProject( bool bAllowProjectOpening, bool bAllowProjectCreate ) { if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning()) { return; } TSharedRef NewProjectWindow = SNew(SWindow) .Title(LOCTEXT( "SelectProjectWindowHeader", "Select Project")) .ClientSize( FVector2D(1280, 720) ) .SizingRule( ESizingRule::FixedSize ) .SupportsMinimize(false) .SupportsMaximize(false); NewProjectWindow->SetContent( FGameProjectGenerationModule::Get().CreateGameProjectDialog(bAllowProjectOpening, bAllowProjectCreate) ); IMainFrameModule& MainFrameModule = FModuleManager::GetModuleChecked(TEXT("MainFrame")); if (MainFrameModule.GetParentWindow().IsValid()) { FSlateApplication::Get().AddWindowAsNativeChild(NewProjectWindow, MainFrameModule.GetParentWindow().ToSharedRef()); } else { FSlateApplication::Get().AddWindow(NewProjectWindow); } } void FMainFrameActionCallbacks::AddCodeToProject() { FGameProjectGenerationModule::Get().OpenAddCodeToProjectDialog(); } void FMainFrameActionCallbacks::CookContent( const FName InPlatformInfoName ) { const PlatformInfo::FPlatformInfo* const PlatformInfo = PlatformInfo::FindPlatformInfo(InPlatformInfoName); check(PlatformInfo); FString OptionalParams; if (!FModuleManager::LoadModuleChecked("ProjectTargetPlatformEditor").ShowUnsupportedTargetWarning(PlatformInfo->VanillaPlatformName)) { return; } if (PlatformInfo->TargetPlatformName == FName("MacNoEditor")) { OptionalParams += TEXT(" -targetplatform=Mac"); } else if (PlatformInfo->TargetPlatformName == FName("LinuxNoEditor")) { OptionalParams += TEXT(" -targetplatform=Linux"); } // Append any extra UAT flags specified for this platform flavor if (!PlatformInfo->UATCommandLine.IsEmpty()) { OptionalParams += TEXT(" "); OptionalParams += PlatformInfo->UATCommandLine; } FString ExecutableName = FPlatformProcess::ExecutableName(false); #if PLATFORM_WINDOWS // turn UE4editor into UE4editor-cmd if(ExecutableName.EndsWith(".exe", ESearchCase::IgnoreCase) && !FPaths::GetBaseFilename(ExecutableName).EndsWith("-cmd", ESearchCase::IgnoreCase)) { FString NewExeName = ExecutableName.Left(ExecutableName.Len() - 4) + "-Cmd.exe"; if (FPaths::FileExists(NewExeName)) { ExecutableName = NewExeName; } } #endif const bool bRunningDebug = FParse::Param(FCommandLine::Get(), TEXT("debug")); if (bRunningDebug) { OptionalParams += TEXT(" -UseDebugParamForEditorExe"); } FString ProjectPath = FPaths::IsProjectFilePathSet() ? FPaths::ConvertRelativePathToFull(FPaths::GetProjectFilePath()) : FPaths::RootDir() / FApp::GetGameName() / FApp::GetGameName() + TEXT(".uproject"); FString CommandLine = FString::Printf(TEXT("BuildCookRun %s%s -nop4 -project=\"%s\" -cook -allmaps -%s -ue4exe=%s %s"), FRocketSupport::IsRocket() ? TEXT("-rocket -nocompile") : TEXT("-nocompileeditor"), FApp::IsEngineInstalled() ? TEXT(" -installed") : TEXT(""), *ProjectPath, *PlatformInfo->TargetPlatformName.ToString(), *ExecutableName, *OptionalParams ); CreateUatTask(CommandLine, PlatformInfo->DisplayName, LOCTEXT("CookingContentTaskName", "Cooking content"), LOCTEXT("CookingTaskName", "Cooking"), FEditorStyle::GetBrush(TEXT("MainFrame.CookContent"))); } bool FMainFrameActionCallbacks::CookContentCanExecute( const FName PlatformInfoName ) { return true; } void FMainFrameActionCallbacks::PackageBuildConfiguration( EProjectPackagingBuildConfigurations BuildConfiguration ) { UProjectPackagingSettings* PackagingSettings = Cast(UProjectPackagingSettings::StaticClass()->GetDefaultObject()); PackagingSettings->BuildConfiguration = BuildConfiguration; } bool FMainFrameActionCallbacks::PackageBuildConfigurationIsChecked( EProjectPackagingBuildConfigurations BuildConfiguration ) { return (GetDefault()->BuildConfiguration == BuildConfiguration); } void FMainFrameActionCallbacks::PackageProject( const FName InPlatformInfoName ) { // does the project have any code? FGameProjectGenerationModule& GameProjectModule = FModuleManager::LoadModuleChecked(TEXT("GameProjectGeneration")); bool bProjectHasCode = GameProjectModule.Get().GetProjectCodeFileCount() > 0; const PlatformInfo::FPlatformInfo* const PlatformInfo = PlatformInfo::FindPlatformInfo(InPlatformInfoName); check(PlatformInfo); { const ITargetPlatform* const Platform = GetTargetPlatformManager()->FindTargetPlatform(PlatformInfo->TargetPlatformName.ToString()); if (Platform) { FString NotInstalledDocLink; if (!Platform->IsSdkInstalled(bProjectHasCode, NotInstalledDocLink)) { // broadcast this, and assume someone will pick it up IMainFrameModule& MainFrameModule = FModuleManager::GetModuleChecked(TEXT("MainFrame")); MainFrameModule.BroadcastMainFrameSDKNotInstalled(PlatformInfo->TargetPlatformName.ToString(), NotInstalledDocLink); return; } } } #if PLATFORM_WINDOWS if (bProjectHasCode && FRocketSupport::IsRocket() && PlatformInfo->TargetPlatformName == FName("IOS")) { FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("PackagingNotWorkingMessage", "Sorry, packaging is currently not supported for code-based iOS projects. This feature will be available in a future release.") ); return; } #endif if (!FModuleManager::LoadModuleChecked("ProjectTargetPlatformEditor").ShowUnsupportedTargetWarning(PlatformInfo->VanillaPlatformName)) { return; } UProjectPackagingSettings* PackagingSettings = Cast(UProjectPackagingSettings::StaticClass()->GetDefaultObject()); // let the user pick a target directory if (PackagingSettings->StagingDirectory.Path.IsEmpty()) { PackagingSettings->StagingDirectory.Path = FPaths::GameDir(); } FString OutFolderName; void* ParentWindowWindowHandle = nullptr; IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked(TEXT("MainFrame")); const TSharedPtr& MainFrameParentWindow = MainFrameModule.GetParentWindow(); if ( MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid() ) { ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle(); } if (!FDesktopPlatformModule::Get()->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("PackageDirectoryDialogTitle", "Package project...").ToString(), PackagingSettings->StagingDirectory.Path, OutFolderName)) { return; } PackagingSettings->StagingDirectory.Path = OutFolderName; PackagingSettings->SaveConfig(); // create the packager process FString OptionalParams; if (PackagingSettings->FullRebuild) { OptionalParams += TEXT(" -clean"); } if (PackagingSettings->UsePakFile) { OptionalParams += TEXT(" -pak"); if (PackagingSettings->UseOBB_InAPK) { OptionalParams += TEXT(" -obbinapk"); } } if (PackagingSettings->ForDistribution) { OptionalParams += TEXT(" -distribution"); } if (PlatformInfo->TargetPlatformName == FName("MacNoEditor")) { OptionalParams += TEXT(" -targetplatform=Mac"); } else if (PlatformInfo->TargetPlatformName == FName("LinuxNoEditor")) { OptionalParams += TEXT(" -targetplatform=Linux"); } // Append any extra UAT flags specified for this platform flavor if (!PlatformInfo->UATCommandLine.IsEmpty()) { OptionalParams += TEXT(" "); OptionalParams += PlatformInfo->UATCommandLine; } // only build if the project has code that might need to be built if (bProjectHasCode && FSourceCodeNavigation::IsCompilerAvailable()) { OptionalParams += TEXT(" -build"); } FString ExecutableName = FPlatformProcess::ExecutableName(false); #if PLATFORM_WINDOWS // turn UE4editor into UE4editor.cmd if(ExecutableName.EndsWith(".exe", ESearchCase::IgnoreCase) && !FPaths::GetBaseFilename(ExecutableName).EndsWith("-cmd", ESearchCase::IgnoreCase)) { FString NewExeName = ExecutableName.Left(ExecutableName.Len() - 4) + "-Cmd.exe"; if (FPaths::FileExists(NewExeName)) { ExecutableName = NewExeName; } } #endif const bool bRunningDebug = FParse::Param(FCommandLine::Get(), TEXT("debug")); if (bRunningDebug) { OptionalParams += TEXT(" -UseDebugParamForEditorExe"); } FString Configuration = FindObject(ANY_PACKAGE, TEXT("EProjectPackagingBuildConfigurations"))->GetEnumName(PackagingSettings->BuildConfiguration); Configuration = Configuration.Replace(TEXT("PPBC_"), TEXT("")); FString ProjectPath = FPaths::IsProjectFilePathSet() ? FPaths::ConvertRelativePathToFull(FPaths::GetProjectFilePath()) : FPaths::RootDir() / FApp::GetGameName() / FApp::GetGameName() + TEXT(".uproject"); FString CommandLine = FString::Printf(TEXT("BuildCookRun %s%s -nop4 -project=\"%s\" -cook -allmaps -stage -archive -archivedirectory=\"%s\" -package -%s -clientconfig=%s -ue4exe=%s %s -utf8output"), FRocketSupport::IsRocket() ? TEXT( "-rocket -nocompile" ) : TEXT( "-nocompileeditor" ), FApp::IsEngineInstalled() ? TEXT(" -installed") : TEXT(""), *ProjectPath, *PackagingSettings->StagingDirectory.Path, *PlatformInfo->TargetPlatformName.ToString(), *Configuration, *ExecutableName, *OptionalParams ); CreateUatTask(CommandLine, PlatformInfo->DisplayName, LOCTEXT("PackagingProjectTaskName", "Packaging project"), LOCTEXT("PackagingTaskName", "Packaging"), FEditorStyle::GetBrush(TEXT("MainFrame.PackageProject"))); } bool FMainFrameActionCallbacks::PackageProjectCanExecute( const FName PlatformInfoName, bool IsImplemented ) { return IsImplemented; } void FMainFrameActionCallbacks::RefreshCodeProject() { if ( !FSourceCodeNavigation::IsCompilerAvailable() ) { // Attempt to trigger the tutorial if the user doesn't have a compiler installed for the project. FSourceCodeNavigation::AccessOnCompilerNotFound().Broadcast(); } FText FailReason; if(!FGameProjectGenerationModule::Get().UpdateCodeProject(FailReason)) { FSlateNotificationManager::Get().AddNotification(FNotificationInfo(FailReason)); } } void FMainFrameActionCallbacks::OpenIDE() { if ( !FSourceCodeNavigation::IsCompilerAvailable() ) { // Attempt to trigger the tutorial if the user doesn't have a compiler installed for the project. FSourceCodeNavigation::AccessOnCompilerNotFound().Broadcast(); } else { if ( !FSourceCodeNavigation::OpenModuleSolution() ) { const FString FullPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead( *FModuleManager::Get().GetSolutionFilepath() ); const FText Message = FText::Format( LOCTEXT( "OpenIDEFailed_MissingFile", "Could not open {0} for project {1}" ), FSourceCodeNavigation::GetSuggestedSourceCodeIDE(), FText::FromString( FullPath ) ); FMessageDialog::Open( EAppMsgType::Ok, Message ); } } } void FMainFrameActionCallbacks::PackagingSettings() { FModuleManager::LoadModuleChecked("Settings").ShowViewer("Project", "Game", "Packaging"); } void FMainFrameActionCallbacks::SwitchProjectByIndex( int32 ProjectIndex ) { FUnrealEdMisc::Get().SwitchProject( ProjectNames[ ProjectIndex ] ); } void FMainFrameActionCallbacks::SwitchProject(const FString& GameOrProjectFileName) { FUnrealEdMisc::Get().SwitchProject( GameOrProjectFileName ); } void FMainFrameActionCallbacks::OpenBackupDirectory( FString BackupFile ) { FPlatformProcess::LaunchFileInDefaultExternalApplication(*FPaths::GetPath(FPaths::ConvertRelativePathToFull(BackupFile))); } void FMainFrameActionCallbacks::ResetLayout() { if(EAppReturnType::Ok != OpenMsgDlgInt(EAppMsgType::OkCancel, LOCTEXT( "ActionRestartMsg", "This action requires the editor to restart; you will be prompted to save any changes. Continue?" ), LOCTEXT( "ResetUILayout_Title", "Reset UI Layout" ) ) ) { return; } // make a backup GEditor->SaveEditorUserSettings(); FString BackupEditorLayoutIni = FString::Printf(TEXT("%s_Backup.ini"), *FPaths::GetBaseFilename(GEditorLayoutIni, false)); if( COPY_Fail == IFileManager::Get().Copy(*BackupEditorLayoutIni, *GEditorLayoutIni) ) { FMessageLog EditorErrors("EditorErrors"); if(!FPaths::FileExists(GEditorLayoutIni)) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("FileName"), FText::FromString(GEditorLayoutIni)); EditorErrors.Warning(FText::Format(LOCTEXT("UnsuccessfulBackup_NoExist_Notification", "Unsuccessful backup! {FileName} does not exist!"), Arguments)); } else if(IFileManager::Get().IsReadOnly(*BackupEditorLayoutIni)) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("FileName"), FText::FromString(FPaths::ConvertRelativePathToFull(BackupEditorLayoutIni))); EditorErrors.Warning(FText::Format(LOCTEXT("UnsuccessfulBackup_ReadOnly_Notification", "Unsuccessful backup! {FileName} is read-only!"), Arguments)); } else { // We don't specifically know why it failed, this is a fallback. FFormatNamedArguments Arguments; Arguments.Add(TEXT("SourceFileName"), FText::FromString(GEditorLayoutIni)); Arguments.Add(TEXT("BackupFileName"), FText::FromString(FPaths::ConvertRelativePathToFull(BackupEditorLayoutIni))); EditorErrors.Warning(FText::Format(LOCTEXT("UnsuccessfulBackup_Fallback_Notification", "Unsuccessful backup of {SourceFileName} to {BackupFileName}"), Arguments)); } EditorErrors.Notify(LOCTEXT("BackupUnsuccessful_Title", "Backup Unsuccessful!")); } else { FNotificationInfo ErrorNotification( FText::GetEmpty() ); ErrorNotification.bFireAndForget = true; ErrorNotification.ExpireDuration = 3.0f; ErrorNotification.bUseThrobber = true; ErrorNotification.Hyperlink = FSimpleDelegate::CreateStatic(&FMainFrameActionCallbacks::OpenBackupDirectory, BackupEditorLayoutIni); ErrorNotification.HyperlinkText = LOCTEXT("SuccessfulBackup_Notification_Hyperlink", "Open Directory"); ErrorNotification.Text = LOCTEXT("SuccessfulBackup_Notification", "Backup Successful!"); ErrorNotification.Image = FEditorStyle::GetBrush(TEXT("NotificationList.SuccessImage")); FSlateNotificationManager::Get().AddNotification(ErrorNotification); } // reset layout & restart Editor FUnrealEdMisc::Get().AllowSavingLayoutOnClose(false); FUnrealEdMisc::Get().RestartEditor(false); } void FMainFrameActionCallbacks::SaveLayout() { FGlobalTabmanager::Get()->SaveAllVisualState(); // Write the saved state's config to disk GConfig->Flush( false, GEditorLayoutIni ); } void FMainFrameActionCallbacks::ToggleFullscreen_Execute() { if ( GIsEditor && FApp::HasGameName() ) { static TWeakPtr LevelEditorTabPtr = FGlobalTabmanager::Get()->InvokeTab(FTabId("LevelEditor")); const TSharedPtr LevelEditorWindow = FSlateApplication::Get().FindWidgetWindow( LevelEditorTabPtr.Pin().ToSharedRef() ); if (LevelEditorWindow->GetWindowMode() == EWindowMode::Windowed) { LevelEditorWindow->SetWindowMode(EWindowMode::WindowedFullscreen); } else { LevelEditorWindow->SetWindowMode(EWindowMode::Windowed); } } } bool FMainFrameActionCallbacks::FullScreen_IsChecked() { const TWeakPtr LevelEditorTabPtr = FModuleManager::Get().GetModuleChecked( "LevelEditor" ).GetLevelEditorTab(); const TSharedPtr LevelEditorWindow = LevelEditorTabPtr.IsValid() ? LevelEditorTabPtr.Pin()->GetParentWindow() : TSharedPtr(); return (LevelEditorWindow.IsValid()) ? (LevelEditorWindow->GetWindowMode() != EWindowMode::Windowed) : false; } bool FMainFrameActionCallbacks::CanSwitchToProject( int32 InProjectIndex ) { if ( FApp::HasGameName() && ProjectNames[ InProjectIndex ].StartsWith( GGameName ) ) { return false; } if ( FPaths::IsProjectFilePathSet() && ProjectNames[ InProjectIndex ] == FPaths::GetProjectFilePath() ) { return false; } return true; } bool FMainFrameActionCallbacks::IsSwitchProjectChecked( int32 InProjectIndex ) { return CanSwitchToProject( InProjectIndex ) == false; } void FMainFrameActionCallbacks::Exit() { FSlateApplication::Get().LeaveDebuggingMode(); // Shut down the editor // NOTE: We can't close the editor from within this stack frame as it will cause various DLLs // (such as MainFrame) to become unloaded out from underneath the code pointer. We'll shut down // as soon as it's safe to do so. GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME")); } bool FMainFrameActionCallbacks::Undo_CanExecute() { return GUnrealEd->Trans->CanUndo() && FSlateApplication::Get().IsNormalExecution(); } bool FMainFrameActionCallbacks::Redo_CanExecute() { return GUnrealEd->Trans->CanRedo() && FSlateApplication::Get().IsNormalExecution(); } void FMainFrameActionCallbacks::ExecuteExecCommand( FString Command ) { GUnrealEd->Exec( GEditor->GetEditorWorldContext(true).World(), *Command ); } void FMainFrameActionCallbacks::OpenSlateApp_ViaModule( FName AppName, FName ModuleName ) { FModuleManager::Get().LoadModule( ModuleName ); OpenSlateApp( AppName ); } void FMainFrameActionCallbacks::OpenSlateApp( FName AppName ) { FGlobalTabmanager::Get()->InvokeTab(FTabId(AppName)); } bool FMainFrameActionCallbacks::OpenSlateApp_IsChecked( FName AppName ) { return false; } void FMainFrameActionCallbacks::VisitAskAQuestionPage() { FString AskAQuestionURL; if(FUnrealEdMisc::Get().GetURL( TEXT("AskAQuestionURL"), AskAQuestionURL, true )) { FPlatformProcess::LaunchURL( *AskAQuestionURL, NULL, NULL ); } } void FMainFrameActionCallbacks::VisitSearchForAnswersPage() { FString SearchForAnswersURL; if(FUnrealEdMisc::Get().GetURL( TEXT("SearchForAnswersURL"), SearchForAnswersURL, true )) { FPlatformProcess::LaunchURL( *SearchForAnswersURL, NULL, NULL ); } } void FMainFrameActionCallbacks::VisitSupportWebSite() { FString SupportWebsiteURL; if(FUnrealEdMisc::Get().GetURL( TEXT("SupportWebsiteURL"), SupportWebsiteURL, true )) { FPlatformProcess::LaunchURL( *SupportWebsiteURL, NULL, NULL ); } } void FMainFrameActionCallbacks::VisitEpicGamesDotCom() { FString EpicGamesURL; if(FUnrealEdMisc::Get().GetURL( TEXT("EpicGamesURL"), EpicGamesURL )) { FPlatformProcess::LaunchURL( *EpicGamesURL, NULL, NULL ); } } void FMainFrameActionCallbacks::VisitWiki() { FString URL; if (FUnrealEdMisc::Get().GetURL(TEXT("WikiURL"), URL)) { FPlatformProcess::LaunchURL(*URL, NULL, NULL); } } void FMainFrameActionCallbacks::VisitForums() { FString URL; if (FUnrealEdMisc::Get().GetURL(TEXT("ForumsURL"), URL)) { FPlatformProcess::LaunchURL(*URL, NULL, NULL); } } void FMainFrameActionCallbacks::AboutUnrealEd_Execute() { const FText AboutWindowTitle = LOCTEXT( "AboutUnrealEditor", "About Unreal Editor" ); TSharedPtr AboutWindow = SNew(SWindow) .Title( AboutWindowTitle ) .ClientSize(FVector2D(600.f, 200.f)) .SupportsMaximize(false) .SupportsMinimize(false) .SizingRule( ESizingRule::FixedSize ) [ SNew(SAboutScreen) ]; IMainFrameModule& MainFrame = FModuleManager::LoadModuleChecked( "MainFrame" ); TSharedPtr ParentWindow = MainFrame.GetParentWindow(); if ( ParentWindow.IsValid() ) { FSlateApplication::Get().AddModalWindow(AboutWindow.ToSharedRef(), ParentWindow.ToSharedRef()); } else { FSlateApplication::Get().AddWindow(AboutWindow.ToSharedRef()); } } void FMainFrameActionCallbacks::OpenWidgetReflector_Execute() { FGlobalTabmanager::Get()->InvokeTab(FTabId("WidgetReflector")); } /* FMainFrameActionCallbacks implementation *****************************************************************************/ void FMainFrameActionCallbacks::CreateUatTask( const FString& CommandLine, const FText& PlatformDisplayName, const FText& TaskName, const FText &TaskShortName, const FSlateBrush* TaskIcon ) { // make sure that the UAT batch file is in place #if PLATFORM_WINDOWS FString RunUATScriptName = TEXT("RunUAT.bat"); FString CmdExe = TEXT("cmd.exe"); #else FString RunUATScriptName = TEXT("RunUAT.command"); FString CmdExe = TEXT("/bin/sh"); #endif FString UatPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles") / RunUATScriptName); if (!FPaths::FileExists(UatPath)) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("File"), FText::FromString(UatPath)); FMessageDialog::Open(EAppMsgType::Ok, FText::Format(LOCTEXT("RequiredFileNotFoundMessage", "A required file could not be found:\n{File}"), Arguments)); return; } #if PLATFORM_WINDOWS FString FullCommandLine = FString::Printf(TEXT("/c \"\"%s\" %s\""), *UatPath, *CommandLine); #else FString FullCommandLine = FString::Printf(TEXT("\"%s\" %s"), *UatPath, *CommandLine); #endif TSharedPtr UatProcess = MakeShareable(new FMonitoredProcess(CmdExe, FullCommandLine, true)); // create notification item FFormatNamedArguments Arguments; Arguments.Add(TEXT("Platform"), PlatformDisplayName); Arguments.Add(TEXT("TaskName"), TaskName); FNotificationInfo Info( FText::Format( LOCTEXT("UatTaskInProgressNotification", "{TaskName} for {Platform}..."), Arguments) ); Info.Image = TaskIcon; Info.bFireAndForget = false; Info.ExpireDuration = 3.0f; Info.Hyperlink = FSimpleDelegate::CreateStatic(&FMainFrameActionCallbacks::HandleUatHyperlinkNavigate); Info.HyperlinkText = LOCTEXT("ShowOutputLogHyperlink", "Show Output Log"); Info.ButtonDetails.Add( FNotificationButtonInfo( LOCTEXT("UatTaskCancel", "Cancel"), LOCTEXT("UatTaskCancelToolTip", "Cancels execution of this task."), FSimpleDelegate::CreateStatic(&FMainFrameActionCallbacks::HandleUatCancelButtonClicked, UatProcess) ) ); TSharedPtr NotificationItem = FSlateNotificationManager::Get().AddNotification(Info); if (!NotificationItem.IsValid()) { return; } NotificationItem->SetCompletionState(SNotificationItem::CS_Pending); // launch the packager TWeakPtr NotificationItemPtr(NotificationItem); UatProcess->OnCanceled().BindStatic(&FMainFrameActionCallbacks::HandleUatProcessCanceled, NotificationItemPtr, PlatformDisplayName, TaskShortName); UatProcess->OnCompleted().BindStatic(&FMainFrameActionCallbacks::HandleUatProcessCompleted, NotificationItemPtr, PlatformDisplayName, TaskShortName); UatProcess->OnOutput().BindStatic(&FMainFrameActionCallbacks::HandleUatProcessOutput, NotificationItemPtr, PlatformDisplayName, TaskShortName); if (UatProcess->Launch()) { GEditor->PlayEditorSound(TEXT("/Engine/EditorSounds/Notifications/CompileStart_Cue.CompileStart_Cue")); } else { GEditor->PlayEditorSound(TEXT("/Engine/EditorSounds/Notifications/CompileFailed_Cue.CompileFailed_Cue")); NotificationItem->SetText(LOCTEXT("UatLaunchFailedNotification", "Failed to launch Unreal Automation Tool (UAT)!")); NotificationItem->SetCompletionState(SNotificationItem::CS_Fail); NotificationItem->ExpireAndFadeout(); } } /* FMainFrameActionCallbacks callbacks *****************************************************************************/ class FMainFrameActionsNotificationTask { public: FMainFrameActionsNotificationTask( TWeakPtr InNotificationItemPtr, SNotificationItem::ECompletionState InCompletionState, const FText& InText ) : CompletionState(InCompletionState) , NotificationItemPtr(InNotificationItemPtr) , Text(InText) { } void DoTask( ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent ) { if (NotificationItemPtr.IsValid()) { if (CompletionState == SNotificationItem::CS_Fail) { GEditor->PlayEditorSound(TEXT("/Engine/EditorSounds/Notifications/CompileFailed_Cue.CompileFailed_Cue")); } else { GEditor->PlayEditorSound(TEXT("/Engine/EditorSounds/Notifications/CompileSuccess_Cue.CompileSuccess_Cue")); } TSharedPtr NotificationItem = NotificationItemPtr.Pin(); NotificationItem->SetText(Text); NotificationItem->SetCompletionState(CompletionState); NotificationItem->ExpireAndFadeout(); } } static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } ENamedThreads::Type GetDesiredThread( ) { return ENamedThreads::GameThread; } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(FMainFrameActionsNotificationTask, STATGROUP_TaskGraphTasks); } private: SNotificationItem::ECompletionState CompletionState; TWeakPtr NotificationItemPtr; FText Text; }; void FMainFrameActionCallbacks::HandleUatHyperlinkNavigate( ) { FGlobalTabmanager::Get()->InvokeTab(FName("OutputLog")); } void FMainFrameActionCallbacks::HandleUatCancelButtonClicked( TSharedPtr PackagerProcess ) { if (PackagerProcess.IsValid()) { PackagerProcess->Cancel(true); } } void FMainFrameActionCallbacks::HandleUatProcessCanceled( TWeakPtr NotificationItemPtr, FText PlatformDisplayName, FText TaskName ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("Platform"), PlatformDisplayName); Arguments.Add(TEXT("TaskName"), TaskName); TGraphTask::CreateTask().ConstructAndDispatchWhenReady( NotificationItemPtr, SNotificationItem::CS_Fail, FText::Format(LOCTEXT("UatProcessFailedNotification", "{TaskName} canceled!"), Arguments) ); // FMessageLog("PackagingResults").Warning(FText::Format(LOCTEXT("UatProcessCanceledMessageLog", "{TaskName} for {Platform} canceled by user"), Arguments)); } void FMainFrameActionCallbacks::HandleUatProcessCompleted( int32 ReturnCode, TWeakPtr NotificationItemPtr, FText PlatformDisplayName, FText TaskName ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("Platform"), PlatformDisplayName); Arguments.Add(TEXT("TaskName"), TaskName); if (ReturnCode == 0) { TGraphTask::CreateTask().ConstructAndDispatchWhenReady( NotificationItemPtr, SNotificationItem::CS_Success, FText::Format(LOCTEXT("UatProcessSucceededNotification", "{TaskName} complete!"), Arguments) ); // FMessageLog("PackagingResults").Info(FText::Format(LOCTEXT("UatProcessSuccessMessageLog", "{TaskName} for {Platform} completed successfully"), Arguments)); } else { TGraphTask::CreateTask().ConstructAndDispatchWhenReady( NotificationItemPtr, SNotificationItem::CS_Fail, FText::Format(LOCTEXT("PackagerFailedNotification", "{TaskName} failed!"), Arguments) ); // FMessageLog("PackagingResults").Info(FText::Format(LOCTEXT("UatProcessFailedMessageLog", "{TaskName} for {Platform} failed"), Arguments)); } } void FMainFrameActionCallbacks::HandleUatProcessOutput( FString Output, TWeakPtr NotificationItemPtr, FText PlatformDisplayName, FText TaskName ) { if (!Output.IsEmpty()) { UE_LOG(MainFrameActions, Log, TEXT("%s (%s): %s"), *TaskName.ToString(), *PlatformDisplayName.ToString(), *Output); } } #undef LOCTEXT_NAMESPACE