2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-08-28 10:03:31 -04:00
# include "MergePrivatePCH.h"
# include "SMergeTreeView.h"
2014-12-17 19:27:27 -05:00
void SMergeTreeView : : Construct ( const FArguments InArgs
, const FBlueprintMergeData & InData
, FOnMergeNodeSelected SelectionCallback
, TArray < TSharedPtr < FBlueprintDifferenceTreeEntry > > & OutTreeEntries
, TArray < TSharedPtr < FBlueprintDifferenceTreeEntry > > & OutRealDifferences
, TArray < TSharedPtr < FBlueprintDifferenceTreeEntry > > & OutConflicts )
2014-08-28 10:03:31 -04:00
{
Data = InData ;
CurrentDifference = - 1 ;
2014-11-04 22:25:35 -05:00
CurrentMergeConflict = - 1 ;
2014-08-28 10:03:31 -04:00
// generate controls:
2014-11-24 18:59:49 -05:00
// EMergeParticipant::Remote
2014-08-28 10:03:31 -04:00
{
SCSViews . Push (
2015-02-20 17:26:02 -05:00
MakeShareable ( new FSCSDiff ( InData . BlueprintRemote ) )
2014-08-28 10:03:31 -04:00
) ;
}
2014-11-24 18:59:49 -05:00
// EMergeParticipant::Base
2014-08-28 10:03:31 -04:00
{
SCSViews . Push (
2015-02-20 17:26:02 -05:00
MakeShareable ( new FSCSDiff ( InData . BlueprintBase ) )
2014-08-28 10:03:31 -04:00
) ;
}
2014-11-24 18:59:49 -05:00
// EMergeParticipant::Local
2014-08-28 10:03:31 -04:00
{
SCSViews . Push (
2015-02-20 17:26:02 -05:00
MakeShareable ( new FSCSDiff ( InData . BlueprintLocal ) )
2014-08-28 10:03:31 -04:00
) ;
}
2015-02-20 17:26:02 -05:00
TArray < FSCSResolvedIdentifier > RemoteHierarchy = GetRemoteView ( ) - > GetDisplayedHierarchy ( ) ;
TArray < FSCSResolvedIdentifier > BaseHierarchy = GetBaseView ( ) - > GetDisplayedHierarchy ( ) ;
TArray < FSCSResolvedIdentifier > LocalHierarchy = GetLocalView ( ) - > GetDisplayedHierarchy ( ) ;
2014-11-04 22:25:35 -05:00
FSCSDiffRoot RemoteDifferingProperties ;
DiffUtils : : CompareUnrelatedSCS ( InData . BlueprintBase , BaseHierarchy , InData . BlueprintRemote , RemoteHierarchy , RemoteDifferingProperties ) ;
FSCSDiffRoot LocalDifferingProperties ;
DiffUtils : : CompareUnrelatedSCS ( InData . BlueprintBase , BaseHierarchy , InData . BlueprintLocal , LocalHierarchy , LocalDifferingProperties ) ;
DifferingProperties = RemoteDifferingProperties ;
DifferingProperties . Entries . Append ( LocalDifferingProperties . Entries ) ;
2014-12-17 19:27:27 -05:00
struct FSCSDiffPair
2014-11-04 22:25:35 -05:00
{
2014-12-17 19:27:27 -05:00
const FSCSDiffEntry * Local ;
const FSCSDiffEntry * Remote ;
} ;
TArray < FSCSDiffPair > ConflictingDifferences ;
2014-11-04 22:25:35 -05:00
/* This predicate sorts the list of differing properties so that those that are 'earlier' in the tree appear first.
For example , if we get the following two trees back :
B added at position ( 3 , 2 , 1 )
C removed at position ( 1 , 2 )
and
D added at position ( 4 , 2 , 1 )
the resulting list will be
2014-12-17 19:27:27 -05:00
[ C , B , D ] : */
2014-11-04 22:25:35 -05:00
const auto SortTreePredicate = [ ] ( const FSCSDiffEntry & A , const FSCSDiffEntry & B )
{
int32 Idx = 0 ;
const TArray < int32 > & ATreeAddress = A . TreeIdentifier . TreeLocation ;
const TArray < int32 > & BTreeAddress = B . TreeIdentifier . TreeLocation ;
while ( true )
{
if ( ! ATreeAddress . IsValidIndex ( Idx ) )
{
// A has a shorter address, show it first:
return true ;
}
else if ( ! BTreeAddress . IsValidIndex ( Idx ) )
{
// B has a shorter address, show it first:
return false ;
}
else if ( ATreeAddress [ Idx ] < BTreeAddress [ Idx ] )
{
// A has a lower index, show it first:
return true ;
}
else if ( ATreeAddress [ Idx ] > BTreeAddress [ Idx ] )
{
// B has a lower index, show it first:
return false ;
}
else
{
// tie, go to the next level of the tree:
+ + Idx ;
}
}
// fall back, just let diff type win:
return A . DiffType < B . DiffType ;
} ;
2014-12-17 19:27:27 -05:00
RemoteDifferingProperties . Entries . Sort ( SortTreePredicate ) ;
LocalDifferingProperties . Entries . Sort ( SortTreePredicate ) ;
const FText RemoteLabel = NSLOCTEXT ( " SMergeTreeView " , " RemoteLabel " , " Remote " ) ;
const FText LocalLabel = NSLOCTEXT ( " SMergeTreeView " , " LocalLabel " , " Local " ) ;
struct FSCSMergeEntry
{
FText Label ;
FSCSIdentifier Identifier ;
FPropertySoftPath PropertyIdentifier ;
bool bConflicted ;
} ;
TArray < FSCSMergeEntry > Entries ;
bool bAnyConflict = false ;
int RemoteIter = 0 ;
int LocalIter = 0 ;
while ( RemoteIter ! = RemoteDifferingProperties . Entries . Num ( ) | |
LocalIter ! = LocalDifferingProperties . Entries . Num ( ) )
{
if ( RemoteIter ! = RemoteDifferingProperties . Entries . Num ( ) & &
LocalIter ! = LocalDifferingProperties . Entries . Num ( ) )
{
// check for conflicts:
const FSCSDiffEntry & Remote = RemoteDifferingProperties . Entries [ RemoteIter ] ;
const FSCSDiffEntry & Local = LocalDifferingProperties . Entries [ LocalIter ] ;
if ( Remote . TreeIdentifier = = Local . TreeIdentifier )
{
bool bConflicting = true ;
if ( Remote . DiffType = = ETreeDiffType : : NODE_PROPERTY_CHANGED & &
Local . DiffType = = ETreeDiffType : : NODE_PROPERTY_CHANGED )
{
// conflict only if property changed is the same:
bConflicting = Remote . PropertyDiff . Identifier = = Local . PropertyDiff . Identifier ;
}
if ( bConflicting )
{
bAnyConflict = true ;
2015-01-05 22:59:34 -05:00
FSCSMergeEntry Entry =
{
FText : : Format ( NSLOCTEXT ( " SMergeTreeView " , " ConflictIdentifier " , " CONFLICT: {0} conflicts with {1} " ) , DiffViewUtils : : SCSDiffMessage ( Remote , RemoteLabel ) , DiffViewUtils : : SCSDiffMessage ( Local , LocalLabel ) ) ,
Remote . TreeIdentifier ,
Remote . DiffType = = ETreeDiffType : : NODE_PROPERTY_CHANGED ? Remote . PropertyDiff . Identifier : Local . PropertyDiff . Identifier ,
true
} ;
2014-12-17 19:27:27 -05:00
// create a tree entry that describes both the local and remote change..
2015-01-05 22:59:34 -05:00
Entries . Push ( Entry ) ;
2014-12-17 19:27:27 -05:00
+ + RemoteIter ;
+ + LocalIter ;
continue ;
}
}
}
// no possibility of conflict, advance the entry that has a 'lower' tree identifier, keeping in mind that tree identifier
// may be equal, and that in that case we need to use the property identifier as a tiebreaker:
const FSCSDiffEntry * Remote = RemoteIter ! = RemoteDifferingProperties . Entries . Num ( ) ? & RemoteDifferingProperties . Entries [ RemoteIter ] : nullptr ;
const FSCSDiffEntry * Local = LocalIter ! = LocalDifferingProperties . Entries . Num ( ) ? & LocalDifferingProperties . Entries [ LocalIter ] : nullptr ;
if ( Local & & ( ! Remote | | SortTreePredicate ( * Local , * Remote ) ) )
{
2015-01-05 22:59:34 -05:00
FSCSMergeEntry Entry =
{
DiffViewUtils : : SCSDiffMessage ( * Local , LocalLabel ) ,
Local - > TreeIdentifier ,
Local - > PropertyDiff . Identifier ,
false
} ;
Entries . Push ( Entry ) ;
2014-12-17 19:27:27 -05:00
+ + LocalIter ;
}
else
{
2015-01-05 22:59:34 -05:00
FSCSMergeEntry Entry =
{
DiffViewUtils : : SCSDiffMessage ( * Remote , RemoteLabel ) ,
Remote - > TreeIdentifier ,
Remote - > PropertyDiff . Identifier ,
false
} ;
Entries . Push ( Entry ) ;
2014-12-17 19:27:27 -05:00
+ + RemoteIter ;
}
}
const auto CreateSCSMergeWidget = [ ] ( FSCSMergeEntry Entry ) - > TSharedRef < SWidget >
{
return SNew ( STextBlock )
. Text ( Entry . Label )
. ColorAndOpacity ( Entry . bConflicted ? DiffViewUtils : : Conflicting ( ) : DiffViewUtils : : Differs ( ) ) ;
} ;
2015-03-03 12:30:55 -05:00
const auto FocusSCSDifferenceEntry = [ ] ( FSCSMergeEntry Entry , SMergeTreeView * Parent , FOnMergeNodeSelected InSelectionCallback )
2014-12-17 19:27:27 -05:00
{
2015-03-03 12:30:55 -05:00
InSelectionCallback . ExecuteIfBound ( ) ;
2014-12-17 19:27:27 -05:00
Parent - > HighlightDifference ( Entry . Identifier , Entry . PropertyIdentifier ) ;
} ;
TArray < TSharedPtr < FBlueprintDifferenceTreeEntry > > Children ;
for ( const auto & Difference : Entries )
{
auto Entry = TSharedPtr < FBlueprintDifferenceTreeEntry > (
new FBlueprintDifferenceTreeEntry (
FOnDiffEntryFocused : : CreateStatic ( FocusSCSDifferenceEntry , Difference , this , SelectionCallback )
, FGenerateDiffEntryWidget : : CreateStatic ( CreateSCSMergeWidget , Difference )
, TArray < TSharedPtr < FBlueprintDifferenceTreeEntry > > ( )
)
) ;
Children . Push ( Entry ) ;
OutRealDifferences . Push ( Entry ) ;
if ( Difference . bConflicted )
{
OutConflicts . Push ( Entry ) ;
}
}
2014-11-04 22:25:35 -05:00
DifferingProperties . Entries . Sort ( SortTreePredicate ) ;
2015-03-03 12:30:55 -05:00
const auto ForwardSelection = [ ] ( FOnMergeNodeSelected InSelectionCallback )
2014-12-17 19:27:27 -05:00
{
// This allows the owning control to focus the correct tab (or do whatever else it likes):
2015-03-03 12:30:55 -05:00
InSelectionCallback . ExecuteIfBound ( ) ;
2014-12-17 19:27:27 -05:00
} ;
const bool bHasDiffferences = Children . Num ( ) ! = 0 ;
if ( ! bHasDiffferences )
{
Children . Push ( FBlueprintDifferenceTreeEntry : : NoDifferencesEntry ( ) ) ;
}
TSharedPtr < FBlueprintDifferenceTreeEntry > Category = FBlueprintDifferenceTreeEntry : : CreateComponentsCategoryEntryForMerge (
FOnDiffEntryFocused : : CreateStatic ( ForwardSelection , SelectionCallback )
, Children
, RemoteDifferingProperties . Entries . Num ( ) ! = 0
, LocalDifferingProperties . Entries . Num ( ) ! = 0
, bAnyConflict ) ;
OutTreeEntries . Push ( Category ) ;
2014-08-28 10:03:31 -04:00
ChildSlot [
SNew ( SSplitter )
+ SSplitter : : Slot ( )
[
2015-02-20 17:26:02 -05:00
GetRemoteView ( ) - > TreeWidget ( )
2014-08-28 10:03:31 -04:00
]
+ SSplitter : : Slot ( )
[
2015-02-20 17:26:02 -05:00
GetBaseView ( ) - > TreeWidget ( )
2014-08-28 10:03:31 -04:00
]
+ SSplitter : : Slot ( )
[
2015-02-20 17:26:02 -05:00
GetLocalView ( ) - > TreeWidget ( )
2014-08-28 10:03:31 -04:00
]
] ;
}
2014-12-17 19:27:27 -05:00
void SMergeTreeView : : HighlightDifference ( FSCSIdentifier TreeIdentifier , FPropertySoftPath Property )
2014-08-28 10:03:31 -04:00
{
2014-11-04 22:25:35 -05:00
for ( auto & View : SCSViews )
{
2015-02-20 17:26:02 -05:00
View - > HighlightProperty ( TreeIdentifier . Name , Property ) ;
2014-08-28 10:03:31 -04:00
}
}
2015-02-20 17:26:02 -05:00
TSharedRef < FSCSDiff > & SMergeTreeView : : GetRemoteView ( )
2014-08-28 10:03:31 -04:00
{
2014-11-24 18:59:49 -05:00
return SCSViews [ EMergeParticipant : : Remote ] ;
2014-08-28 10:03:31 -04:00
}
2015-02-20 17:26:02 -05:00
TSharedRef < FSCSDiff > & SMergeTreeView : : GetBaseView ( )
2014-08-28 10:03:31 -04:00
{
2014-11-24 18:59:49 -05:00
return SCSViews [ EMergeParticipant : : Base ] ;
2014-08-28 10:03:31 -04:00
}
2015-02-20 17:26:02 -05:00
TSharedRef < FSCSDiff > & SMergeTreeView : : GetLocalView ( )
2014-08-28 10:03:31 -04:00
{
2014-11-24 18:59:49 -05:00
return SCSViews [ EMergeParticipant : : Local ] ;
2014-08-28 10:03:31 -04:00
}