2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-06-25 13:25:21 -04:00
# include "MergePrivatePCH.h"
2014-07-09 13:18:10 -04:00
# include "BlueprintEditor.h"
# include "ISourceControlModule.h"
2014-06-25 13:25:21 -04:00
# include "SBlueprintMerge.h"
# include "Toolkits/ToolkitManager.h"
# include "Toolkits/IToolkit.h"
2014-10-14 22:50:06 -04:00
# include "SDockTab.h"
# include "SNotificationList.h"
# include "NotificationManager.h"
2014-12-11 12:24:41 -05:00
# include "MergeUtils.h"
2014-06-25 13:25:21 -04:00
# define LOCTEXT_NAMESPACE "Merge"
2014-07-15 20:22:37 -04:00
const FName MergeToolTabId = FName ( TEXT ( " MergeTool " ) ) ;
2014-07-15 13:27:02 -04:00
static void DisplayErrorMessage ( const FText & ErrorMessage )
{
FNotificationInfo Info ( ErrorMessage ) ;
Info . ExpireDuration = 5.0f ;
FSlateNotificationManager : : Get ( ) . AddNotification ( Info ) ;
}
2014-06-25 13:25:21 -04:00
static FRevisionInfo GetRevisionInfo ( ISourceControlRevision const & FromRevision )
{
2015-01-20 05:48:14 -05:00
FRevisionInfo Ret = { FromRevision . GetRevision ( ) , FromRevision . GetCheckInIdentifier ( ) , FromRevision . GetDate ( ) } ;
2014-06-26 15:58:00 -04:00
return Ret ;
2014-06-25 13:25:21 -04:00
}
2014-12-11 12:24:41 -05:00
static const UObject * LoadHeadRev ( const FString & PackageName , const FString & AssetName , const ISourceControlState & SourceControlState , FRevisionInfo & OutRevInfo )
2014-06-25 13:25:21 -04:00
{
2014-07-15 13:27:02 -04:00
// HistoryItem(0) is apparently the head revision:
TSharedPtr < ISourceControlRevision , ESPMode : : ThreadSafe > Revision = SourceControlState . GetHistoryItem ( 0 ) ;
check ( Revision . IsValid ( ) ) ;
OutRevInfo = GetRevisionInfo ( * Revision ) ;
2014-12-11 12:24:41 -05:00
return FMergeToolUtils : : LoadRevision ( AssetName , * Revision ) ;
2014-06-25 13:25:21 -04:00
}
2014-12-11 12:24:41 -05:00
static const UObject * LoadBaseRev ( const FString & PackageName , const FString & AssetName , const ISourceControlState & SourceControlState , FRevisionInfo & OutRevInfo )
2014-06-25 13:25:21 -04:00
{
2014-07-15 13:27:02 -04:00
TSharedPtr < ISourceControlRevision , ESPMode : : ThreadSafe > Revision = SourceControlState . GetBaseRevForMerge ( ) ;
check ( Revision . IsValid ( ) ) ;
OutRevInfo = GetRevisionInfo ( * Revision ) ;
2014-12-11 12:24:41 -05:00
return FMergeToolUtils : : LoadRevision ( AssetName , * Revision ) ;
2014-06-25 13:25:21 -04:00
}
2014-11-21 12:21:17 -05:00
static TSharedPtr < SWidget > GenerateMergeTabContents ( TSharedRef < FBlueprintEditor > Editor ,
2014-11-24 17:38:44 -05:00
const UBlueprint * BaseBlueprint ,
const FRevisionInfo & BaseRevInfo ,
const UBlueprint * RemoteBlueprint ,
const FRevisionInfo & RemoteRevInfo ,
2014-12-04 15:45:39 -05:00
const UBlueprint * LocalBlueprint ,
2014-11-24 17:38:44 -05:00
const FOnMergeResolved & MereResolutionCallback )
2014-11-21 12:21:17 -05:00
{
2014-12-11 12:24:41 -05:00
bool bForceAssetPicker = false ;
if ( BaseBlueprint = = nullptr )
2014-11-21 12:21:17 -05:00
{
2014-12-11 12:24:41 -05:00
BaseBlueprint = LocalBlueprint ;
bForceAssetPicker = true ;
2014-11-21 12:21:17 -05:00
}
2014-12-11 12:24:41 -05:00
if ( RemoteBlueprint = = nullptr )
2014-11-21 12:21:17 -05:00
{
2014-12-11 12:24:41 -05:00
RemoteBlueprint = LocalBlueprint ;
bForceAssetPicker = true ;
2014-11-21 12:21:17 -05:00
}
2014-12-11 12:24:41 -05:00
FBlueprintMergeData Data ( Editor
, LocalBlueprint
, BaseBlueprint
2014-12-17 19:27:27 -05:00
, BaseRevInfo
2014-12-11 12:24:41 -05:00
, RemoteBlueprint
2014-12-17 19:27:27 -05:00
, RemoteRevInfo ) ;
2014-12-11 12:24:41 -05:00
return SNew ( SBlueprintMerge , Data )
. bForcePickAssets ( bForceAssetPicker )
. OnMergeResolved ( MereResolutionCallback ) ;
2014-11-21 12:21:17 -05:00
}
2014-12-11 12:24:41 -05:00
class FMerge : public IMerge
2014-06-25 13:25:21 -04:00
{
/** IModuleInterface implementation */
virtual void StartupModule ( ) override ;
virtual void ShutdownModule ( ) override ;
2014-07-15 20:22:37 -04:00
virtual TSharedRef < SDockTab > GenerateMergeWidget ( const UBlueprint & Object , TSharedRef < FBlueprintEditor > Editor ) override ;
2014-11-24 17:38:44 -05:00
virtual TSharedRef < SDockTab > GenerateMergeWidget ( const UBlueprint * BaseAsset , const UBlueprint * RemoteAsset , const UBlueprint * LocalAsset , const FOnMergeResolved & MergeResolutionCallback , TSharedRef < FBlueprintEditor > Editor ) override ;
2014-07-09 13:18:10 -04:00
virtual bool PendingMerge ( const UBlueprint & BlueprintObj ) const override ;
2014-11-24 17:38:44 -05:00
//virtual FOnMergeResolved& OnMergeResolved() const override;
2014-07-15 20:22:37 -04:00
// Simplest to only allow one merge operation at a time, we could easily make this a map of Blueprint=>MergeTab
// but doing so will complicate the tab management
TWeakPtr < SDockTab > ActiveTab ;
2014-06-25 13:25:21 -04:00
} ;
IMPLEMENT_MODULE ( FMerge , Merge )
void FMerge : : StartupModule ( )
{
// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
2014-07-15 20:22:37 -04:00
2014-12-11 11:09:39 -05:00
// Registering a nomad spawner that spawns an empty dock tab on purpose - allows us to call InvokeTab() using our TabId later and set the content. (see GenerateMergeWidget())
FGlobalTabmanager : : Get ( ) - > RegisterNomadTabSpawner ( MergeToolTabId , FOnSpawnTab : : CreateStatic ( [ ] ( const FSpawnTabArgs & ) { return SNew ( SDockTab ) ; } ) )
2014-07-15 20:22:37 -04:00
. SetDisplayName ( NSLOCTEXT ( " MergeTool " , " TabTitle " , " Merge Tool " ) )
2014-12-11 11:09:39 -05:00
. SetTooltipText ( NSLOCTEXT ( " MergeTool " , " TooltipText " , " Used to display several versions of a blueprint that need to be merged into a single version. " ) )
. SetAutoGenerateMenuEntry ( false ) ;
2014-06-25 13:25:21 -04:00
}
void FMerge : : ShutdownModule ( )
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
2014-07-15 20:22:37 -04:00
FGlobalTabmanager : : Get ( ) - > UnregisterNomadTabSpawner ( MergeToolTabId ) ;
2014-06-25 13:25:21 -04:00
}
2014-07-15 20:22:37 -04:00
TSharedRef < SDockTab > FMerge : : GenerateMergeWidget ( const UBlueprint & Object , TSharedRef < FBlueprintEditor > Editor )
2014-06-25 13:25:21 -04:00
{
2014-07-15 20:22:37 -04:00
auto ActiveTabPtr = ActiveTab . Pin ( ) ;
if ( ActiveTabPtr . IsValid ( ) )
{
// just bring the tab to the foreground:
auto CurrentTab = FGlobalTabmanager : : Get ( ) - > InvokeTab ( MergeToolTabId ) ;
check ( CurrentTab = = ActiveTabPtr ) ;
return ActiveTabPtr . ToSharedRef ( ) ;
}
2014-06-25 13:25:21 -04:00
// merge the local asset with the depot, SCC provides us with the last common revision as
// a basis for the merge:
2014-07-15 20:22:37 -04:00
TSharedPtr < SWidget > Contents ;
2014-12-11 12:24:41 -05:00
if ( ! PendingMerge ( Object ) )
2014-07-15 13:27:02 -04:00
{
2014-12-11 12:24:41 -05:00
// this should load up the merge-tool, with an asset picker, where they
// can pick the asset/revisions to merge against
Contents = GenerateMergeTabContents ( Editor , nullptr , FRevisionInfo : : InvalidRevision ( ) , nullptr , FRevisionInfo : : InvalidRevision ( ) , & Object , FOnMergeResolved ( ) ) ;
2014-06-25 13:25:21 -04:00
}
else
{
2014-12-11 12:24:41 -05:00
// @todo DO: this will probably need to be async.. pulling down some old versions of assets:
const FString & PackageName = Object . GetOutermost ( ) - > GetName ( ) ;
const FString & AssetName = Object . GetName ( ) ;
2014-07-15 20:22:37 -04:00
2014-12-11 12:24:41 -05:00
FSourceControlStatePtr SourceControlState = FMergeToolUtils : : GetSourceControlState ( PackageName ) ;
if ( ! SourceControlState . IsValid ( ) )
{
DisplayErrorMessage (
FText : : Format (
LOCTEXT ( " MergeFailedNoSourceControl " , " Aborted Load of {0} from {1} because the source control state was invalidated " )
, FText : : FromString ( AssetName )
, FText : : FromString ( PackageName )
)
) ;
2014-07-15 20:22:37 -04:00
2014-12-11 12:24:41 -05:00
Contents = SNew ( SHorizontalBox ) ;
}
else
{
ISourceControlState const & SourceControlStateRef = * SourceControlState ;
FRevisionInfo CurrentRevInfo = FRevisionInfo : : InvalidRevision ( ) ;
const UBlueprint * RemoteBlueprint = Cast < UBlueprint > ( LoadHeadRev ( PackageName , AssetName , SourceControlStateRef , CurrentRevInfo ) ) ;
FRevisionInfo BaseRevInfo = FRevisionInfo : : InvalidRevision ( ) ;
const UBlueprint * BaseBlueprint = Cast < UBlueprint > ( LoadBaseRev ( PackageName , AssetName , SourceControlStateRef , BaseRevInfo ) ) ;
Contents = GenerateMergeTabContents ( Editor , BaseBlueprint , BaseRevInfo , RemoteBlueprint , CurrentRevInfo , & Object , FOnMergeResolved ( ) ) ;
}
2014-06-25 13:25:21 -04:00
}
2014-07-15 20:22:37 -04:00
2014-09-01 22:02:31 -04:00
TSharedRef < SDockTab > Tab = FGlobalTabmanager : : Get ( ) - > InvokeTab ( MergeToolTabId ) ;
2014-07-15 20:22:37 -04:00
Tab - > SetContent ( Contents . ToSharedRef ( ) ) ;
ActiveTab = Tab ;
return Tab ;
2014-06-25 13:25:21 -04:00
}
2014-11-24 17:38:44 -05:00
TSharedRef < SDockTab > FMerge : : GenerateMergeWidget ( const UBlueprint * BaseBlueprint , const UBlueprint * RemoteBlueprint , const UBlueprint * LocalBlueprint , const FOnMergeResolved & MergeResolutionCallback , TSharedRef < FBlueprintEditor > Editor )
2014-11-21 12:21:17 -05:00
{
if ( ActiveTab . IsValid ( ) )
{
TSharedPtr < SDockTab > ActiveTabPtr = ActiveTab . Pin ( ) ;
// just bring the tab to the foreground:
TSharedRef < SDockTab > CurrentTab = FGlobalTabmanager : : Get ( ) - > InvokeTab ( MergeToolTabId ) ;
check ( CurrentTab = = ActiveTabPtr ) ;
return ActiveTabPtr . ToSharedRef ( ) ;
}
// @TODO: pipe revision info through
2014-12-04 15:45:39 -05:00
TSharedPtr < SWidget > TabContents = GenerateMergeTabContents ( Editor , BaseBlueprint , FRevisionInfo : : InvalidRevision ( ) , RemoteBlueprint , FRevisionInfo : : InvalidRevision ( ) , LocalBlueprint , MergeResolutionCallback ) ;
2014-11-21 12:21:17 -05:00
TSharedRef < SDockTab > Tab = FGlobalTabmanager : : Get ( ) - > InvokeTab ( MergeToolTabId ) ;
Tab - > SetContent ( TabContents . ToSharedRef ( ) ) ;
ActiveTab = Tab ;
return Tab ;
}
2014-07-09 13:18:10 -04:00
bool FMerge : : PendingMerge ( const UBlueprint & BlueprintObj ) const
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
bool bPendingMerge = false ;
2014-12-18 13:57:42 -05:00
if ( SourceControlProvider . IsEnabled ( ) )
2014-07-09 13:18:10 -04:00
{
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( BlueprintObj . GetOutermost ( ) , EStateCacheUsage : : Use ) ;
bPendingMerge = SourceControlState . IsValid ( ) & & SourceControlState - > IsConflicted ( ) ;
}
return bPendingMerge ;
}
2014-06-25 16:26:10 -04:00
# undef LOCTEXT_NAMESPACE