2021-02-04 17:41:41 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SSourceControlCommon.h"
2021-10-29 09:53:59 -04:00
# include "Algo/Count.h"
# include "Algo/Find.h"
2023-12-12 17:18:07 -05:00
# include "Algo/Replace.h"
2022-05-02 18:06:48 -04:00
# include "AssetRegistry/AssetData.h"
2022-01-07 10:01:19 -05:00
# include "ActorFolder.h"
# include "ActorFolderDesc.h"
2024-06-28 04:07:02 -04:00
# include "AssetDefinitionRegistry.h"
2021-02-04 17:41:41 -04:00
# include "AssetToolsModule.h"
2022-05-09 13:12:28 -04:00
# include "Styling/AppStyle.h"
2021-08-31 15:14:29 -04:00
# include "ISourceControlModule.h"
# include "SourceControlAssetDataCache.h"
2021-02-04 17:41:41 -04:00
# include "SourceControlHelpers.h"
2022-09-07 17:15:39 -04:00
# include "SSourceControlFileDialog.h"
2021-02-04 17:41:41 -04:00
# include "Widgets/SOverlay.h"
# include "Widgets/Images/SImage.h"
# include "Widgets/Images/SLayeredImage.h"
# include "Widgets/Layout/SBox.h"
2022-09-07 17:15:55 -04:00
# include "Framework/Docking/TabManager.h"
# include "Framework/Notifications/NotificationManager.h"
2022-11-01 16:30:00 -04:00
# include "Logging/MessageLog.h"
2024-08-26 04:13:38 -04:00
# include "Misc/PathViews.h"
2022-09-07 17:15:39 -04:00
# include "Misc/ScopedSlowTask.h"
2022-11-01 16:30:00 -04:00
# include "Modules/ModuleManager.h"
2022-09-07 17:15:55 -04:00
# include "Editor.h"
2021-02-04 17:41:41 -04:00
# define LOCTEXT_NAMESPACE "SourceControlChangelist"
//////////////////////////////////////////////////////////////////////////
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
2021-02-04 17:41:41 -04:00
FChangelistTreeItemPtr IChangelistTreeItem : : GetParent ( ) const
{
return Parent ;
}
const TArray < FChangelistTreeItemPtr > & IChangelistTreeItem : : GetChildren ( ) const
{
return Children ;
}
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
void IChangelistTreeItem : : AddChild ( TSharedRef < IChangelistTreeItem > Child )
2021-02-04 17:41:41 -04:00
{
Child - > Parent = AsShared ( ) ;
Children . Add ( MoveTemp ( Child ) ) ;
}
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
void IChangelistTreeItem : : RemoveChild ( const TSharedRef < IChangelistTreeItem > & Child )
2021-02-04 17:41:41 -04:00
{
if ( Children . Remove ( Child ) )
{
Child - > Parent = nullptr ;
}
}
2022-11-01 16:30:00 -04:00
void IChangelistTreeItem : : RemoveAllChildren ( )
{
for ( TSharedPtr < IChangelistTreeItem > & Child : Children )
{
Child - > Parent = nullptr ;
}
Children . Reset ( ) ;
}
2022-09-30 12:21:26 -04:00
static FString RetrieveAssetName ( const FAssetData & InAssetData )
{
static const FName NAME_ActorLabel ( TEXT ( " ActorLabel " ) ) ;
if ( InAssetData . FindTag ( NAME_ActorLabel ) )
{
2023-10-06 09:14:09 -04:00
FString ResultAssetName ;
2022-09-30 12:21:26 -04:00
InAssetData . GetTagValue ( NAME_ActorLabel , ResultAssetName ) ;
return ResultAssetName ;
}
2023-10-06 09:14:09 -04:00
else if ( InAssetData . FindTag ( FPrimaryAssetId : : PrimaryAssetDisplayNameTag ) )
{
FString ResultAssetName ;
InAssetData . GetTagValue ( FPrimaryAssetId : : PrimaryAssetDisplayNameTag , ResultAssetName ) ;
return ResultAssetName ;
}
2022-09-30 12:21:26 -04:00
else if ( InAssetData . AssetClassPath = = UActorFolder : : StaticClass ( ) - > GetClassPathName ( ) )
{
FString ActorFolderPath = UActorFolder : : GetAssetRegistryInfoFromPackage ( InAssetData . PackageName ) . GetDisplayName ( ) ;
if ( ! ActorFolderPath . IsEmpty ( ) )
{
return ActorFolderPath ;
}
}
return InAssetData . AssetName . ToString ( ) ;
}
static FString RetrieveAssetPath ( const FAssetData & InAssetData )
{
int32 LastDot = - 1 ;
FString Path = InAssetData . GetObjectPathString ( ) ;
// Strip asset name from object path
if ( Path . FindLastChar ( ' . ' , LastDot ) )
{
Path . LeftInline ( LastDot ) ;
}
return Path ;
}
2024-06-28 04:07:02 -04:00
static FString RetrieveAssetTypeName ( const FAssetData & InAssetData )
{
if ( UAssetDefinitionRegistry * AssetDefinitionRegistry = UAssetDefinitionRegistry : : Get ( ) )
{
const UAssetDefinition * AssetDefinition = AssetDefinitionRegistry - > GetAssetDefinitionForAsset ( InAssetData ) ;
if ( AssetDefinition )
{
return AssetDefinition - > GetAssetDisplayName ( ) . ToString ( ) ;
}
}
return InAssetData . AssetClassPath . ToString ( ) ;
}
static void RefreshAssetInformationInternal ( const TArray < FAssetData > & Assets , const FString & InFilename , FString & OutAssetName , FString & OutAssetPath , FString & OutAssetType , FString & OutAssetTypeName , FText & OutPackageName , FColor & OutAssetTypeColor )
2022-09-30 12:21:26 -04:00
{
// Initialize display-related members
FString Filename = InFilename ;
2024-08-26 04:13:38 -04:00
FString Extension = FPaths : : GetExtension ( Filename ) ;
2022-09-30 12:21:26 -04:00
FString TempAssetName = SSourceControlCommon : : GetDefaultAssetName ( ) . ToString ( ) ;
FString TempAssetPath = Filename ;
FString TempAssetType = SSourceControlCommon : : GetDefaultAssetType ( ) . ToString ( ) ;
2024-06-28 04:07:02 -04:00
FString TempAssetTypeName = SSourceControlCommon : : GetDefaultAssetType ( ) . ToString ( ) ;
2022-09-30 12:21:26 -04:00
FString TempPackageName = Filename ;
FColor TempAssetColor = 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
2024-08-26 04:13:38 -04:00
bool bIsPackageExtension =
FPackageName : : IsPackageExtension ( * Extension ) | |
FPackageName : : IsVerseExtension ( * Extension ) ;
2022-09-30 12:21:26 -04:00
if ( Assets . Num ( ) > 0 )
{
auto IsNotRedirector = [ ] ( const FAssetData & InAssetData ) { return ! InAssetData . IsRedirector ( ) ; } ;
int32 NumUserFacingAsset = Algo : : CountIf ( Assets , IsNotRedirector ) ;
if ( NumUserFacingAsset = = 1 )
{
const FAssetData & AssetData = * Algo : : FindByPredicate ( Assets , IsNotRedirector ) ;
TempAssetName = RetrieveAssetName ( AssetData ) ;
TempAssetPath = RetrieveAssetPath ( AssetData ) ;
TempAssetType = AssetData . AssetClassPath . ToString ( ) ;
2024-06-28 04:07:02 -04:00
TempAssetTypeName = RetrieveAssetTypeName ( AssetData ) ;
2022-09-30 12:21:26 -04:00
const FAssetToolsModule & AssetToolsModule = FModuleManager : : LoadModuleChecked < FAssetToolsModule > ( TEXT ( " AssetTools " ) ) ;
const TSharedPtr < IAssetTypeActions > AssetTypeActions = AssetToolsModule . Get ( ) . GetAssetTypeActionsForClass ( AssetData . GetClass ( ) ) . Pin ( ) ;
if ( AssetTypeActions . IsValid ( ) )
{
TempAssetColor = AssetTypeActions - > GetTypeColor ( ) ;
}
else
{
TempAssetColor = FColor : : White ;
}
}
else
{
TempAssetName = RetrieveAssetName ( Assets [ 0 ] ) ;
TempAssetPath = RetrieveAssetPath ( Assets [ 0 ] ) ;
2024-06-28 04:07:02 -04:00
TempAssetTypeName = RetrieveAssetTypeName ( Assets [ 0 ] ) ;
2022-09-30 12:21:26 -04:00
for ( int32 i = 1 ; i < Assets . Num ( ) ; + + i )
{
TempAssetName + = TEXT ( " ; " ) + RetrieveAssetName ( Assets [ i ] ) ;
}
TempAssetType = SSourceControlCommon : : GetDefaultMultipleAsset ( ) . ToString ( ) ;
TempAssetColor = FColor : : White ;
}
// Beautify the package name
TempPackageName = TempAssetPath + " . " + TempAssetName ;
}
2024-08-26 04:13:38 -04:00
else if ( bIsPackageExtension & & FPackageName : : TryConvertFilenameToLongPackageName ( Filename , TempPackageName ) )
2022-09-30 12:21:26 -04:00
{
// Fake asset name, asset path from the package name
TempAssetPath = TempPackageName ;
int32 LastSlash = - 1 ;
if ( TempPackageName . FindLastChar ( ' / ' , LastSlash ) )
{
TempAssetName = TempPackageName ;
TempAssetName . RightChopInline ( LastSlash + 1 ) ;
}
}
else
{
TempAssetName = FPaths : : GetCleanFilename ( Filename ) ;
2024-08-26 04:13:38 -04:00
TempPackageName = Filename ; // Put back original package name if the try failed
2022-09-30 12:21:26 -04:00
TempAssetType = FText : : Format ( SSourceControlCommon : : GetDefaultUnknownAssetType ( ) , FText : : FromString ( FPaths : : GetExtension ( Filename ) . ToUpper ( ) ) ) . ToString ( ) ;
2024-06-28 04:07:02 -04:00
TempAssetTypeName = TempAssetType ;
2024-08-26 04:13:38 -04:00
// Attempt to make package name relative to one of the project roots instead of a full absolute path
TArray < FSourceControlProjectInfo > CustomProjects = ISourceControlModule : : Get ( ) . GetCustomProjects ( ) ;
for ( const FSourceControlProjectInfo & ProjectInfo : CustomProjects )
{
FStringView RelativePackageName ;
if ( FPathViews : : TryMakeChildPathRelativeTo ( TempPackageName , ProjectInfo . ProjectDirectory , RelativePackageName ) )
{
TempPackageName = FPaths : : Combine ( TEXT ( " / " ) , FPaths : : GetBaseFilename ( ProjectInfo . ProjectDirectory ) , RelativePackageName ) ;
break ;
}
}
2022-09-30 12:21:26 -04:00
}
// Finally, assign the temp variables to the member variables
2022-10-19 15:31:41 -04:00
OutAssetName = TempAssetName ;
OutAssetPath = TempAssetPath ;
OutAssetType = TempAssetType ;
2024-06-28 04:07:02 -04:00
OutAssetTypeName = TempAssetTypeName ;
2022-09-30 12:21:26 -04:00
OutAssetTypeColor = TempAssetColor ;
OutPackageName = FText : : FromString ( TempPackageName ) ;
}
2021-02-04 17:41:41 -04:00
//////////////////////////////////////////////////////////////////////////
2022-10-19 15:31:41 -04:00
FString IFileViewTreeItem : : DefaultStrValue ; // Default is an empty string.
FDateTime IFileViewTreeItem : : DefaultDateTimeValue ; // Default is FDateTime::MinValue().
void IFileViewTreeItem : : SetLastModifiedDateTime ( const FDateTime & Timestamp )
{
2022-10-27 11:59:24 -04:00
if ( Timestamp ! = LastModifiedDateTime ) // Pay the text conversion only if needed.
2022-10-19 15:31:41 -04:00
{
2022-10-27 11:59:24 -04:00
LastModifiedDateTime = Timestamp ;
if ( Timestamp ! = FDateTime : : MinValue ( ) )
{
LastModifiedTimestampText = FText : : AsDateTime ( Timestamp , EDateTimeStyle : : Short ) ;
}
else
{
LastModifiedTimestampText = FText : : GetEmpty ( ) ;
}
2022-10-19 15:31:41 -04:00
}
}
//////////////////////////////////////////////////////////////////////////
2023-01-31 01:26:50 -05:00
FString FUnsavedAssetsTreeItem : : GetDisplayString ( ) const
{
return " " ;
}
2021-03-24 08:29:57 -04:00
FFileTreeItem : : FFileTreeItem ( FSourceControlStateRef InFileState , bool bBeautifyPaths , bool bIsShelvedFile )
2022-10-19 15:31:41 -04:00
: IFileViewTreeItem ( bIsShelvedFile ? IChangelistTreeItem : : ShelvedFile : IChangelistTreeItem : : File )
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
, FileState ( InFileState )
2021-08-31 15:14:29 -04:00
, MinTimeBetweenUpdate ( FTimespan : : FromSeconds ( 5.f ) )
, LastUpdateTime ( )
, bAssetsUpToDate ( false )
2021-02-04 17:41:41 -04:00
{
CheckBoxState = ECheckBoxState : : Checked ;
// Initialize asset data first
2021-08-31 15:14:29 -04:00
if ( bBeautifyPaths )
2021-02-08 09:36:20 -04:00
{
2021-08-31 15:14:29 -04:00
FSourceControlAssetDataCache & AssetDataCache = ISourceControlModule : : Get ( ) . GetAssetDataCache ( ) ;
bAssetsUpToDate = AssetDataCache . GetAssetDataArray ( FileState , Assets ) ;
}
else
{
// We do not need to wait for AssetData from the cache.
bAssetsUpToDate = true ;
2021-02-08 09:36:20 -04:00
}
2021-08-31 15:14:29 -04:00
RefreshAssetInformation ( ) ;
}
2021-02-04 17:41:41 -04:00
2022-10-19 15:31:41 -04:00
int32 FFileTreeItem : : GetIconSortingPriority ( ) const
{
if ( ! FileState - > IsCurrent ( ) ) { return 0 ; } // First if sorted in ascending order.
if ( FileState - > IsUnknown ( ) ) { return 1 ; }
if ( FileState - > IsConflicted ( ) ) { return 2 ; }
if ( FileState - > IsCheckedOutOther ( ) ) { return 3 ; }
if ( FileState - > IsCheckedOut ( ) ) { return 4 ; }
if ( FileState - > IsDeleted ( ) ) { return 5 ; }
if ( FileState - > IsAdded ( ) ) { return 6 ; }
else { return 7 ; }
}
const FString & FFileTreeItem : : GetCheckedOutBy ( ) const
{
CheckedOutBy . Reset ( ) ;
FileState - > IsCheckedOutOther ( & CheckedOutBy ) ;
return CheckedOutBy ;
}
2022-09-15 18:45:09 -04:00
FText FFileTreeItem : : GetCheckedOutByUser ( ) const
{
2022-10-19 15:31:41 -04:00
return FText : : FromString ( GetCheckedOutBy ( ) ) ;
2022-09-15 18:45:09 -04:00
}
2021-08-31 15:14:29 -04:00
void FFileTreeItem : : RefreshAssetInformation ( )
{
2021-02-04 17:41:41 -04:00
// Initialize display-related members
2022-09-30 12:21:26 -04:00
static TArray < FAssetData > NoAssets ;
2024-06-28 04:07:02 -04:00
RefreshAssetInformationInternal ( Assets . IsValid ( ) ? * Assets : NoAssets , FileState - > GetFilename ( ) , AssetNameStr , AssetPathStr , AssetTypeStr , AssetTypeNameStr , PackageName , AssetTypeColor ) ;
2022-10-19 15:31:41 -04:00
AssetName = FText : : FromString ( AssetNameStr ) ;
AssetPath = FText : : FromString ( AssetPathStr ) ;
AssetType = FText : : FromString ( AssetTypeStr ) ;
2024-06-28 04:07:02 -04:00
AssetTypeName = FText : : FromString ( AssetTypeNameStr ) ;
2021-02-04 17:41:41 -04:00
}
2022-09-12 18:11:36 -04:00
FText FFileTreeItem : : GetAssetName ( ) const
{
return AssetName ;
}
2021-08-31 15:14:29 -04:00
FText FFileTreeItem : : GetAssetName ( )
{
const FTimespan CurrentTime = FTimespan : : FromSeconds ( FPlatformTime : : Seconds ( ) ) ;
if ( ( ! bAssetsUpToDate ) & & ( ( CurrentTime - LastUpdateTime ) > MinTimeBetweenUpdate ) )
{
FSourceControlAssetDataCache & AssetDataCache = ISourceControlModule : : Get ( ) . GetAssetDataCache ( ) ;
LastUpdateTime = CurrentTime ;
if ( AssetDataCache . GetAssetDataArray ( FileState , Assets ) )
{
bAssetsUpToDate = true ;
RefreshAssetInformation ( ) ;
}
}
return AssetName ;
}
2021-06-08 17:12:28 -04:00
//////////////////////////////////////////////////////////////////////////
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
FText FShelvedChangelistTreeItem : : GetDisplayText ( ) const
{
2022-11-01 16:30:00 -04:00
return LOCTEXT ( " SourceControl_ShelvedFiles " , " Shelved Items " ) ;
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
}
//////////////////////////////////////////////////////////////////////////
2021-06-08 17:12:28 -04:00
FOfflineFileTreeItem : : FOfflineFileTreeItem ( const FString & InFilename )
2022-10-19 15:31:41 -04:00
: IFileViewTreeItem ( IChangelistTreeItem : : OfflineFile )
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
, Assets ( )
2022-08-26 11:04:20 -04:00
, Filename ( InFilename )
2021-06-08 17:12:28 -04:00
, PackageName ( FText : : FromString ( InFilename ) )
, AssetName ( SSourceControlCommon : : GetDefaultAssetName ( ) )
, AssetPath ( )
, AssetType ( SSourceControlCommon : : GetDefaultAssetType ( ) )
, AssetTypeColor ( )
{
FString TempString ;
USourceControlHelpers : : GetAssetData ( InFilename , Assets ) ;
2022-09-30 12:21:26 -04:00
RefreshAssetInformation ( ) ;
}
2021-06-08 17:12:28 -04:00
2022-09-30 12:21:26 -04:00
void FOfflineFileTreeItem : : RefreshAssetInformation ( )
{
2024-06-28 04:07:02 -04:00
RefreshAssetInformationInternal ( Assets , Filename , AssetNameStr , AssetPathStr , AssetTypeStr , AssetTypeNameStr , PackageName , AssetTypeColor ) ;
2022-10-19 15:31:41 -04:00
AssetName = FText : : FromString ( AssetNameStr ) ;
AssetPath = FText : : FromString ( AssetPathStr ) ;
AssetType = FText : : FromString ( AssetTypeStr ) ;
2024-06-28 04:07:02 -04:00
AssetTypeName = FText : : FromString ( AssetTypeNameStr ) ;
2021-06-08 17:12:28 -04:00
}
2021-02-04 17:41:41 -04:00
//////////////////////////////////////////////////////////////////////////
namespace SSourceControlCommon
{
TSharedRef < SWidget > GetSCCFileWidget ( FSourceControlStateRef InFileState , bool bIsShelvedFile )
{
2022-05-09 13:12:28 -04:00
const FSlateBrush * IconBrush = FAppStyle : : GetBrush ( " ContentBrowser.ColumnViewAssetIcon " ) ;
2021-02-04 17:41:41 -04:00
// 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 )
. ColorAndOpacity_Lambda ( [ bIsShelvedFile ] ( ) - > FSlateColor {
return FSlateColor ( bIsShelvedFile ? FColor : : Yellow : FColor : : White ) ;
} )
]
// Source control state
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Top )
[
SNew ( SBox )
. WidthOverride ( IconOverlaySize )
. HeightOverride ( IconOverlaySize )
[
SNew ( SLayeredImage , InFileState - > GetIcon ( ) )
2022-09-06 15:43:24 -04:00
. ToolTipText ( InFileState - > GetDisplayTooltip ( ) )
2021-02-04 17:41:41 -04:00
]
] ;
}
2023-08-09 18:41:28 -04:00
TSharedRef < SWidget > GetSCCFileWidget ( )
{
const FSlateBrush * IconBrush = FAppStyle : : 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 )
. ColorAndOpacity ( FSlateColor ( FColor : : White ) )
]
// Source control state
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Top )
[
SNew ( SBox )
. WidthOverride ( IconOverlaySize )
. HeightOverride ( IconOverlaySize )
] ;
}
2021-06-08 17:12:28 -04:00
FText GetDefaultAssetName ( )
{
return LOCTEXT ( " SourceControl_DefaultAssetName " , " Unavailable " ) ;
}
FText GetDefaultAssetType ( )
{
return LOCTEXT ( " SourceControl_DefaultAssetType " , " Unknown " ) ;
}
FText GetDefaultUnknownAssetType ( )
{
return LOCTEXT ( " SourceControl_FileTypeDefault " , " {0} File " ) ;
}
FText GetDefaultMultipleAsset ( )
{
return LOCTEXT ( " SourceCOntrol_ManyAssetType " , " Multiple Assets " ) ;
}
2023-12-12 17:18:07 -05:00
FText GetSingleLineChangelistDescription ( const FText & InFullDescription , ESingleLineFlags Flags )
2022-12-05 13:19:35 -05:00
{
FString DescriptionTextAsString = InFullDescription . ToString ( ) ;
2023-12-12 17:18:07 -05:00
DescriptionTextAsString . TrimStartAndEndInline ( ) ;
2022-12-05 13:19:35 -05:00
2023-12-12 17:18:07 -05:00
if ( ( Flags & ESingleLineFlags : : Mask_NewlineBehavior ) = = ESingleLineFlags : : NewlineConvertToSpace )
2022-12-05 13:19:35 -05:00
{
2023-12-12 17:18:07 -05:00
static constexpr TCHAR Replacer = TCHAR ( ' ' ) ;
// Replace all non-space whitespace characters with space
Algo : : ReplaceIf ( DescriptionTextAsString ,
[ ] ( TCHAR C ) { return FChar : : IsWhitespace ( C ) & & C ! = Replacer ; } ,
Replacer ) ;
2022-12-05 13:19:35 -05:00
}
2023-12-12 17:18:07 -05:00
else
2023-02-01 17:54:20 -05:00
{
2023-12-12 17:18:07 -05:00
int32 NewlineStartIndex = INDEX_NONE ;
DescriptionTextAsString . FindChar ( TCHAR ( ' \n ' ) , NewlineStartIndex ) ;
if ( NewlineStartIndex ! = INDEX_NONE )
{
DescriptionTextAsString . LeftInline ( NewlineStartIndex ) ;
}
// Trim any trailing carriage returns
if ( DescriptionTextAsString . EndsWith ( TEXT ( " \r " ) , ESearchCase : : CaseSensitive ) )
{
DescriptionTextAsString . LeftChopInline ( 1 ) ;
}
2023-02-01 17:54:20 -05:00
}
2022-12-05 13:19:35 -05:00
return InFullDescription . IsCultureInvariant ( ) ? FText : : AsCultureInvariant ( DescriptionTextAsString ) : FText : : FromString ( DescriptionTextAsString ) ;
}
2022-09-07 17:15:39 -04:00
/** Wraps the execution of a changelist operations with a slow task. */
void ExecuteChangelistOperationWithSlowTaskWrapper ( const FText & Message , const TFunction < void ( ) > & ChangelistTask )
{
// NOTE: This is a ugly workaround for P4 because the generic popup feedback operations in FScopedSourceControlProgress() was supressed for all synchrounous
// operations. For other source control providers, the popup still shows up and showing a slow task and the FScopedSourceControlProgress at the same
// time is a bad user experience. Until we fix source control popup situation in general in the Editor, this hack is in place to avoid the double popup.
// At the time of writing, the other source control provider that supports changelists is Plastic.
if ( ISourceControlModule : : Get ( ) . GetProvider ( ) . GetName ( ) = = " Perforce " )
{
FScopedSlowTask Progress ( 0.f , Message ) ;
Progress . MakeDialog ( ) ;
ChangelistTask ( ) ;
}
else
{
ChangelistTask ( ) ;
}
}
/** Wraps the execution of an uncontrolled changelist operations with a slow task. */
void ExecuteUncontrolledChangelistOperationWithSlowTaskWrapper ( const FText & Message , const TFunction < void ( ) > & UncontrolledChangelistTask )
{
ExecuteChangelistOperationWithSlowTaskWrapper ( Message , UncontrolledChangelistTask ) ;
}
/** Displays toast notification to report the status of task. */
void DisplaySourceControlOperationNotification ( const FText & Message , SNotificationItem : : ECompletionState CompletionState )
{
if ( Message . IsEmpty ( ) )
{
return ;
}
2022-11-01 16:30:00 -04:00
FMessageLog ( " SourceControl " ) . Message ( CompletionState = = SNotificationItem : : ECompletionState : : CS_Fail ? EMessageSeverity : : Error : EMessageSeverity : : Info , Message ) ;
2022-09-07 17:15:39 -04:00
FNotificationInfo NotificationInfo ( Message ) ;
NotificationInfo . ExpireDuration = 6.0f ;
NotificationInfo . Hyperlink = FSimpleDelegate : : CreateLambda ( [ ] ( ) { FGlobalTabmanager : : Get ( ) - > TryInvokeTab ( FName ( " OutputLog " ) ) ; } ) ;
NotificationInfo . HyperlinkText = LOCTEXT ( " ShowOutputLogHyperlink " , " Show Output Log " ) ;
FSlateNotificationManager : : Get ( ) . AddNotification ( NotificationInfo ) - > SetCompletionState ( CompletionState ) ;
}
bool OpenConflictDialog ( const TArray < FSourceControlStateRef > & InFilesConflicts )
{
TSharedPtr < SWindow > Window ;
TSharedPtr < SSourceControlFileDialog > SourceControlFileDialog ;
Window = SNew ( SWindow )
. Title ( LOCTEXT ( " CheckoutPackagesDialogTitle " , " Check Out Assets " ) )
. SizingRule ( ESizingRule : : UserSized )
. ClientSize ( FVector2D ( 1024.0f , 512.0f ) )
. SupportsMaximize ( false )
. SupportsMinimize ( false )
[
SNew ( SBorder )
. Padding ( 4.f )
. BorderImage ( FAppStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
[
SAssignNew ( SourceControlFileDialog , SSourceControlFileDialog )
. Message ( LOCTEXT ( " CheckoutPackagesDialogMessage " , " Conflict detected in the following assets: " ) )
2022-11-23 11:57:50 -05:00
. Warning ( LOCTEXT ( " CheckoutPackagesWarnMessage " , " Warning: These assets are locked or not at the head revision. You may lose your changes if you continue, as you will be unable to submit them to revision control. " ) )
2022-09-07 17:15:39 -04:00
. Files ( InFilesConflicts )
]
] ;
SourceControlFileDialog - > SetWindow ( Window ) ;
Window - > SetWidgetToFocusOnActivate ( SourceControlFileDialog ) ;
GEditor - > EditorAddModalWindow ( Window . ToSharedRef ( ) ) ;
return SourceControlFileDialog - > IsProceedButtonPressed ( ) ;
}
2021-02-04 17:41:41 -04:00
} // end of namespace SSourceControlCommon
Refactored the Changelist Window UI to work better with large changelists along with bug fixes.
This submit should not regress any existing functionalites of the previous widget.
Along with the user interface changes, notable bug fixes were included
- If a changelist is not specified for P4 operations 'Mark for Add', 'Mark for Delete and 'Checkout', defaulted to the 'default' P4 changlist. Without a valid changelist, the cache wasn't properly updated.
- Fixed updating the cache for P4 'Mark for delete' operation not correctly updating the file changelist cached in the file state.
Other changes:
- P4 changelists are now always returned sorted by changelist number, ascending.
- Some of the safe operations were running synchronous are not running asynchrnous (create new changelist, delete empty changelist, delete shelved files).
This submit addresses the following Jiras:
#jira UE-155207 - Refactor the changelist window layout to have the left/right panel.
#jira UE-155209 - Add the context menu on right click on a file or a changelist.
#jira UE-155218 - Support creating new empty changelist from the changelist view.
#jira UE-155220 - Support moving files from the selected changelist (right view) to another changelist (left view)
#jira UE-155211 - Add visual feedback for any operation taking more than 0.5s.
#jira UE-155212 - Display a list of uncontrolled files in the left panel of the changelist window
#jira UE-155499 - Changelist windows buttons should be disabled if SCC is disabled
#jira UE-155229 - Add an option to automatically refresh the changelist window when new assets are imported|created (as uncontrolled), marked for add, checked out, marked for delete
#jira UE-107577 - Source Control's Changelists dialog does not refresh to reflect changes made while open
#rb Patrick.Enfedaque
#preflight 62ff946ef7404b55a326297b
[CL 21499885 by patrick laflamme in ue5-main branch]
2022-08-22 21:20:05 -04:00
# undef LOCTEXT_NAMESPACE