2023-11-21 09:56:04 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2023-11-21 10:29:56 -05:00
# if SOURCE_CONTROL_WITH_SLATE
2023-11-21 09:56:04 -05:00
# include "SSourceControlControls.h"
# include "ISourceControlProvider.h"
# include "ISourceControlModule.h"
# include "Misc/ConfigCacheIni.h"
# include "RevisionControlStyle/RevisionControlStyle.h"
# include "Widgets/Input/SButton.h"
# include "Widgets/Input/SComboBox.h"
# include "Widgets/Layout/SSeparator.h"
# define LOCTEXT_NAMESPACE "SSkeinSourceControlWidgets"
2023-12-22 14:15:22 -05:00
bool SSourceControlControls : : bStaticDisableCheckInChangesOverride = false ;
bool SSourceControlControls : : bStaticDisableSyncLatestOverride = false ;
FOnClicked SSourceControlControls : : OnSyncLatestClickedStaticOverride ;
2023-11-21 09:56:04 -05:00
/**
* Construct this widget
*
* @ param InArgs The declaration data for this widget
*/
void SSourceControlControls : : Construct ( const FArguments & InArgs )
{
OnSyncLatestClicked = InArgs . _OnClickedSyncLatest ;
OnCheckInChangesClicked = InArgs . _OnClickedCheckInChanges ;
2023-11-30 03:37:36 -05:00
IsSyncLatestEnabled = InArgs . _IsEnabledSyncLatest ;
IsCheckInChangesEnabled = InArgs . _IsEnabledCheckInChanges ;
2023-12-22 03:31:43 -05:00
IsSyncLatestSeparatorEnabled = InArgs . _IsEnabledSyncLatestSeparator ;
IsCheckInChangesSeparatorEnabled = InArgs . _IsEnabledCheckInChangesSeparator ;
2023-11-21 09:56:04 -05:00
ChildSlot
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( ) // Check In Changes Button
. VAlign ( VAlign_Center )
. Padding ( FMargin ( 0.0f , 0.0f , 4.0f , 0.0f ) )
. AutoWidth ( )
[
SNew ( SButton )
. ButtonStyle ( & FAppStyle : : Get ( ) . GetWidgetStyle < FButtonStyle > ( " StatusBar.StatusBarButton " ) )
. ToolTipText ( this , & SSourceControlControls : : GetSourceControlCheckInStatusTooltipText )
. Visibility ( this , & SSourceControlControls : : GetSourceControlCheckInStatusVisibility )
2023-11-30 03:37:36 -05:00
. IsEnabled ( this , & SSourceControlControls : : IsSourceControlCheckInEnabled )
2023-11-21 09:56:04 -05:00
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Center )
[
SNew ( SImage )
. Image ( this , & SSourceControlControls : : GetSourceControlCheckInStatusIcon )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( FMargin ( 5 , 0 , 0 , 0 ) )
[
SNew ( STextBlock )
. TextStyle ( & FAppStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " NormalText " ) )
. Text ( this , & SSourceControlControls : : GetSourceControlCheckInStatusText )
]
]
2023-12-12 07:03:52 -05:00
. OnClicked ( this , & SSourceControlControls : : OnSourceControlCheckInChangesClicked )
2023-11-21 09:56:04 -05:00
]
+ SHorizontalBox : : Slot ( ) // Check In Kebab Combo button
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SComboButton )
. ContentPadding ( FMargin ( 7.f , 0.f ) )
. ComboButtonStyle ( & FAppStyle : : Get ( ) . GetWidgetStyle < FComboButtonStyle > ( " StatusBar.StatusBarEllipsisComboButton " ) )
. MenuPlacement ( MenuPlacement_AboveAnchor )
. Visibility ( this , & SSourceControlControls : : GetSourceControlCheckInStatusVisibility )
. OnGetMenuContent ( InArgs . _OnGenerateKebabMenu )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SSeparator )
2023-12-22 03:31:43 -05:00
. Visibility ( this , & SSourceControlControls : : GetSourceControlCheckInSeparatorVisibility )
2023-11-21 09:56:04 -05:00
. Thickness ( 1.0 )
. Orientation ( EOrientation : : Orient_Vertical )
]
+ SHorizontalBox : : Slot ( ) // Sync Latest Button
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SButton )
. ButtonStyle ( & FAppStyle : : Get ( ) . GetWidgetStyle < FButtonStyle > ( " StatusBar.StatusBarButton " ) )
. ToolTipText ( this , & SSourceControlControls : : GetSourceControlSyncStatusTooltipText )
. Visibility ( this , & SSourceControlControls : : GetSourceControlSyncStatusVisibility )
2023-11-30 03:37:36 -05:00
. IsEnabled ( this , & SSourceControlControls : : IsSourceControlSyncEnabled )
2023-11-21 09:56:04 -05:00
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Center )
[
SNew ( SImage )
. Image ( this , & SSourceControlControls : : GetSourceControlSyncStatusIcon )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( FMargin ( 5 , 0 , 0 , 0 ) )
[
SNew ( STextBlock )
. TextStyle ( & FAppStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " NormalText " ) )
. Text ( this , & SSourceControlControls : : GetSourceControlSyncStatusText )
]
]
. OnClicked ( this , & SSourceControlControls : : OnSourceControlSyncClicked )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SSeparator )
2023-12-22 03:31:43 -05:00
. Visibility ( this , & SSourceControlControls : : GetSourceControlSyncSeparatorVisibility )
2023-11-21 09:56:04 -05:00
. Thickness ( 1.0 )
. Orientation ( EOrientation : : Orient_Vertical )
]
] ;
CheckSourceControlStatus ( ) ;
}
void SSourceControlControls : : CheckSourceControlStatus ( )
{
ISourceControlModule & SourceControlModule = ISourceControlModule : : Get ( ) ;
if ( ! SourceControlProviderChangedHandle . IsValid ( ) )
{
SourceControlProviderChangedHandle = SourceControlModule . RegisterProviderChanged (
FSourceControlProviderChanged : : FDelegate : : CreateSP ( this , & SSourceControlControls : : OnSourceControlProviderChanged )
) ;
SourceControlStateChangedHandle = SourceControlModule . GetProvider ( ) . RegisterSourceControlStateChanged_Handle (
FSourceControlStateChanged : : FDelegate : : CreateSP ( this , & SSourceControlControls : : OnSourceControlStateChanged )
) ;
}
}
void SSourceControlControls : : OnSourceControlProviderChanged ( ISourceControlProvider & OldProvider , ISourceControlProvider & NewProvider )
{
if ( SourceControlStateChangedHandle . IsValid ( ) )
{
OldProvider . UnregisterSourceControlStateChanged_Handle ( SourceControlStateChangedHandle ) ;
SourceControlStateChangedHandle . Reset ( ) ;
}
if ( ! IsEngineExitRequested ( ) )
{
SourceControlStateChangedHandle = NewProvider . RegisterSourceControlStateChanged_Handle (
FSourceControlStateChanged : : FDelegate : : CreateSP ( this , & SSourceControlControls : : OnSourceControlStateChanged )
) ;
}
}
void SSourceControlControls : : OnSourceControlStateChanged ( )
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
TArray < FSourceControlStateRef > Conflicts = SourceControlProvider . GetCachedStateByPredicate (
[ ] ( const FSourceControlStateRef & State )
{
return State - > IsConflicted ( ) ;
}
) ;
2023-12-22 14:15:22 -05:00
NumConflictsRemaining = Conflicts . Num ( ) ;
bConflictsRemaining = ( NumConflictsRemaining > 0 ) ;
2023-11-21 09:56:04 -05:00
}
bool SSourceControlControls : : AreConflictsRemaining ( ) const
{
const bool bExiting = IsEngineExitRequested ( ) ;
if ( ! bExiting )
{
2023-11-22 03:36:56 -05:00
return bConflictsRemaining ;
2023-11-21 09:56:04 -05:00
}
return false ;
}
2023-12-22 14:15:22 -05:00
int32 SSourceControlControls : : GetNumConflictsRemaining ( ) const
{
return NumConflictsRemaining ;
}
2023-11-21 09:56:04 -05:00
/** Sync Status */
bool SSourceControlControls : : IsAtLatestRevision ( ) const
{
ISourceControlModule & SourceControlModule = ISourceControlModule : : Get ( ) ;
return SourceControlModule . IsEnabled ( ) & &
SourceControlModule . GetProvider ( ) . IsAvailable ( ) & &
SourceControlModule . GetProvider ( ) . IsAtLatestRevision ( ) . IsSet ( ) & &
SourceControlModule . GetProvider ( ) . IsAtLatestRevision ( ) . GetValue ( ) ;
}
2023-11-30 03:37:36 -05:00
bool SSourceControlControls : : IsSourceControlSyncEnabled ( ) const
{
if ( ! HasSourceControlChangesToSync ( ) )
{
return false ;
}
2023-12-22 14:15:22 -05:00
return IsSyncLatestEnabled . Get ( true ) & & ! bStaticDisableSyncLatestOverride ;
2023-11-30 03:37:36 -05:00
}
bool SSourceControlControls : : HasSourceControlChangesToSync ( ) const
2023-11-21 09:56:04 -05:00
{
return ! IsAtLatestRevision ( ) ;
}
EVisibility SSourceControlControls : : GetSourceControlSyncStatusVisibility ( ) const
{
if ( ! GIsEditor )
{
// Always visible in the Slate Viewer
return EVisibility : : Visible ;
}
bool bDisplaySourceControlSyncStatus = false ;
GConfig - > GetBool ( TEXT ( " SourceControlSettings " ) , TEXT ( " DisplaySourceControlSyncStatus " ) , bDisplaySourceControlSyncStatus , GEditorIni ) ;
if ( bDisplaySourceControlSyncStatus )
{
ISourceControlModule & SourceControlModule = ISourceControlModule : : Get ( ) ;
if ( SourceControlModule . IsEnabled ( ) & &
SourceControlModule . GetProvider ( ) . IsAvailable ( ) & &
SourceControlModule . GetProvider ( ) . IsAtLatestRevision ( ) . IsSet ( ) ) // Only providers that implement IsAtLatestRevision are supported.
{
return EVisibility : : Visible ;
}
}
return EVisibility : : Collapsed ;
}
2023-12-22 03:31:43 -05:00
EVisibility SSourceControlControls : : GetSourceControlSyncSeparatorVisibility ( ) const
{
EVisibility StatusVisibility = GetSourceControlSyncStatusVisibility ( ) ;
if ( StatusVisibility ! = EVisibility : : Visible )
{
return StatusVisibility ;
}
return IsSyncLatestSeparatorEnabled . Get ( true ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2023-11-21 09:56:04 -05:00
FText SSourceControlControls : : GetSourceControlSyncStatusText ( ) const
{
2023-11-30 03:37:36 -05:00
if ( HasSourceControlChangesToSync ( ) )
2023-11-21 09:56:04 -05:00
{
return LOCTEXT ( " SyncLatestButtonNotAtHeadText " , " Sync Latest " ) ;
}
return LOCTEXT ( " SyncLatestButtonAtHeadText " , " At Latest " ) ;
}
FText SSourceControlControls : : GetSourceControlSyncStatusTooltipText ( ) const
{
if ( AreConflictsRemaining ( ) )
{
return LOCTEXT ( " SyncLatestButtonNotAtHeadTooltipTextConflict " , " Some of your local changes conflict with the latest snapshot of the project. Click here to review these conflicts. " ) ;
}
2023-11-30 03:37:36 -05:00
if ( HasSourceControlChangesToSync ( ) )
2023-11-21 09:56:04 -05:00
{
return LOCTEXT ( " SyncLatestButtonNotAtHeadTooltipText " , " Sync to the latest Snapshot for this project " ) ;
}
return LOCTEXT ( " SyncLatestButtonAtHeadTooltipText " , " Currently at the latest Snapshot for this project " ) ;
}
const FSlateBrush * SSourceControlControls : : GetSourceControlSyncStatusIcon ( ) const
{
static const FSlateBrush * ConflictBrush = FRevisionControlStyleManager : : Get ( ) . GetBrush ( " RevisionControl.StatusBar.Conflicted " ) ;
static const FSlateBrush * AtHeadBrush = FRevisionControlStyleManager : : Get ( ) . GetBrush ( " RevisionControl.StatusBar.AtLatestRevision " ) ;
static const FSlateBrush * NotAtHeadBrush = FRevisionControlStyleManager : : Get ( ) . GetBrush ( " RevisionControl.StatusBar.NotAtLatestRevision " ) ;
if ( AreConflictsRemaining ( ) )
{
return ConflictBrush ;
}
2023-11-30 03:37:36 -05:00
if ( HasSourceControlChangesToSync ( ) )
2023-11-21 09:56:04 -05:00
{
return NotAtHeadBrush ;
}
return AtHeadBrush ;
}
FReply SSourceControlControls : : OnSourceControlSyncClicked ( ) const
{
if ( AreConflictsRemaining ( ) )
{
if ( IConsoleObject * CObj = IConsoleManager : : Get ( ) . FindConsoleObject ( TEXT ( " UnrealRevisionControl.FocusConflictResolution " ) ) )
{
CObj - > AsCommand ( ) - > Execute ( /*Args=*/ TArray < FString > ( ) , /*InWorld=*/ nullptr , * GLog ) ;
}
}
2023-11-30 03:37:36 -05:00
else if ( HasSourceControlChangesToSync ( ) )
2023-11-21 09:56:04 -05:00
{
2023-12-22 14:15:22 -05:00
if ( OnSyncLatestClickedStaticOverride . IsBound ( ) )
{
OnSyncLatestClickedStaticOverride . Execute ( ) ;
}
else if ( OnSyncLatestClicked . IsBound ( ) )
2023-11-21 09:56:04 -05:00
{
OnSyncLatestClicked . Execute ( ) ;
}
}
return FReply : : Handled ( ) ;
}
/** Check-in Status */
int SSourceControlControls : : GetNumLocalChanges ( ) const
{
ISourceControlModule & SourceControlModule = ISourceControlModule : : Get ( ) ;
if ( SourceControlModule . IsEnabled ( ) & &
SourceControlModule . GetProvider ( ) . IsAvailable ( ) & &
SourceControlModule . GetProvider ( ) . GetNumLocalChanges ( ) . IsSet ( ) )
{
return SourceControlModule . GetProvider ( ) . GetNumLocalChanges ( ) . GetValue ( ) ;
}
return 0 ;
}
2023-11-30 03:37:36 -05:00
bool SSourceControlControls : : IsSourceControlCheckInEnabled ( ) const
{
if ( ! HasSourceControlChangesToCheckIn ( ) )
{
return false ;
}
2023-12-22 14:15:22 -05:00
return IsCheckInChangesEnabled . Get ( true ) & & ! bStaticDisableCheckInChangesOverride ;
2023-11-30 03:37:36 -05:00
}
bool SSourceControlControls : : HasSourceControlChangesToCheckIn ( ) const
2023-11-21 09:56:04 -05:00
{
return ( GetNumLocalChanges ( ) > 0 ) ;
}
EVisibility SSourceControlControls : : GetSourceControlCheckInStatusVisibility ( ) const
{
if ( ! GIsEditor )
{
// Always visible in the Slate Viewer
return EVisibility : : Visible ;
}
bool bDisplaySourceControlCheckInStatus = false ;
GConfig - > GetBool ( TEXT ( " SourceControlSettings " ) , TEXT ( " DisplaySourceControlCheckInStatus " ) , bDisplaySourceControlCheckInStatus , GEditorIni ) ;
if ( bDisplaySourceControlCheckInStatus )
{
ISourceControlModule & SourceControlModule = ISourceControlModule : : Get ( ) ;
if ( SourceControlModule . IsEnabled ( ) & &
SourceControlModule . GetProvider ( ) . IsAvailable ( ) & &
SourceControlModule . GetProvider ( ) . GetNumLocalChanges ( ) . IsSet ( ) ) // Only providers that implement GetNumLocalChanges are supported.
{
return EVisibility : : Visible ;
}
}
return EVisibility : : Collapsed ;
}
2023-12-22 03:31:43 -05:00
EVisibility SSourceControlControls : : GetSourceControlCheckInSeparatorVisibility ( ) const
{
EVisibility StatusVisibility = GetSourceControlCheckInStatusVisibility ( ) ;
if ( StatusVisibility ! = EVisibility : : Visible )
{
return StatusVisibility ;
}
return IsCheckInChangesSeparatorEnabled . Get ( true ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2023-11-21 09:56:04 -05:00
FText SSourceControlControls : : GetSourceControlCheckInStatusText ( ) const
{
2023-11-30 03:37:36 -05:00
if ( HasSourceControlChangesToCheckIn ( ) )
2023-11-21 09:56:04 -05:00
{
return LOCTEXT ( " CheckInButtonChangesText " , " Check-in Changes " ) ;
}
return LOCTEXT ( " CheckInButtonNoChangesText " , " No Changes " ) ;
}
FText SSourceControlControls : : GetSourceControlCheckInStatusTooltipText ( ) const
{
if ( AreConflictsRemaining ( ) )
{
return LOCTEXT ( " CheckInButtonChangesTooltipTextConflict " , " Some of your local changes conflict with the latest snapshot of the project. Click here to review these conflicts. " ) ;
}
2023-11-30 03:37:36 -05:00
if ( HasSourceControlChangesToCheckIn ( ) )
2023-11-21 09:56:04 -05:00
{
2023-12-22 14:15:22 -05:00
if ( bStaticDisableCheckInChangesOverride )
{
return LOCTEXT ( " CheckInButtonChangesTooltipTextDisabled " , " Check-in disabled while in a rewound state. " ) ;
}
2023-11-21 09:56:04 -05:00
return FText : : Format ( LOCTEXT ( " CheckInButtonChangesTooltipText " , " Check-in {0} change(s) to this project " ) , GetNumLocalChanges ( ) ) ;
}
return LOCTEXT ( " CheckInButtonNoChangesTooltipText " , " No Changes to check in for this project " ) ;
}
const FSlateBrush * SSourceControlControls : : GetSourceControlCheckInStatusIcon ( ) const
{
static const FSlateBrush * ConflictBrush = FRevisionControlStyleManager : : Get ( ) . GetBrush ( " RevisionControl.StatusBar.Conflicted " ) ;
static const FSlateBrush * NoLocalChangesBrush = FRevisionControlStyleManager : : Get ( ) . GetBrush ( " RevisionControl.StatusBar.NoLocalChanges " ) ;
static const FSlateBrush * HasLocalChangesBrush = FRevisionControlStyleManager : : Get ( ) . GetBrush ( " RevisionControl.StatusBar.HasLocalChanges " ) ;
if ( AreConflictsRemaining ( ) )
{
return ConflictBrush ;
}
2023-11-30 03:37:36 -05:00
if ( HasSourceControlChangesToCheckIn ( ) )
2023-11-21 09:56:04 -05:00
{
return HasLocalChangesBrush ;
}
return NoLocalChangesBrush ;
}
FReply SSourceControlControls : : OnSourceControlCheckInChangesClicked ( ) const
{
if ( AreConflictsRemaining ( ) )
{
if ( IConsoleObject * CObj = IConsoleManager : : Get ( ) . FindConsoleObject ( TEXT ( " UnrealRevisionControl.FocusConflictResolution " ) ) )
{
CObj - > AsCommand ( ) - > Execute ( /*Args=*/ TArray < FString > ( ) , /*InWorld=*/ nullptr , * GLog ) ;
}
}
2023-11-30 03:37:36 -05:00
else if ( HasSourceControlChangesToCheckIn ( ) )
2023-11-21 09:56:04 -05:00
{
if ( OnCheckInChangesClicked . IsBound ( ) )
{
OnCheckInChangesClicked . Execute ( ) ;
}
}
return FReply : : Handled ( ) ;
}
2023-11-21 10:29:56 -05:00
# undef LOCTEXT_NAMESPACE
# endif // SOURCE_CONTROL_WITH_SLATE