2021-01-11 15:31:58 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SSourceControlChangelists.h"
# include "EditorStyleSet.h"
2021-01-18 15:31:14 -04:00
# include "Algo/Transform.h"
2021-01-11 15:31:58 -04:00
# include "Widgets/DeclarativeSyntaxSupport.h"
# include "Widgets/Images/SImage.h"
# include "Widgets/Layout/SScrollBorder.h"
# include "Widgets/SOverlay.h"
# include "ISourceControlProvider.h"
# include "ISourceControlModule.h"
# include "SourceControlOperations.h"
2021-01-18 09:42:33 -04:00
# include "ToolMenus.h"
2021-01-11 21:46:43 -04:00
# include "Widgets/Images/SLayeredImage.h"
2021-01-18 09:42:33 -04:00
# include "SSourceControlDescription.h"
2021-01-19 14:50:23 -04:00
# include "SourceControlWindows.h"
# include "AssetToolsModule.h"
# include "ContentBrowserModule.h"
# include "IContentBrowserSingleton.h"
2021-01-20 09:51:23 -04:00
# include "Misc/MessageDialog.h"
2021-01-20 11:49:37 -04:00
# include "AssetRegistry/AssetRegistryModule.h"
2021-01-19 14:50:23 -04:00
2021-01-11 15:31:58 -04:00
# define LOCTEXT_NAMESPACE "SourceControlChangelist"
2021-01-18 15:31:14 -04:00
//////////////////////////////
static TSharedRef < SWidget > GetSCCFileWidget ( FSourceControlStateRef InFileState )
{
const FSlateBrush * IconBrush = FEditorStyle : : GetBrush ( " ContentBrowser.ColumnViewAssetIcon " ) ;
// Make icon overlays (eg, SCC and dirty status) a reasonable size in relation to the icon size (note: it is assumed this icon is square)
const float ICON_SCALING_FACTOR = 0.7f ;
const float IconOverlaySize = IconBrush - > ImageSize . X * ICON_SCALING_FACTOR ;
return SNew ( SOverlay )
// The actual icon
+ SOverlay : : Slot ( )
[
SNew ( SImage )
. Image ( IconBrush )
]
// Source control state
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Top )
[
SNew ( SBox )
. WidthOverride ( IconOverlaySize )
. HeightOverride ( IconOverlaySize )
[
SNew ( SLayeredImage , InFileState - > GetIcon ( ) )
]
] ;
}
struct FSCCFileDragDropOp : public FDragDropOperation
{
DRAG_DROP_OPERATOR_TYPE ( FSCCFileDragDropOp , FDragDropOperation ) ;
using FDragDropOperation : : Construct ;
virtual TSharedPtr < SWidget > GetDefaultDecorator ( ) const override
{
return GetSCCFileWidget ( Files [ 0 ] ) ;
}
TArray < FSourceControlStateRef > Files ;
} ;
//////////////////////////////
2021-01-11 15:31:58 -04:00
struct FChangelistTreeItem : public IChangelistTreeItem
{
FChangelistTreeItem ( FSourceControlChangelistStateRef InChangelistState )
: ChangelistState ( InChangelistState )
{
Type = IChangelistTreeItem : : Changelist ;
}
FText GetDisplayText ( ) const
{
return ChangelistState - > GetDisplayText ( ) ;
}
FText GetDescriptionText ( ) const
{
return ChangelistState - > GetDescriptionText ( ) ;
}
FSourceControlChangelistStateRef ChangelistState ;
} ;
struct FFileTreeItem : public IChangelistTreeItem
{
FFileTreeItem ( FSourceControlStateRef InFileState )
: FileState ( InFileState )
{
Type = IChangelistTreeItem : : File ;
FString Filename = FileState - > GetFilename ( ) ;
2021-01-20 11:49:37 -04:00
FText AssetName = LOCTEXT ( " SourceControl_DefaultAssetName " , " None " ) ;
FText AssetPath ;
FText AssetType = LOCTEXT ( " SourceControl_DefaultAssetType " , " Unknown " ) ;
2021-01-20 09:51:23 -04:00
FString AssetPackageName ;
2021-01-20 11:49:37 -04:00
FColor AssetColor = FColor ( // Copied from ContentBrowserCLR.cpp
127 + FColor : : Red . R / 2 , // Desaturate the colors a bit (GB colors were too.. much)
127 + FColor : : Red . G / 2 ,
127 + FColor : : Red . B / 2 ,
200 ) ; // Opacity
2021-01-20 09:51:23 -04:00
if ( FPackageName : : TryConvertFilenameToLongPackageName ( Filename , AssetPackageName ) )
{
2021-01-20 11:49:37 -04:00
AssetPath = FText : : FromString ( AssetPackageName ) ;
TArray < FAssetData > Assets ;
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
AssetRegistryModule . Get ( ) . GetAssetsByPackageName ( * AssetPackageName , Assets ) ;
if ( Assets . Num ( ) )
{
AssetName = FText : : FromString ( Assets [ 0 ] . AssetName . ToString ( ) ) ;
AssetColor = FColor : : White ;
if ( Assets . Num ( ) > 1 )
{
AssetType = LOCTEXT ( " SourceCOntrol_ManyAssetType " , " Multiple Assets " ) ;
}
else
{
AssetType = FText : : FromString ( Assets [ 0 ] . AssetClass . ToString ( ) ) ;
const FAssetToolsModule & AssetToolsModule = FModuleManager : : LoadModuleChecked < FAssetToolsModule > ( TEXT ( " AssetTools " ) ) ;
const TSharedPtr < IAssetTypeActions > AssetTypeActions = AssetToolsModule . Get ( ) . GetAssetTypeActionsForClass ( Assets [ 0 ] . GetClass ( ) ) . Pin ( ) ;
if ( AssetTypeActions . IsValid ( ) )
{
AssetColor = AssetTypeActions - > GetTypeColor ( ) ;
}
}
}
2021-01-20 09:51:23 -04:00
}
else
{
2021-01-20 11:49:37 -04:00
AssetPath = FText : : FromString ( Filename ) ;
2021-01-20 09:51:23 -04:00
}
2021-01-20 11:49:37 -04:00
DisplayName = AssetName ;
DisplayPath = AssetPath ;
DisplayType = AssetType ;
DisplayColor = AssetColor ;
}
FText GetDisplayPath ( ) const
{
return DisplayPath ;
}
FText GetDisplayName ( ) const
{
return DisplayName ;
}
FText GetDisplayType ( ) const
{
return DisplayType ;
}
FSlateColor GetDisplayColor ( ) const
{
return FSlateColor ( DisplayColor ) ;
2021-01-11 15:31:58 -04:00
}
FSourceControlStateRef FileState ;
2021-01-20 11:49:37 -04:00
private :
FText DisplayPath ;
FText DisplayName ;
FText DisplayType ;
FColor DisplayColor ;
2021-01-11 15:31:58 -04:00
} ;
SSourceControlChangelistsWidget : : SSourceControlChangelistsWidget ( )
{
}
void SSourceControlChangelistsWidget : : Construct ( const FArguments & InArgs )
{
2021-01-13 11:07:12 -04:00
// Register delegates
ISourceControlModule & SCCModule = ISourceControlModule : : Get ( ) ;
SCCModule . RegisterProviderChanged ( FSourceControlProviderChanged : : FDelegate : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnSourceControlProviderChanged ) ) ;
SourceControlStateChangedDelegateHandle = SCCModule . GetProvider ( ) . RegisterSourceControlStateChanged_Handle ( FSourceControlStateChanged : : FDelegate : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnSourceControlStateChanged ) ) ;
2021-01-11 15:31:58 -04:00
TreeView = CreateTreeviewWidget ( ) ;
ChildSlot
2021-01-13 16:50:22 -04:00
[
SNew ( SScrollBorder , TreeView . ToSharedRef ( ) )
. Visibility ( TAttribute < EVisibility > : : Create ( TAttribute < EVisibility > : : FGetter : : CreateLambda ( [ ] ( ) - > EVisibility { return ISourceControlModule : : Get ( ) . IsEnabled ( ) ? EVisibility : : Visible : EVisibility : : Hidden ; } ) ) )
2021-01-11 15:31:58 -04:00
[
2021-01-13 16:50:22 -04:00
TreeView . ToSharedRef ( )
]
] ;
bShouldRefresh = true ;
2021-01-11 15:31:58 -04:00
}
2021-01-13 16:50:22 -04:00
void SSourceControlChangelistsWidget : : Tick ( const FGeometry & AllottedGeometry , const double InCurrentTime , const float InDeltaTime )
{
if ( bShouldRefresh )
{
if ( ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
RequestRefresh ( ) ;
bShouldRefresh = false ;
}
else
{
// No provider available, clear changelist tree
ClearChangelistsTree ( ) ;
}
}
}
void SSourceControlChangelistsWidget : : RequestRefresh ( )
2021-01-11 15:31:58 -04:00
{
2021-01-13 11:07:12 -04:00
if ( ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
2021-01-13 16:50:22 -04:00
TSharedRef < FUpdatePendingChangelistsStatus , ESPMode : : ThreadSafe > UpdatePendingChangelistsOperation = ISourceControlOperation : : Create < FUpdatePendingChangelistsStatus > ( ) ;
2021-01-13 11:07:12 -04:00
UpdatePendingChangelistsOperation - > SetUpdateAllChangelists ( true ) ;
UpdatePendingChangelistsOperation - > SetUpdateFilesStates ( true ) ;
2021-01-11 15:31:58 -04:00
2021-01-13 11:07:12 -04:00
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
2021-01-13 16:50:22 -04:00
SourceControlProvider . Execute ( UpdatePendingChangelistsOperation , EConcurrency : : Asynchronous , FSourceControlOperationComplete : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnChangelistsStatusUpdated ) ) ;
2021-01-13 11:07:12 -04:00
}
else
{
// No provider available, clear changelist tree
2021-01-13 16:50:22 -04:00
ClearChangelistsTree ( ) ;
}
}
void SSourceControlChangelistsWidget : : ClearChangelistsTree ( )
{
if ( ! ChangelistsNodes . IsEmpty ( ) )
{
2021-01-13 11:07:12 -04:00
ChangelistsNodes . Empty ( ) ;
TreeView - > RequestTreeRefresh ( ) ;
}
}
2021-01-11 15:31:58 -04:00
2021-01-13 16:50:22 -04:00
void SSourceControlChangelistsWidget : : Refresh ( )
2021-01-11 15:31:58 -04:00
{
2021-01-13 11:07:12 -04:00
if ( ISourceControlModule : : Get ( ) . IsEnabled ( ) )
2021-01-11 15:31:58 -04:00
{
2021-01-13 11:07:12 -04:00
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
2021-01-11 15:31:58 -04:00
2021-01-13 11:07:12 -04:00
TArray < FSourceControlChangelistRef > Changelists = SourceControlProvider . GetChangelists ( EStateCacheUsage : : Use ) ;
TArray < FSourceControlChangelistStateRef > ChangelistsStates ;
SourceControlProvider . GetState ( Changelists , ChangelistsStates , EStateCacheUsage : : Use ) ;
ChangelistsNodes . Reset ( ChangelistsStates . Num ( ) ) ;
for ( FSourceControlChangelistStateRef ChangelistState : ChangelistsStates )
2021-01-11 15:31:58 -04:00
{
2021-01-13 11:07:12 -04:00
FChangelistTreeItemRef ChangelistTreeItem = MakeShareable ( new FChangelistTreeItem ( ChangelistState ) ) ;
2021-01-11 15:31:58 -04:00
2021-01-13 11:07:12 -04:00
for ( FSourceControlStateRef FileRef : ChangelistState - > GetFilesStates ( ) )
{
FChangelistTreeItemRef FileTreeItem = MakeShareable ( new FFileTreeItem ( FileRef ) ) ;
ChangelistTreeItem - > AddChild ( FileTreeItem ) ;
}
ChangelistsNodes . Add ( ChangelistTreeItem ) ;
}
2021-01-13 16:50:22 -04:00
TreeView - > RequestTreeRefresh ( ) ;
2021-01-13 11:07:12 -04:00
}
else
{
2021-01-13 16:50:22 -04:00
ClearChangelistsTree ( ) ;
2021-01-11 15:31:58 -04:00
}
}
2021-01-13 16:50:22 -04:00
void SSourceControlChangelistsWidget : : OnSourceControlProviderChanged ( ISourceControlProvider & OldProvider , ISourceControlProvider & NewProvider )
2021-01-11 15:31:58 -04:00
{
2021-01-13 16:50:22 -04:00
OldProvider . UnregisterSourceControlStateChanged_Handle ( SourceControlStateChangedDelegateHandle ) ;
SourceControlStateChangedDelegateHandle = NewProvider . RegisterSourceControlStateChanged_Handle ( FSourceControlStateChanged : : FDelegate : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnSourceControlStateChanged ) ) ;
2021-01-11 15:31:58 -04:00
2021-01-13 16:50:22 -04:00
bShouldRefresh = true ;
}
2021-01-11 15:31:58 -04:00
2021-01-13 16:50:22 -04:00
void SSourceControlChangelistsWidget : : OnSourceControlStateChanged ( )
{
Refresh ( ) ;
}
2021-01-11 15:31:58 -04:00
2021-01-13 16:50:22 -04:00
void SSourceControlChangelistsWidget : : OnChangelistsStatusUpdated ( const FSourceControlOperationRef & InOperation , ECommandResult : : Type InType )
{
Refresh ( ) ;
2021-01-11 15:31:58 -04:00
}
2021-01-13 20:52:07 -04:00
void SChangelistTree : : Private_SetItemSelection ( FChangelistTreeItemPtr TheItem , bool bShouldBeSelected , bool bWasUserDirected )
{
bool bAllowSelectionChange = true ;
if ( bShouldBeSelected & & ! SelectedItems . IsEmpty ( ) )
{
// Prevent selecting changelists and files at the same time.
FChangelistTreeItemPtr CurrentlySelectedItem = ( * SelectedItems . begin ( ) ) ;
if ( TheItem - > GetTreeItemType ( ) ! = CurrentlySelectedItem - > GetTreeItemType ( ) )
{
bAllowSelectionChange = false ;
}
// Prevent selecting items that don't share the same root
else if ( TheItem - > GetParent ( ) ! = CurrentlySelectedItem - > GetParent ( ) )
{
bAllowSelectionChange = false ;
}
}
if ( bAllowSelectionChange )
{
STreeView : : Private_SetItemSelection ( TheItem , bShouldBeSelected , bWasUserDirected ) ;
}
}
2021-01-18 09:42:33 -04:00
FSourceControlChangelistStatePtr SSourceControlChangelistsWidget : : GetCurrentChangelistState ( )
{
if ( ! TreeView )
{
return nullptr ;
}
TArray < FChangelistTreeItemPtr > SelectedItems = TreeView - > GetSelectedItems ( ) ;
if ( SelectedItems . Num ( ) ! = 1 | | SelectedItems [ 0 ] - > GetTreeItemType ( ) ! = IChangelistTreeItem : : Changelist )
{
return nullptr ;
}
else
{
return StaticCastSharedPtr < FChangelistTreeItem > ( SelectedItems [ 0 ] ) - > ChangelistState ;
}
}
FSourceControlChangelistPtr SSourceControlChangelistsWidget : : GetCurrentChangelist ( )
{
FSourceControlChangelistStatePtr ChangelistState = GetCurrentChangelistState ( ) ;
return ChangelistState ? ( FSourceControlChangelistPtr ) ( ChangelistState - > GetChangelist ( ) ) : nullptr ;
}
FSourceControlChangelistStatePtr SSourceControlChangelistsWidget : : GetChangelistStateFromFileSelection ( )
{
if ( ! TreeView )
{
return nullptr ;
}
TArray < FChangelistTreeItemPtr > SelectedItems = TreeView - > GetSelectedItems ( ) ;
if ( SelectedItems . Num ( ) = = 0 | | SelectedItems [ 0 ] - > GetTreeItemType ( ) ! = IChangelistTreeItem : : File )
{
return nullptr ;
}
else
{
return StaticCastSharedPtr < FChangelistTreeItem > ( SelectedItems [ 0 ] - > GetParent ( ) ) - > ChangelistState ;
}
}
FSourceControlChangelistPtr SSourceControlChangelistsWidget : : GetChangelistFromFileSelection ( )
{
FSourceControlChangelistStatePtr ChangelistState = GetChangelistStateFromFileSelection ( ) ;
return ChangelistState ? ( FSourceControlChangelistPtr ) ( ChangelistState - > GetChangelist ( ) ) : nullptr ;
}
TArray < FString > SSourceControlChangelistsWidget : : GetSelectedFiles ( )
{
TArray < FChangelistTreeItemPtr > SelectedItems = TreeView - > GetSelectedItems ( ) ;
if ( SelectedItems . Num ( ) = = 0 | | SelectedItems [ 0 ] - > GetTreeItemType ( ) ! = IChangelistTreeItem : : File )
{
return TArray < FString > ( ) ;
}
else
{
TArray < FString > Files ;
for ( FChangelistTreeItemPtr Item : SelectedItems )
{
Files . Add ( StaticCastSharedPtr < FFileTreeItem > ( Item ) - > FileState - > GetFilename ( ) ) ;
}
return Files ;
}
}
void SSourceControlChangelistsWidget : : OnNewChangelist ( )
{
FText ChangelistDescription ;
bool bOk = GetChangelistDescription (
nullptr ,
LOCTEXT ( " SourceControl.Changelist.New.Title " , " New Changelist... " ) ,
LOCTEXT ( " SourceControl.Changelist.New.Label " , " Enter a description for the changelist: " ) ,
ChangelistDescription ) ;
if ( ! bOk )
{
return ;
}
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
auto NewChangelistOperation = ISourceControlOperation : : Create < FNewChangelist > ( ) ;
NewChangelistOperation - > SetDescription ( ChangelistDescription ) ;
SourceControlProvider . Execute ( NewChangelistOperation ) ;
Refresh ( ) ;
}
void SSourceControlChangelistsWidget : : OnDeleteChangelist ( )
{
if ( GetCurrentChangelist ( ) = = nullptr )
{
return ;
}
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
SourceControlProvider . Execute ( ISourceControlOperation : : Create < FDeleteChangelist > ( ) , GetCurrentChangelist ( ) ) ;
Refresh ( ) ;
}
bool SSourceControlChangelistsWidget : : CanDeleteChangelist ( )
{
FSourceControlChangelistStatePtr Changelist = GetCurrentChangelistState ( ) ;
return Changelist ! = nullptr & & Changelist - > GetFilesStates ( ) . Num ( ) = = 0 & & Changelist - > GetShelvedFilesStates ( ) . Num ( ) = = 0 ;
}
void SSourceControlChangelistsWidget : : OnEditChangelist ( )
{
FSourceControlChangelistStatePtr ChangelistState = GetCurrentChangelistState ( ) ;
if ( ChangelistState = = nullptr )
{
return ;
}
FText NewChangelistDescription = ChangelistState - > GetDescriptionText ( ) ;
bool bOk = GetChangelistDescription (
nullptr ,
LOCTEXT ( " SourceControl.Changelist.New.Title " , " Edit Changelist... " ) ,
LOCTEXT ( " SourceControl.Changelist.New.Label " , " Enter a new description for the changelist: " ) ,
NewChangelistDescription ) ;
if ( ! bOk )
{
return ;
}
auto EditChangelistOperation = ISourceControlOperation : : Create < FEditChangelist > ( ) ;
EditChangelistOperation - > SetDescription ( NewChangelistDescription ) ;
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
SourceControlProvider . Execute ( EditChangelistOperation , ChangelistState - > GetChangelist ( ) ) ;
Refresh ( ) ;
}
void SSourceControlChangelistsWidget : : OnRevertUnchanged ( )
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
auto RevertUnchangedOperation = ISourceControlOperation : : Create < FRevertUnchanged > ( ) ;
if ( GetCurrentChangelist ( ) ! = nullptr )
{
// Operation on full changelist
SourceControlProvider . Execute ( RevertUnchangedOperation , GetCurrentChangelist ( ) ) ;
}
else
{
// Operation on files in a changelist
SourceControlProvider . Execute ( RevertUnchangedOperation , GetChangelistFromFileSelection ( ) , GetSelectedFiles ( ) ) ;
}
Refresh ( ) ;
}
2021-01-19 14:50:23 -04:00
void SSourceControlChangelistsWidget : : OnRevert ( )
{
2021-01-20 09:51:23 -04:00
FText DialogText ;
FText DialogTitle ;
2021-01-19 14:50:23 -04:00
2021-01-20 09:51:23 -04:00
const bool bApplyOnChangelist = ( GetCurrentChangelist ( ) ! = nullptr ) ;
if ( bApplyOnChangelist )
{
DialogText = LOCTEXT ( " SourceControl_ConfirmRevertChangelist " , " Are you sure you want to revert this changelist? " ) ;
DialogTitle = LOCTEXT ( " SourceControl_ConfirmRevertChangelist_Title " , " Confirm changelist revert " ) ;
}
else
{
DialogText = LOCTEXT ( " SourceControl_ConfirmRevertFiles " , " Are you sure you want to revert the selected files? " ) ;
DialogTitle = LOCTEXT ( " SourceControl_ConfirmReverFiles_Title " , " Confirm files revert " ) ;
}
EAppReturnType : : Type UserConfirmation = FMessageDialog : : Open ( EAppMsgType : : OkCancel , EAppReturnType : : Ok , DialogText , & DialogTitle ) ;
if ( UserConfirmation ! = EAppReturnType : : Ok )
{
return ;
}
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
2021-01-19 14:50:23 -04:00
auto RevertOperation = ISourceControlOperation : : Create < FRevert > ( ) ;
if ( GetCurrentChangelist ( ) ! = nullptr )
{
// Operation on full changelist
SourceControlProvider . Execute ( RevertOperation , GetCurrentChangelist ( ) ) ;
}
else
{
// Operation on files in a changelist
SourceControlProvider . Execute ( RevertOperation , GetChangelistFromFileSelection ( ) , GetSelectedFiles ( ) ) ;
}
Refresh ( ) ;
}
2021-01-18 09:42:33 -04:00
void SSourceControlChangelistsWidget : : OnSubmitChangelist ( )
{
FSourceControlChangelistPtr Changelist = GetCurrentChangelist ( ) ;
if ( ! Changelist )
{
return ;
}
2021-01-20 09:51:23 -04:00
const FText DialogText = LOCTEXT ( " SourceControl_ConfirmSubmit " , " Are you sure you want to submit this changelist? " ) ;
const FText DialogTitle = LOCTEXT ( " SourceControl_ConfirmSubmit_Title " , " Confirm changelist submit " ) ;
2021-01-18 09:42:33 -04:00
2021-01-20 09:51:23 -04:00
EAppReturnType : : Type UserConfirmation = FMessageDialog : : Open ( EAppMsgType : : OkCancel , EAppReturnType : : Ok , DialogText , & DialogTitle ) ;
if ( UserConfirmation = = EAppReturnType : : Ok )
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
auto SubmitChangelistOperation = ISourceControlOperation : : Create < FCheckIn > ( ) ;
SourceControlProvider . Execute ( SubmitChangelistOperation , Changelist ) ;
Refresh ( ) ;
}
2021-01-18 09:42:33 -04:00
}
bool SSourceControlChangelistsWidget : : CanSubmitChangelist ( )
{
FSourceControlChangelistStatePtr Changelist = GetCurrentChangelistState ( ) ;
return Changelist ! = nullptr & & Changelist - > GetFilesStates ( ) . Num ( ) > = 0 & & Changelist - > GetShelvedFilesStates ( ) . Num ( ) = = 0 ;
}
2021-01-19 14:50:23 -04:00
void SSourceControlChangelistsWidget : : OnLocateFile ( )
{
FAssetToolsModule & AssetToolsModule = FModuleManager : : LoadModuleChecked < FAssetToolsModule > ( TEXT ( " AssetTools " ) ) ;
TArray < UObject * > AssetsToSync ;
TArray < FString > SelectedFiles = GetSelectedFiles ( ) ;
AssetsToSync . Reserve ( SelectedFiles . Num ( ) ) ;
for ( const FString & SelectedFile : SelectedFiles )
{
FString AssetPackageName ;
if ( FPackageName : : TryConvertFilenameToLongPackageName ( SelectedFile , AssetPackageName ) )
{
UPackage * AssetPackage = LoadPackage ( nullptr , * AssetPackageName , LOAD_ForDiff | LOAD_DisableCompileOnLoad ) ;
// grab the asset from the package - we assume asset name matches file name
FString AssetName = FPaths : : GetBaseFilename ( SelectedFile ) ;
UObject * SelectedAsset = FindObject < UObject > ( AssetPackage , * AssetName ) ;
if ( SelectedAsset )
{
AssetsToSync . Add ( SelectedAsset ) ;
}
}
}
if ( AssetsToSync . Num ( ) > 0 )
{
FContentBrowserModule & ContentBrowserModule = FModuleManager : : Get ( ) . LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) ;
ContentBrowserModule . Get ( ) . SyncBrowserToAssets ( AssetsToSync , true ) ;
}
}
bool SSourceControlChangelistsWidget : : CanLocateFile ( )
{
return GetSelectedFiles ( ) . Num ( ) > 0 ;
}
void SSourceControlChangelistsWidget : : OnShowHistory ( )
{
TArray < FString > SelectedFiles = GetSelectedFiles ( ) ;
if ( SelectedFiles . Num ( ) > 0 )
{
FSourceControlWindows : : DisplayRevisionHistory ( SelectedFiles ) ;
}
}
void SSourceControlChangelistsWidget : : OnDiffAgainstDepot ( )
{
TArray < FString > SelectedFiles = GetSelectedFiles ( ) ;
if ( SelectedFiles . Num ( ) > 0 )
{
FSourceControlWindows : : DiffAgainstWorkspace ( SelectedFiles [ 0 ] ) ;
}
}
bool SSourceControlChangelistsWidget : : CanDiffAgainstDepot ( )
{
return GetSelectedFiles ( ) . Num ( ) = = 1 ;
}
2021-01-18 09:42:33 -04:00
TSharedPtr < SWidget > SSourceControlChangelistsWidget : : OnOpenContextMenu ( )
{
UToolMenus * ToolMenus = UToolMenus : : Get ( ) ;
static const FName MenuName = " SourceControl.ChangelistContextMenu " ;
if ( ! ToolMenus - > IsMenuRegistered ( MenuName ) )
{
ToolMenus - > RegisterMenu ( MenuName ) ;
}
// Build up the menu for a selection
FToolMenuContext Context ;
UToolMenu * Menu = ToolMenus - > GenerateMenu ( MenuName , Context ) ;
bool bHasSelectedChangelist = ( GetCurrentChangelist ( ) ! = nullptr ) ;
bool bHasEmptySelection = ( GetCurrentChangelist ( ) = = nullptr & & GetSelectedFiles ( ) . Num ( ) = = 0 ) ;
FToolMenuSection & Section = Menu - > AddSection ( " Source Control " ) ;
// This should appear only on change lists
if ( bHasSelectedChangelist )
{
Section . AddMenuEntry ( " SubmitChangelist " , LOCTEXT ( " SourceControl_SubmitChangelist " , " Submit Changelist " ) , LOCTEXT ( " SourceControl_SubmitChangeslit_Tooltip " , " Submits a changelist " ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnSubmitChangelist ) ,
FCanExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : CanSubmitChangelist ) ) ) ;
}
// This can appear on both files & changelist
if ( ! bHasEmptySelection )
{
Section . AddMenuEntry ( " RevertUnchanged " , LOCTEXT ( " SourceControl_RevertUnchanged " , " Revert Unchanged " ) , LOCTEXT ( " SourceControl_Revert_Unchanged_Tooltip " , " Reverts unchanged files & changelists " ) , FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnRevertUnchanged ) ) ) ;
2021-01-19 14:50:23 -04:00
Section . AddMenuEntry ( " Revert " , LOCTEXT ( " SourceControl_Revert " , " Revert Files " ) , LOCTEXT ( " SourceControl_Revert_Tooltip " , " Reverts all files in the changelist or from the selection " ) , FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnRevert ) ) ) ;
}
if ( bHasEmptySelection | | bHasSelectedChangelist )
{
Section . AddSeparator ( " Changelists " ) ;
}
// This should appear only if we have no selection
if ( bHasEmptySelection )
{
Section . AddMenuEntry ( " NewChangelist " , LOCTEXT ( " SourceControl_NewChangelist " , " New Changelist " ) , LOCTEXT ( " SourceControl_NewChangelist_Tooltip " , " Creates an empty changelist " ) , FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnNewChangelist ) ) ) ;
}
if ( bHasSelectedChangelist )
{
Section . AddMenuEntry ( " EditChangelist " , LOCTEXT ( " SourceControl_EditChangelist " , " Edit Changelist " ) , LOCTEXT ( " SourceControl_Edit_Changelist_Tooltip " , " Edit a changelist description " ) , FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnEditChangelist ) ) ) ;
Section . AddMenuEntry ( " DeleteChangelist " , LOCTEXT ( " SourceControl_DeleteChangelist " , " Delete Empty Changelist " ) , LOCTEXT ( " SourceControl_Delete_Changelist_Tooltip " , " Deletes an empty changelist " ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnDeleteChangelist ) ,
FCanExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : CanDeleteChangelist ) ) ) ;
}
// Files-only operations
if ( ! bHasEmptySelection & & ! bHasSelectedChangelist )
{
Section . AddSeparator ( " Files " ) ;
Section . AddMenuEntry ( " Locate File " , LOCTEXT ( " SourceControl_LocateFile " , " Locate File " ) , LOCTEXT ( " SourceControl_LocateFile_Tooltip " , " Locate File in Project... " ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnLocateFile ) ,
FCanExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : CanLocateFile ) ) ) ;
Section . AddMenuEntry ( " Show History " , LOCTEXT ( " SourceControl_ShowHistory " , " Show History " ) , LOCTEXT ( " SourceControl_ShowHistory_ToolTip " , " Show File History From Selection... " ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnShowHistory ) ) ) ;
Section . AddMenuEntry ( " Diff Against Local Version " , LOCTEXT ( " SourceControl_DiffAgainstDepot " , " Diff Against Depot " ) , LOCTEXT ( " SourceControl_DiffAgainstLocal_Tooltip " , " Diff local file against depot revision. " ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : OnDiffAgainstDepot ) ,
FCanExecuteAction : : CreateSP ( this , & SSourceControlChangelistsWidget : : CanDiffAgainstDepot ) ) ) ;
2021-01-18 09:42:33 -04:00
}
return ToolMenus - > GenerateWidget ( Menu ) ;
}
2021-01-11 15:31:58 -04:00
TSharedRef < SChangelistTree > SSourceControlChangelistsWidget : : CreateTreeviewWidget ( )
{
return SAssignNew ( TreeView , SChangelistTree )
. ItemHeight ( 24.0f )
. TreeItemsSource ( & ChangelistsNodes )
. OnGenerateRow ( this , & SSourceControlChangelistsWidget : : OnGenerateRow )
. OnGetChildren ( this , & SSourceControlChangelistsWidget : : OnGetChildren )
. SelectionMode ( ESelectionMode : : Multi )
2021-01-18 09:42:33 -04:00
. OnContextMenuOpening ( this , & SSourceControlChangelistsWidget : : OnOpenContextMenu )
2021-01-11 15:31:58 -04:00
. HeaderRow
(
SNew ( SHeaderRow )
+ SHeaderRow : : Column ( " Change " )
. DefaultLabel ( LOCTEXT ( " Change " , " Change " ) )
. FillWidth ( 0.2f )
+ SHeaderRow : : Column ( " Description " )
. DefaultLabel ( LOCTEXT ( " Description " , " Description " ) )
2021-01-20 11:49:37 -04:00
. FillWidth ( 0.6f )
+ SHeaderRow : : Column ( " Type " )
. DefaultLabel ( LOCTEXT ( " Type " , " Type " ) )
. FillWidth ( 0.2f )
2021-01-11 15:31:58 -04:00
) ;
}
class SChangelistTableRow : public SMultiColumnTableRow < FChangelistTreeItemPtr >
{
public :
SLATE_BEGIN_ARGS ( SChangelistTableRow )
: _TreeItemToVisualize ( )
{ }
SLATE_ARGUMENT ( FChangelistTreeItemPtr , TreeItemToVisualize )
SLATE_END_ARGS ( )
public :
/**
* Construct child widgets that comprise this widget .
*
* @ param InArgs Declaration from which to construct this widget .
*/
void Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & InOwner )
{
TreeItem = static_cast < FChangelistTreeItem * > ( InArgs . _TreeItemToVisualize . Get ( ) ) ;
auto Args = FSuperRowType : : FArguments ( ) ;
SMultiColumnTableRow < FChangelistTreeItemPtr > : : Construct ( Args , InOwner ) ;
}
// SMultiColumnTableRow overrides
virtual TSharedRef < SWidget > GenerateWidgetForColumn ( const FName & ColumnName ) override
{
if ( ColumnName = = TEXT ( " Change " ) )
{
const FSlateBrush * IconBrush = FEditorStyle : : GetBrush ( " SourceControl.Changelist " ) ;
return SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SExpanderArrow , SharedThis ( this ) )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SImage )
. Image ( IconBrush )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 2.0f , 0.0f )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Text ( this , & SChangelistTableRow : : GetChangelistText )
] ;
}
else if ( ColumnName = = TEXT ( " Description " ) )
{
return SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 2.0f , 0.0f )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Text ( this , & SChangelistTableRow : : GetChangelistDescriptionText )
] ;
}
else
{
return SNullWidget : : NullWidget ;
}
}
FText GetChangelistText ( ) const
{
return TreeItem - > GetDisplayText ( ) ;
}
FText GetChangelistDescriptionText ( ) const
{
FString DescriptionString = TreeItem - > GetDescriptionText ( ) . ToString ( ) ;
DescriptionString . ReplaceInline ( TEXT ( " \n " ) , TEXT ( " " ) ) ;
DescriptionString . TrimEndInline ( ) ;
return FText : : FromString ( DescriptionString ) ;
}
2021-01-18 15:31:14 -04:00
protected :
//~ Begin STableRow Interface.
virtual FReply OnDrop ( const FGeometry & InGeometry , const FDragDropEvent & InDragDropEvent ) override
{
TSharedPtr < FSCCFileDragDropOp > Operation = InDragDropEvent . GetOperationAs < FSCCFileDragDropOp > ( ) ;
if ( Operation . IsValid ( ) )
{
FSourceControlChangelistPtr Changelist = TreeItem - > ChangelistState - > GetChangelist ( ) ;
check ( Changelist . IsValid ( ) ) ;
TArray < FString > Files ;
Algo : : Transform ( Operation - > Files , Files , [ ] ( const FSourceControlStateRef & State ) { return State - > GetFilename ( ) ; } ) ;
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
SourceControlProvider . Execute ( ISourceControlOperation : : Create < FMoveToChangelist > ( ) , Changelist , Files ) ;
}
return FReply : : Handled ( ) ;
}
//~ End STableRow Interface.
2021-01-11 15:31:58 -04:00
private :
/** The info about the widget that we are visualizing. */
FChangelistTreeItem * TreeItem ;
} ;
2021-01-20 11:49:37 -04:00
class SFileTableRow : public SMultiColumnTableRow < FChangelistTreeItemPtr >
2021-01-11 15:31:58 -04:00
{
public :
SLATE_BEGIN_ARGS ( SFileTableRow )
: _TreeItemToVisualize ( )
{ }
SLATE_ARGUMENT ( FChangelistTreeItemPtr , TreeItemToVisualize )
2021-01-18 15:31:14 -04:00
SLATE_EVENT ( FOnDragDetected , OnDragDetected )
2021-01-11 15:31:58 -04:00
SLATE_END_ARGS ( )
public :
/**
* Construct child widgets that comprise this widget .
*
* @ param InArgs Declaration from which to construct this widget .
*/
void Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & InOwner )
{
TreeItem = static_cast < FFileTreeItem * > ( InArgs . _TreeItemToVisualize . Get ( ) ) ;
2021-01-20 11:49:37 -04:00
auto Args = FSuperRowType : : FArguments ( )
. OnDragDetected ( InArgs . _OnDragDetected )
. ShowSelection ( true ) ;
FSuperRowType : : Construct ( Args , InOwner ) ;
}
// SMultiColumnTableRow overrides
virtual TSharedRef < SWidget > GenerateWidgetForColumn ( const FName & ColumnName ) override
{
if ( ColumnName = = TEXT ( " Change " ) ) // eq. to name
{
return SNew ( SHorizontalBox )
2021-01-11 15:31:58 -04:00
// Icon
2021-01-18 15:31:14 -04:00
+ SHorizontalBox : : Slot ( )
2021-01-11 15:31:58 -04:00
. AutoWidth ( )
. Padding ( 40 , 0 , 4 , 0 )
[
2021-01-18 15:31:14 -04:00
GetSCCFileWidget ( TreeItem - > FileState )
2021-01-11 15:31:58 -04:00
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
2021-01-20 11:49:37 -04:00
. Text ( this , & SFileTableRow : : GetDisplayName )
] ;
}
else if ( ColumnName = = TEXT ( " Description " ) ) // eq. to path
{
return SNew ( STextBlock )
. Text ( this , & SFileTableRow : : GetDisplayPath ) ;
}
else if ( ColumnName = = TEXT ( " Type " ) )
{
return SNew ( STextBlock )
. Text ( this , & SFileTableRow : : GetDisplayType )
. ColorAndOpacity ( this , & SFileTableRow : : GetDisplayColor ) ;
}
else
{
return SNullWidget : : NullWidget ;
}
2021-01-11 15:31:58 -04:00
}
2021-01-20 11:49:37 -04:00
FText GetDisplayName ( ) const
2021-01-11 15:31:58 -04:00
{
2021-01-20 11:49:37 -04:00
return TreeItem - > GetDisplayName ( ) ;
}
FText GetDisplayPath ( ) const
{
return TreeItem - > GetDisplayPath ( ) ;
}
FText GetDisplayType ( ) const
{
return TreeItem - > GetDisplayType ( ) ;
}
FSlateColor GetDisplayColor ( ) const
{
return TreeItem - > GetDisplayColor ( ) ;
2021-01-11 15:31:58 -04:00
}
2021-01-18 15:31:14 -04:00
protected :
//~ Begin STableRow Interface.
virtual void OnDragEnter ( FGeometry const & InGeometry , FDragDropEvent const & InDragDropEvent ) override
{
TSharedPtr < FDragDropOperation > DragOperation = InDragDropEvent . GetOperation ( ) ;
DragOperation - > SetCursorOverride ( EMouseCursor : : SlashedCircle ) ;
}
virtual void OnDragLeave ( FDragDropEvent const & InDragDropEvent ) override
{
TSharedPtr < FDragDropOperation > DragOperation = InDragDropEvent . GetOperation ( ) ;
DragOperation - > SetCursorOverride ( EMouseCursor : : None ) ;
}
//~ End STableRow Interface.
2021-01-11 15:31:58 -04:00
private :
/** The info about the widget that we are visualizing. */
FFileTreeItem * TreeItem ;
} ;
TSharedRef < ITableRow > SSourceControlChangelistsWidget : : OnGenerateRow ( FChangelistTreeItemPtr InTreeItem , const TSharedRef < STableViewBase > & OwnerTable )
{
switch ( InTreeItem - > GetTreeItemType ( ) )
{
case IChangelistTreeItem : : Changelist :
return SNew ( SChangelistTableRow , OwnerTable )
. TreeItemToVisualize ( InTreeItem ) ;
case IChangelistTreeItem : : File :
return SNew ( SFileTableRow , OwnerTable )
2021-01-18 15:31:14 -04:00
. TreeItemToVisualize ( InTreeItem )
. OnDragDetected ( this , & SSourceControlChangelistsWidget : : OnFilesDragged ) ;
2021-01-11 15:31:58 -04:00
default :
check ( false ) ;
} ;
return SNew ( STableRow < TSharedPtr < FString > > , OwnerTable ) ;
}
2021-01-18 15:31:14 -04:00
FReply SSourceControlChangelistsWidget : : OnFilesDragged ( const FGeometry & InGeometry , const FPointerEvent & InMouseEvent )
{
if ( InMouseEvent . IsMouseButtonDown ( EKeys : : LeftMouseButton ) & & ! TreeView - > GetSelectedItems ( ) . IsEmpty ( ) )
{
TSharedRef < FSCCFileDragDropOp > Operation = MakeShareable ( new FSCCFileDragDropOp ( ) ) ;
Algo : : Transform ( TreeView - > GetSelectedItems ( ) , Operation - > Files , [ ] ( FChangelistTreeItemPtr InTreeItem ) { check ( InTreeItem - > GetTreeItemType ( ) = = IChangelistTreeItem : : File ) ; return static_cast < FFileTreeItem * > ( InTreeItem . Get ( ) ) - > FileState ; } ) ;
Operation - > Construct ( ) ;
return FReply : : Handled ( ) . BeginDragDrop ( Operation ) ;
}
return FReply : : Unhandled ( ) ;
}
2021-01-11 15:31:58 -04:00
void SSourceControlChangelistsWidget : : OnGetChildren ( FChangelistTreeItemPtr InParent , TArray < FChangelistTreeItemPtr > & OutChildren )
{
for ( auto & Child : InParent - > GetChildren ( ) )
{
// Should never have bogus entries in this list
check ( Child . IsValid ( ) ) ;
OutChildren . Add ( Child ) ;
}
}
# undef LOCTEXT_NAMESPACE