2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "UnrealEd.h"
# include "ConsolidateWindow.h"
# include "AssetSelection.h"
# include "ObjectTools.h"
# include "MainFrame.h"
# include "ISourceControlModule.h"
# include "AssetRegistryModule.h"
# define LOCTEXT_NAMESPACE "SConsolidateWindow"
/**
* The Consolidate Tool Widget Class
*/
class SConsolidateToolWidget : public SBorder
{
public :
SLATE_BEGIN_ARGS ( SConsolidateToolWidget )
: _ParentWindow ( )
{ }
SLATE_ATTRIBUTE ( TSharedPtr < SWindow > , ParentWindow )
SLATE_END_ARGS ( )
void Construct ( const FArguments & InArgs ) ;
SConsolidateToolWidget ( )
{
}
/**
* Class to support our list box
*/
class FListItem
{
public :
/**
* Constructor
* @ param InParent Parent Widget that holds the ListBox
* @ param InObject the UObject this list item represents in the ListBox
*/
FListItem ( SConsolidateToolWidget * InParent , UObject * InObject )
{
Parent = InParent ;
Object = InObject ;
} ;
/**
* Callback function used to tell the ListBox parent what item has been selected
*/
2014-12-10 14:24:09 -05:00
void OnAssetSelected ( ECheckBoxState NewCheckedState )
2014-03-14 14:13:41 -04:00
{
check ( Parent ! = NULL ) ;
Parent - > SetSelectedListItem ( this ) ;
} ;
/**
* Callback function used to ensure only one item is highlighted ( selected ) at a time
*/
2014-12-10 14:24:09 -05:00
ECheckBoxState IsAssetSelected ( ) const
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
return ( Parent - > GetSelectedListItem ( ) = = this ) ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-03-14 14:13:41 -04:00
}
/** @return The full name of the object this item represents */
FString GetObjectName ( ) const
{
return Object - > GetFullName ( ) ;
}
/** @return The UObject this item represents */
const UObject * GetObject ( ) const
{
return Object ;
}
private :
/** Parent Widget that holds the ListBox */
SConsolidateToolWidget * Parent ;
/** The UObject this item represents */
UObject * Object ;
} ;
/** @return Selected Item in the listbox */
FListItem * GetSelectedListItem ( )
{
return SelectedListItem ;
}
/**
* Used by the listbox to tell its parent what item is selected .
*
* @ param List item from the listbox to select
*/
void SetSelectedListItem ( FListItem * ListItem )
{
SelectedListItem = ListItem ;
}
/**
* Used by the listbox to tell its parent what item is selected .
*
* @ param Item from the listbox to select
*/
void SetSelectedItem ( UObject * Item )
{
for ( TSharedPtr < FListItem > & ListItem : ListViewItems )
{
if ( ListItem - > GetObject ( ) = = Item )
{
SetSelectedListItem ( ListItem . Get ( ) ) ;
break ;
}
}
}
/** @return Return the index of the ConsolidationoOjects array of the actively selected ListItem */
int32 GetSelectedListItemIndex ( ) ;
/**
* Attempt to add the provided objects to the consolidation panel ; Only adds objects which are compatible with objects already existing within the panel , if any
*
* @ param InObjects Objects to attempt to add to the panel
*
* @ return The number of objects successfully added to the consolidation panel
*/
int32 AddConsolidationObjects ( const TArray < UObject * > & InObjects ) ;
/**
* Fills the provided array with all of the UObjects referenced by the consolidation panel , for the purpose of serialization
*
* @ param [ out ] OutSerializableObjects Array to fill with all of the UObjects referenced by the consolidation panel
*/
void QuerySerializableObjects ( TArray < UObject * > & OutSerializableObjects ) ;
/**
* Determine the compatibility of the passed in objects with the objects already present in the consolidation panel
*
* @ param InProposedObjects Objects to check compatibility with vs . the objects already present in the consolidation panel
* @ param OutCompatibleObjects [ out ] Objects from the passed in array which are compatible with those already present in the
* consolidation panel , if any
*
* @ return true if all of the passed in objects are compatible , false otherwise
*/
bool DetermineAssetCompatibility ( const TArray < UObject * > & InProposedObjects , TArray < UObject * > & OutCompatibleObjects ) ;
/** Removes all consolidation objects from the consolidation panel */
void ClearConsolidationObjects ( ) ;
private :
/**
* Verifies if all of the consolidation objects in the panel are of the same class or not
*
* @ return true if all of the classes of the consolidation objects are the same ; false otherwise
*/
bool AreObjClassesHomogeneous ( ) ;
/** Delete all of the dropped asset data for drag-drop support */
void ClearDroppedAssets ( ) ;
/** Reset the consolidate panel's error panel to its default state */
void ResetErrorPanel ( ) ;
/** Remove the currently selected object from the consolidation panel */
void RemoveSelectedObject ( ) ;
/**
* Display a message in the consolidation panel ' s " error " panel ; Naive implementation , wipes out any pre - existing message
*
* @ param bError If true , change the error panel ' s styling to indicate the severity of the message ; if false , use a lighter style
* @ param ErrorMessage Message to display in the " error " panel
*
* @ note The current implementation is naive and will wipe out any pre - existing message when called . The current needs of the window don ' t require
* anything more sophisticated , but in the future perhaps the messages should be appended , multiple panel types should exist , etc .
*/
2014-04-23 18:06:41 -04:00
void DisplayMessage ( bool bError , const FText & ErrorMessage ) ;
2014-03-14 14:13:41 -04:00
// Button Responses
/** Called in response to the user clicking the "X" button on the error panel; dismisses the error panel */
FReply OnDismissErrorPanelButtonClicked ( ) ;
/** Called in response to the user clicking the "Consolidate Objects"/OK button; performs asset consolidation */
FReply OnConsolidateButtonClicked ( ) ;
/** Called in response to the user clicking the cancel button; dismisses the panel w/o consolidating objects */
FReply OnCancelButtonClicked ( ) ;
// Drag-drop Support
/** Called in response to the user beginning to drag something over the consolidation panel; parses the drop data into dropped assets, if possible */
2014-06-13 06:14:46 -04:00
void OnDragEnter ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
/** Called in response to the user's drag operation exiting the consolidation panel; deletes any dropped asset data */
2014-06-13 06:14:46 -04:00
void OnDragLeave ( const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
/** Called in response to the user performing a drop operation in the consolidation panel; adds the dropped objects to the panel */
2014-06-13 06:14:46 -04:00
FReply OnDrop ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
/** Called while the user is dragging something over the consolidation panel; provides visual feedback on whether a drop is allowed or not */
2014-06-13 06:14:46 -04:00
FReply OnDragOver ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
// Input Responses
/** Called in response to the user releasing a keyboard key while the consolidation panel has keyboard focus */
2014-10-30 12:29:36 -04:00
FReply OnKeyUp ( const FGeometry & MyGeometry , const FKeyEvent & InKeyEvent ) override ;
2014-03-14 14:13:41 -04:00
/** Track if the panel has already warned the user about consolidating assets with different types, so as not to repeatedly (and annoyingly) warn */
bool bAlreadyWarnedAboutTypes ;
/** if checked, signifies that after a consolidation operation, an attempt will be made to save the packages dirtied by the operation */
bool bSavePackagesChecked ;
/** List of strings to appear in the list box */
//using AssetInfo array instead
TArray < FString > ConsolidationObjectNames ;
/** Array of consolidation objects */
TArray < UObject * > ConsolidationObjects ;
/** Array of dropped asset data for supporting drag-and-drop */
TArray < FAssetData > DroppedAssets ;
private :
/** A Pointer to our Parent Window */
TWeakPtr < SWindow > ParentWindowPtr ;
typedef SListView < TSharedPtr < FListItem > > SListType ;
/** ListBox for selecting which object to consolidate */
TSharedPtr < SListType > ListView ;
/** Collection of objects (Widgets) to display in the List View. */
TArray < TSharedPtr < FListItem > > ListViewItems ;
/** List Box Item currently selected */
FListItem * SelectedListItem ;
/** Error Text display for error/warning messages */
TSharedPtr < SErrorText > ErrorPanel ;
/** Callback to generate ListBoxRows */
TSharedRef < ITableRow > OnGenerateRowForList ( TSharedPtr < FListItem > ListItemPtr , const TSharedRef < STableViewBase > & OwnerTable ) ;
/** Callback for enabling/disabling the Cosolidate Button */
bool IsConsolidateButtonEnabled ( ) const ;
/** @return true if the user has elected to "Save Dirty Packages" */
2014-12-10 14:24:09 -05:00
ECheckBoxState IsSavePackagesChecked ( ) const ;
2014-03-14 14:13:41 -04:00
/** Callback called when the user checks/unchecks the "Save Dirty Packages" button */
2014-12-10 14:24:09 -05:00
void OnSavePackagesCheckStateChanged ( ECheckBoxState NewCheckedState ) ;
2014-03-14 14:13:41 -04:00
/** Callback Called to determin the error message visibility */
EVisibility IsErrorPanelVisible ( ) const ;
/** Refreshes the List Box and window */
void RefreshListItems ( ) ;
} ;
// Window/Interface Function...
TWeakPtr < SConsolidateToolWidget > FConsolidateToolWindow : : WidgetInstance ;
void FConsolidateToolWindow : : AddConsolidationObjects ( const TArray < UObject * > & InObjects , UObject * SelectedItem )
{
if ( WidgetInstance . IsValid ( ) )
{
//Use the existing widget
WidgetInstance . Pin ( ) - > AddConsolidationObjects ( InObjects ) ;
}
else
{
//Create a new window
TSharedRef < SWindow > NewWindow = SNew ( SWindow )
. Title ( LOCTEXT ( " Consolidate_Title " , " Replace References " ) )
. ClientSize ( FVector2D ( 768 , 300 ) )
. SupportsMinimize ( false )
. SupportsMaximize ( false ) ;
TSharedRef < SConsolidateToolWidget > NewWidget =
SNew ( SConsolidateToolWidget )
. ParentWindow ( NewWindow ) ;
NewWidget - > AddConsolidationObjects ( InObjects ) ;
if ( SelectedItem )
{
NewWidget - > SetSelectedItem ( SelectedItem ) ;
}
NewWindow - > SetContent ( NewWidget ) ;
IMainFrameModule & MainFrameModule = FModuleManager : : LoadModuleChecked < IMainFrameModule > ( TEXT ( " MainFrame " ) ) ;
if ( MainFrameModule . GetParentWindow ( ) . IsValid ( ) )
{
FSlateApplication : : Get ( ) . AddWindowAsNativeChild ( NewWindow , MainFrameModule . GetParentWindow ( ) . ToSharedRef ( ) ) ;
}
else
{
FSlateApplication : : Get ( ) . AddWindow ( NewWindow ) ;
}
WidgetInstance = NewWidget ;
}
}
bool FConsolidateToolWindow : : DetermineAssetCompatibility ( const TArray < UObject * > & InProposedObjects , TArray < UObject * > & OutCompatibleObjects )
{
if ( WidgetInstance . IsValid ( ) )
{
//Compare with the existing widget
return WidgetInstance . Pin ( ) - > DetermineAssetCompatibility ( InProposedObjects , OutCompatibleObjects ) ;
}
else
{
//create a temp widget to compare assets with
TSharedRef < SConsolidateToolWidget > TempWidget =
SNew ( SConsolidateToolWidget )
. ParentWindow ( TSharedPtr < SWindow > ( ) ) ;
return TempWidget - > DetermineAssetCompatibility ( InProposedObjects , OutCompatibleObjects ) ;
}
return false ;
}
// Widget Function definitions...
void SConsolidateToolWidget : : Construct ( const FArguments & InArgs )
{
ParentWindowPtr = InArgs . _ParentWindow . Get ( ) ;
SelectedListItem = NULL ;
bSavePackagesChecked = ISourceControlModule : : Get ( ) . IsEnabled ( ) ;
this - > BorderImage = FEditorStyle : : GetBrush ( " NoBorder " ) ;
ChildSlot
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 5 )
[
SNew ( STextBlock )
. AutoWrapText ( true )
2014-04-23 18:06:41 -04:00
. Text ( LOCTEXT ( " Consolidate_Select " , " Select an asset to serve as the asset to consolidate the non-selected assets to. This will replace all uses of the non-selected assets below with the selected asset. " ) )
2014-03-14 14:13:41 -04:00
]
+ SVerticalBox : : Slot ( )
. FillHeight ( 1.f )
. Padding ( 5 )
[
SNew ( SBorder )
. Padding ( 5 )
[
SAssignNew ( ListView , SListType )
. ItemHeight ( 24 )
. ListItemsSource ( & ListViewItems )
. OnGenerateRow ( this , & SConsolidateToolWidget : : OnGenerateRowForList )
]
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 5 )
[
SNew ( SHorizontalBox )
. Visibility ( this , & SConsolidateToolWidget : : IsErrorPanelVisible )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Fill )
[
SAssignNew ( ErrorPanel , SErrorText )
. Visibility ( EVisibility : : Hidden )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Right )
[
SNew ( SButton )
. ButtonStyle ( FEditorStyle : : Get ( ) , " Window.Buttons.Close " )
. OnClicked ( this , & SConsolidateToolWidget : : OnDismissErrorPanelButtonClicked )
]
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. HAlign ( HAlign_Fill )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 5 )
. HAlign ( HAlign_Left )
[
SNew ( SCheckBox )
. IsChecked ( this , & SConsolidateToolWidget : : IsSavePackagesChecked )
. OnCheckStateChanged ( this , & SConsolidateToolWidget : : OnSavePackagesCheckStateChanged )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " Consolidate_SaveDirtyAssets " , " Save dirtied assets " ) )
]
]
+ SHorizontalBox : : Slot ( )
. Padding ( 5 )
. HAlign ( HAlign_Right )
. FillWidth ( 1 )
[
SNew ( SButton )
. Text ( LOCTEXT ( " ConsolidateAssetsButton " , " Consolidate Assets " ) )
. IsEnabled ( this , & SConsolidateToolWidget : : IsConsolidateButtonEnabled )
. OnClicked ( this , & SConsolidateToolWidget : : OnConsolidateButtonClicked )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 5 )
. HAlign ( HAlign_Right )
[
SNew ( SButton )
. Text ( LOCTEXT ( " CancelConsolidateButton " , " Cancel " ) )
. OnClicked ( this , & SConsolidateToolWidget : : OnCancelButtonClicked )
]
]
] ;
}
TSharedRef < ITableRow > SConsolidateToolWidget : : OnGenerateRowForList ( TSharedPtr < FListItem > ListItemPtr , const TSharedRef < STableViewBase > & OwnerTable )
{
return
SNew ( STableRow < TSharedPtr < FName > > , OwnerTable )
[
SNew ( SCheckBox )
. Style ( FEditorStyle : : Get ( ) , " Menu.RadioButton " )
. IsChecked ( ListItemPtr . ToSharedRef ( ) , & FListItem : : IsAssetSelected )
. OnCheckStateChanged ( ListItemPtr . ToSharedRef ( ) , & FListItem : : OnAssetSelected )
[
SNew ( STextBlock )
2015-01-07 09:52:40 -05:00
. Text ( FText : : FromString ( ListItemPtr - > GetObjectName ( ) ) )
2014-03-14 14:13:41 -04:00
]
] ;
}
bool SConsolidateToolWidget : : IsConsolidateButtonEnabled ( ) const
{
return ( ConsolidationObjects . Num ( ) > 1 & & SelectedListItem ! = NULL ) ;
}
2014-12-10 14:24:09 -05:00
ECheckBoxState SConsolidateToolWidget : : IsSavePackagesChecked ( ) const
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
return bSavePackagesChecked ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 14:24:09 -05:00
void SConsolidateToolWidget : : OnSavePackagesCheckStateChanged ( ECheckBoxState NewCheckedState )
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
bSavePackagesChecked = ( NewCheckedState = = ECheckBoxState : : Checked ) ;
2014-03-14 14:13:41 -04:00
}
EVisibility SConsolidateToolWidget : : IsErrorPanelVisible ( ) const
{
if ( ErrorPanel . IsValid ( ) )
{
return ErrorPanel - > GetVisibility ( ) ;
}
return EVisibility : : Hidden ;
}
void SConsolidateToolWidget : : RefreshListItems ( )
{
ListViewItems . Empty ( ) ;
for ( TArray < UObject * > : : TConstIterator ObjIter ( ConsolidationObjects ) ; ObjIter ; + + ObjIter )
{
ListViewItems . Add ( MakeShareable ( new FListItem ( this , * ObjIter ) ) ) ;
}
ListView - > RequestListRefresh ( ) ;
SelectedListItem = NULL ;
}
int32 SConsolidateToolWidget : : GetSelectedListItemIndex ( )
{
if ( SelectedListItem )
{
for ( int32 Index = 0 ; Index < ConsolidationObjects . Num ( ) ; Index + + )
{
if ( SelectedListItem - > GetObject ( ) = = ConsolidationObjects [ Index ] )
{
return Index ;
}
}
}
return INDEX_NONE ;
}
/**
* Attempt to add the provided objects to the consolidation panel ; Only adds objects which are compatible with objects already existing within the panel , if any
*
* @ param InObjects Objects to attempt to add to the panel
*
* @ return The number of objects successfully added to the consolidation panel
*/
int32 SConsolidateToolWidget : : AddConsolidationObjects ( const TArray < UObject * > & InObjects )
{
// First check the passed in objects for compatibility; allowing cross-type consolidation would result in disaster
TArray < UObject * > CompatibleObjects ;
DetermineAssetCompatibility ( InObjects , CompatibleObjects ) ;
// Iterate over each compatible object, adding it to the panel if it's not already there
for ( TArray < UObject * > : : TConstIterator CompatibleObjIter ( CompatibleObjects ) ; CompatibleObjIter ; + + CompatibleObjIter )
{
UObject * CurObj = * CompatibleObjIter ;
check ( CurObj ) ;
// Don't allow an object to be added to the panel twice
if ( ! ConsolidationObjects . Contains ( CurObj ) )
{
ConsolidationObjectNames . Add ( CurObj - > GetFullName ( ) ) ;
ConsolidationObjects . Add ( CurObj ) ;
}
}
// Refresh the list box, as new items have been added
RefreshListItems ( ) ;
// Check if all of the consolidation objects share the same type. If they don't, and the user hasn't been prompted about it before,
// display a warning message informing them of the potential danger.
if ( ! AreObjClassesHomogeneous ( ) & & ! bAlreadyWarnedAboutTypes )
{
2014-04-23 18:06:41 -04:00
DisplayMessage ( false , LOCTEXT ( " Consolidate_WarningSameClass " , " The object to consolidate are not the same class " ) ) ;
2014-03-14 14:13:41 -04:00
bAlreadyWarnedAboutTypes = true ;
}
return CompatibleObjects . Num ( ) ;
}
/**
* Determine the compatibility of the passed in objects with the objects already present in the consolidation panel
*
* @ param InProposedObjects Objects to check compatibility with vs . the objects already present in the consolidation panel
* @ param OutCompatibleObjects [ out ] Objects from the passed in array which are compatible with those already present in the
* consolidation panel , if any
*
* @ return true if all of the passed in objects are compatible , false otherwise
*/
bool SConsolidateToolWidget : : DetermineAssetCompatibility ( const TArray < UObject * > & InProposedObjects , TArray < UObject * > & OutCompatibleObjects )
{
bool bAllAssetsValid = true ;
OutCompatibleObjects . Empty ( ) ;
if ( InProposedObjects . Num ( ) > 0 )
{
// If the consolidation panel is currently empty, use the first member of the proposed objects as the object whose class should be checked against.
// Otherwise, use the first consolidation object.
const UObject * ComparisonObject = ConsolidationObjects . Num ( ) > 0 ? ConsolidationObjects [ 0 ] : InProposedObjects [ 0 ] ;
check ( ComparisonObject ) ;
const UClass * ComparisonClass = ComparisonObject - > GetClass ( ) ;
check ( ComparisonClass ) ;
// Iterate over each proposed consolidation object, checking if each shares a common class with the consolidation objects, or at least, a common base that
// is allowed as an exception (currently only exceptions made for textures and materials).
for ( TArray < UObject * > : : TConstIterator ProposedObjIter ( InProposedObjects ) ; ProposedObjIter ; + + ProposedObjIter )
{
UObject * CurProposedObj = * ProposedObjIter ;
check ( CurProposedObj ) ;
// You may not consolidate object redirectors
if ( CurProposedObj - > GetClass ( ) - > IsChildOf ( UObjectRedirector : : StaticClass ( ) ) )
{
bAllAssetsValid = false ;
continue ;
}
if ( CurProposedObj - > GetClass ( ) ! = ComparisonClass )
{
const UClass * NearestCommonBase = CurProposedObj - > FindNearestCommonBaseClass ( ComparisonClass ) ;
// If the proposed object doesn't share a common class or a common base that is allowed as an exception, it is not a compatible object
if ( ! ( NearestCommonBase - > IsChildOf ( UTexture : : StaticClass ( ) ) ) & & ! ( NearestCommonBase - > IsChildOf ( UMaterialInterface : : StaticClass ( ) ) ) )
{
bAllAssetsValid = false ;
continue ;
}
}
// If the proposed object is already in the panel, it is not a compatible object
if ( ConsolidationObjects . Contains ( CurProposedObj ) )
{
bAllAssetsValid = false ;
continue ;
}
// If execution has gotten this far, the current proposed object is compatible
OutCompatibleObjects . Add ( CurProposedObj ) ;
}
}
return bAllAssetsValid ;
}
/**
* Fills the provided array with all of the UObjects referenced by the consolidation panel , for the purpose of serialization
*
* @ param [ out ] OutSerializableObjects Array to fill with all of the UObjects referenced by the consolidation panel
*/
void SConsolidateToolWidget : : QuerySerializableObjects ( TArray < UObject * > & OutSerializableObjects )
{
OutSerializableObjects . Empty ( ConsolidationObjects . Num ( ) ) ;
// Add all of the consolidation objects to the array
OutSerializableObjects . Append ( ConsolidationObjects ) ;
// Add each drop data info object to the array
for ( TArray < FAssetData > : : TConstIterator DroppedAssetsIter ( DroppedAssets ) ; DroppedAssetsIter ; + + DroppedAssetsIter )
{
const FAssetData & AssetData = * DroppedAssetsIter ;
UObject * Object = AssetData . GetAsset ( ) ;
if ( Object ! = NULL )
{
OutSerializableObjects . AddUnique ( Object ) ;
}
}
}
/** Removes all consolidation objects from the consolidation panel */
void SConsolidateToolWidget : : ClearConsolidationObjects ( )
{
ConsolidationObjectNames . Empty ( ) ;
ConsolidationObjects . Empty ( ) ;
RefreshListItems ( ) ;
}
/**
* Verifies if all of the consolidation objects in the panel are of the same class or not
*
* @ return true if all of the classes of the consolidation objects are the same ; false otherwise
*/
bool SConsolidateToolWidget : : AreObjClassesHomogeneous ( )
{
bool bAllClassesSame = true ;
if ( ConsolidationObjects . Num ( ) > 1 )
{
TArray < UObject * > : : TConstIterator ConsolidationObjIter ( ConsolidationObjects ) ;
const UObject * FirstObj = * ConsolidationObjIter ;
check ( FirstObj ) ;
// Store the class of the first consolidation object for comparison purposes
const UClass * FirstObjClass = FirstObj - > GetClass ( ) ;
check ( FirstObjClass ) ;
// Starting from the second consolidation object, iterate through all consolidation objects
// to see if they all share a common class
+ + ConsolidationObjIter ;
2014-05-29 17:09:44 -04:00
for ( ; ConsolidationObjIter ; + + ConsolidationObjIter )
2014-03-14 14:13:41 -04:00
{
const UObject * CurObj = * ConsolidationObjIter ;
check ( CurObj ) ;
const UClass * CurObjClass = CurObj - > GetClass ( ) ;
check ( CurObjClass ) ;
if ( CurObjClass ! = FirstObjClass )
{
bAllClassesSame = false ;
break ;
}
}
}
return bAllClassesSame ;
}
/** Delete all of the dropped asset data for drag-drop support */
void SConsolidateToolWidget : : ClearDroppedAssets ( )
{
DroppedAssets . Empty ( ) ;
}
/** Reset the consolidate panel's error panel to its default state */
void SConsolidateToolWidget : : ResetErrorPanel ( )
{
bAlreadyWarnedAboutTypes = false ;
ErrorPanel - > SetVisibility ( EVisibility : : Hidden ) ;
ErrorPanel - > SetError ( FText : : GetEmpty ( ) ) ;
}
/** Remove the currently selected object from the consolidation panel */
void SConsolidateToolWidget : : RemoveSelectedObject ( )
{
const int32 SelectedIndex = GetSelectedListItemIndex ( ) ;
// Ensure there's currently a valid selection
if ( ConsolidationObjects . IsValidIndex ( SelectedIndex ) )
{
// If the selection was valid, remove the consolidation object from the panel
ConsolidationObjects . RemoveAt ( SelectedIndex ) ;
ConsolidationObjectNames . RemoveAt ( SelectedIndex ) ;
// Refresh the list box to display the change in contents
RefreshListItems ( ) ;
// If prior to the removal the consolidation objects contained multiple classes but now only
// contain one, remove the warning about the presence of multiple classes
// NOTE: This works because of the limited number of messages utilized by the window. If more errors are added,
// simply resetting the error panel here might confuse the user.
if ( bAlreadyWarnedAboutTypes & & AreObjClassesHomogeneous ( ) )
{
ResetErrorPanel ( ) ;
}
}
}
/**
* Display a message in the consolidation panel ' s " error " panel ; Naive implementation , wipes out any pre - existing message
*
* @ param bError If true , change the error panel ' s styling to indicate the severity of the message ; if false , use a lighter style
* @ param ErrorMessage Message to display in the " error " panel
*
* @ note The current implementation is naive and will wipe out any pre - existing message when called . The current needs of the window don ' t require
* anything more sophisticated , but in the future perhaps the messages should be appended , multiple panel types should exist , etc .
*/
2014-04-23 18:06:41 -04:00
void SConsolidateToolWidget : : DisplayMessage ( bool bError , const FText & ErrorMessage )
2014-03-14 14:13:41 -04:00
{
// Update the error text block to display the requested message
ErrorPanel - > SetError ( ErrorMessage ) ;
// Show the error panel
ErrorPanel - > SetVisibility ( EVisibility : : Visible ) ;
}
/** Called in response to the user clicking the "X" button on the error panel; dismisses the error panel */
FReply SConsolidateToolWidget : : OnDismissErrorPanelButtonClicked ( )
{
// Hide the error panel
ErrorPanel - > SetVisibility ( EVisibility : : Hidden ) ;
return FReply : : Handled ( ) ;
}
/** Called in response to the user clicking the "Consolidate Objects"/OK button; performs asset consolidation */
FReply SConsolidateToolWidget : : OnConsolidateButtonClicked ( )
{
const int32 SelectedIndex = GetSelectedListItemIndex ( ) ;
check ( SelectedIndex > = 0 & & ConsolidationObjects . Num ( ) > 1 ) ;
// Find which object the user has elected to be the "object to consolidate to"
UObject * ObjectToConsolidateTo = ConsolidationObjects [ SelectedIndex ] ;
check ( ObjectToConsolidateTo ) ;
// Compose an array of the objects to consolidate, removing the "object to consolidate to" from the array
// NOTE: We cannot just use the array held on the panel, because the references need to be cleared prior to the consolidation
// attempt or else they will interfere and cause problems.
TArray < UObject * > FinalConsolidationObjects = ConsolidationObjects ;
FinalConsolidationObjects . RemoveSingle ( ObjectToConsolidateTo ) ;
// Close the window while the consolidation operation occurs
ParentWindowPtr . Pin ( ) - > HideWindow ( ) ;
// Reset the panel back to its default state so that post-consolidation the panel appears as it would from a fresh launch
ResetErrorPanel ( ) ;
// The consolidation objects must be cleared from the panel, lest they interfere with the consolidation
ClearConsolidationObjects ( ) ;
// Perform the object consolidation
ObjectTools : : FConsolidationResults ConsResults = ObjectTools : : ConsolidateObjects ( ObjectToConsolidateTo , FinalConsolidationObjects ) ;
// Check if the user has specified if they'd like to save the dirtied packages post-consolidation
if ( bSavePackagesChecked )
{
// If the consolidation went off successfully with no failed objects, prompt the user to checkout/save the packages dirtied by the operation
if ( ConsResults . DirtiedPackages . Num ( ) > 0 & & ConsResults . FailedConsolidationObjs . Num ( ) = = 0 & & bSavePackagesChecked = = true )
{
FEditorFileUtils : : PromptForCheckoutAndSave ( ConsResults . DirtiedPackages , false , true ) ;
}
// If the consolidation resulted in failed (partially consolidated) objects, do not save, and inform the user no save attempt was made
else if ( ConsResults . FailedConsolidationObjs . Num ( ) > 0 & & bSavePackagesChecked = = true )
{
2014-04-23 18:06:41 -04:00
DisplayMessage ( true , LOCTEXT ( " Consolidate_WarningPartial " , " Not all objects could be consolidated, no save has occurred " ) ) ;
2014-03-14 14:13:41 -04:00
}
}
RefreshListItems ( ) ;
ParentWindowPtr . Pin ( ) - > ShowWindow ( ) ;
return FReply : : Handled ( ) ;
}
/** Called in response to the user clicking the cancel button; dismisses the panel w/o consolidating objects */
FReply SConsolidateToolWidget : : OnCancelButtonClicked ( )
{
// Close the window and clear out all the consolidation assets/dropped assets/etc.
ParentWindowPtr . Pin ( ) - > RequestDestroyWindow ( ) ;
ClearConsolidationObjects ( ) ;
ClearDroppedAssets ( ) ;
ResetErrorPanel ( ) ;
return FReply : : Handled ( ) ;
}
/** Called in response to the user beginning to drag something over the consolidation panel; parses the drop data into dropped assets, if possible */
void SConsolidateToolWidget : : OnDragEnter ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
// Assets being dropped from content browser should be parsable from a string format
TArray < FAssetData > ExtractedDroppedAsset = AssetUtil : : ExtractAssetDataFromDrag ( DragDropEvent ) ;
// Construct drop data info for each parsed asset string
DroppedAssets . Empty ( ExtractedDroppedAsset . Num ( ) ) ;
DroppedAssets . Append ( ExtractedDroppedAsset ) ;
}
/** Called in response to the user's drag operation exiting the consolidation panel; deletes any dropped asset data */
void SConsolidateToolWidget : : OnDragLeave ( const FDragDropEvent & DragDropEvent )
{
ClearDroppedAssets ( ) ;
}
/** Called in response to the user performing a drop operation in the consolidation panel; adds the dropped objects to the panel */
FReply SConsolidateToolWidget : : OnDrop ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
TArray < FAssetData > ExtractedDroppedAsset = AssetUtil : : ExtractAssetDataFromDrag ( DragDropEvent ) ;
TArray < UObject * > DroppedObjects ;
for ( int Index = 0 ; Index < ExtractedDroppedAsset . Num ( ) ; Index + + )
{
UObject * Object = ExtractedDroppedAsset [ Index ] . GetAsset ( ) ;
if ( Object ! = NULL )
{
DroppedObjects . AddUnique ( Object ) ;
}
}
AddConsolidationObjects ( DroppedObjects ) ;
// Clear out the drop data, as the drop is over
ClearDroppedAssets ( ) ;
return FReply : : Handled ( ) ;
}
/** Called while the user is dragging something over the consolidation panel; provides visual feedback on whether a drop is allowed or not */
FReply SConsolidateToolWidget : : OnDragOver ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
// Construct an array of objects that would be dropped upon the consolidation panel
TArray < FAssetData > ExtractedDroppedAsset = AssetUtil : : ExtractAssetDataFromDrag ( DragDropEvent ) ;
TArray < UObject * > DroppedObjects ;
for ( int Index = 0 ; Index < ExtractedDroppedAsset . Num ( ) ; Index + + )
{
UObject * Object = ExtractedDroppedAsset [ Index ] . GetAsset ( ) ;
if ( Object = = NULL )
{
Object = ExtractedDroppedAsset [ Index ] . GetClass ( ) - > GetDefaultObject ( ) ;
}
if ( Object ! = NULL )
{
DroppedObjects . AddUnique ( Object ) ;
}
}
// If all of the dragged over assets are compatible, update the mouse cursor to signify a drop is possible
TArray < UObject * > CompatibleAssets ;
if ( DroppedObjects . Num ( ) > 0 & & DetermineAssetCompatibility ( DroppedObjects , CompatibleAssets ) )
{
return FReply : : Handled ( ) ;
}
return FReply : : Unhandled ( ) ;
}
/** Called in response to the user releasing a keyboard key while the consolidation panel has keyboard focus */
2014-10-30 12:29:36 -04:00
FReply SConsolidateToolWidget : : OnKeyUp ( const FGeometry & MyGeometry , const FKeyEvent & InKeyEvent )
2014-03-14 14:13:41 -04:00
{
2014-10-30 12:29:36 -04:00
const FKey Key = InKeyEvent . GetKey ( ) ;
2014-03-14 14:13:41 -04:00
if ( Key = = EKeys : : Platform_Delete )
{
RemoveSelectedObject ( ) ;
return FReply : : Handled ( ) ;
}
return FReply : : Unhandled ( ) ;
}
# undef LOCTEXT_NAMESPACE