You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- The type displayed is consistent with the type displayed in the 'Changelists' window. Removed the 'Off' from 'Source Control Off' on the tool bar because the icon and the text color are enough. #jira UE-155247 - Show the type of actors being checked out in the "Check Out Assets" window. #rb Patrick.Enfedaque #preflight 6324785f5f55ba280e0a3567 [CL 22052349 by patrick laflamme in ue5-main branch]
954 lines
27 KiB
C++
954 lines
27 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SPackagesDialog.h"
|
|
|
|
#include "AssetRegistry/AssetData.h"
|
|
#include "AssetToolsModule.h"
|
|
#include "Framework/Commands/UIAction.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "Framework/Views/ITypedTableView.h"
|
|
#include "IAssetTools.h"
|
|
#include "IAssetTypeActions.h"
|
|
#include "Input/Events.h"
|
|
#include "InputCoreTypes.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#include "Layout/Children.h"
|
|
#include "Layout/ChildrenBase.h"
|
|
#include "Layout/Margin.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Misc/AssetRegistryInterface.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "SWarningOrErrorBox.h"
|
|
#include "SlotBase.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "Styling/ISlateStyle.h"
|
|
#include "Styling/SlateColor.h"
|
|
#include "Styling/StyleDefaults.h"
|
|
#include "Textures/SlateIcon.h"
|
|
#include "Types/SlateEnums.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/UObjectHash.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Widgets/Layout/SBorder.h"
|
|
#include "Widgets/Layout/SBox.h"
|
|
#include "Widgets/Layout/SSpacer.h"
|
|
#include "Widgets/SBoxPanel.h"
|
|
#include "Widgets/SNullWidget.h"
|
|
#include "Widgets/SWidget.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
#include "Widgets/Views/SListView.h"
|
|
|
|
class ITableRow;
|
|
class STableViewBase;
|
|
struct FGeometry;
|
|
struct FSlateBrush;
|
|
|
|
#define LOCTEXT_NAMESPACE "SPackagesDialog"
|
|
|
|
namespace SPackagesDialogDefs
|
|
{
|
|
const FName ColumnID_CheckBoxLabel( "CheckBox" );
|
|
const FName ColumnID_IconLabel( "Icon" );
|
|
const FName ColumnID_AssetLabel( "Asset" );
|
|
const FName ColumnID_OwnerLabel( "Owner" );
|
|
const FName ColumnID_PackageLabel( "Package" );
|
|
const FName ColumnID_TypeLabel( "Type" );
|
|
const FName ColumnID_CheckedOutByLabel( "CheckedOutBy" );
|
|
|
|
const float CheckBoxColumnWidth = 38.0f;
|
|
const float IconColumnWidth = 22.0f;
|
|
}
|
|
|
|
|
|
UObject* FPackageItem::GetPackageObject() const
|
|
{
|
|
UObject* FoundObject = nullptr;
|
|
if ( !FileName.StartsWith(TEXT("/Temp/Untitled")) )
|
|
{
|
|
FoundObject = Package->FindAssetInPackage();
|
|
}
|
|
return FoundObject;
|
|
}
|
|
|
|
bool FPackageItem::HasMultipleAssets() const
|
|
{
|
|
if ( !FileName.StartsWith(TEXT("/Temp/Untitled")) )
|
|
{
|
|
int32 NumAssets = 0;
|
|
int32 NumDeleted = 0;
|
|
ForEachObjectWithPackage(Package, [&NumAssets,&NumDeleted](UObject* Obj)
|
|
{
|
|
if (Obj->IsAsset() && !UE::AssetRegistry::FFiltering::ShouldSkipAsset(Obj))
|
|
{
|
|
++NumAssets;
|
|
|
|
if (!IsValid(Obj))
|
|
{
|
|
++NumDeleted;
|
|
}
|
|
}
|
|
return true;
|
|
}, false /*bIncludeNestedObjects*/);
|
|
|
|
return (NumAssets - NumDeleted) > 1;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FPackageItem::GetTypeNameAndColor(FText& OutName, FColor& OutColor) const
|
|
{
|
|
// Resolve the object belonging to the package and cache.
|
|
if (!Object.IsValid())
|
|
{
|
|
Object = GetPackageObject();
|
|
}
|
|
|
|
if (Object.IsValid(/*bEvenIfPendingKill*/true, /*bThreadsafeTest*/false))
|
|
{
|
|
// Load the asset tools module to get access to the class color
|
|
UObject* ObjectPtr = Object.Get(/*bEvenIfPendingKill*/true);
|
|
const FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
|
|
const TSharedPtr<IAssetTypeActions> AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(ObjectPtr->GetClass()).Pin();
|
|
if ( AssetTypeActions.IsValid() )
|
|
{
|
|
if(HasMultipleAssets())
|
|
{
|
|
OutColor = FColor::White;
|
|
OutName = LOCTEXT("MultipleAssets", "Multiple Assets");
|
|
}
|
|
else // Just one asset in the package.
|
|
{
|
|
OutColor = !IsValidChecked(ObjectPtr) ? FColor::Red : AssetTypeActions->GetTypeColor();
|
|
|
|
FAssetData AssetData(ObjectPtr);
|
|
OutName = FText::FromString(AssetData.AssetClassPath.ToString());
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
// if we do not find any package object, consider the package empty, return a red `Empty Package`
|
|
else
|
|
{
|
|
OutName = LOCTEXT("NoAssets", "Empty Package");
|
|
OutColor = 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
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Construct this widget
|
|
*
|
|
* @param InArgs The declaration data for this widget
|
|
*/
|
|
void SPackagesDialog::Construct(const FArguments& InArgs)
|
|
{
|
|
bSortDirty = false;
|
|
bReadOnly = InArgs._ReadOnly.Get();
|
|
bAllowSourceControlConnection = InArgs._AllowSourceControlConnection.Get();
|
|
Message = InArgs._Message;
|
|
Warning = InArgs._Warning;
|
|
OnSourceControlStateChanged = InArgs._OnSourceControlStateChanged;
|
|
SortByColumn = SPackagesDialogDefs::ColumnID_AssetLabel;
|
|
SortMode = EColumnSortMode::Ascending;
|
|
|
|
ButtonsBox = SNew( SHorizontalBox );
|
|
|
|
if(bAllowSourceControlConnection)
|
|
{
|
|
ButtonsBox->AddSlot()
|
|
.AutoWidth()
|
|
.Padding( 2 )
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("ConnectToSourceControl", "Connect To Source Control"))
|
|
.ToolTipText(LOCTEXT("ConnectToSourceControl_Tooltip", "Connect to source control to allow source control operations to be performed on content and levels."))
|
|
.ContentPadding(FMargin(10, 3))
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
.Visibility(this, &SPackagesDialog::GetConnectToSourceControlVisibility)
|
|
.OnClicked(this, &SPackagesDialog::OnConnectToSourceControlClicked)
|
|
];
|
|
}
|
|
|
|
TSharedRef< SHeaderRow > HeaderRowWidget = SNew( SHeaderRow );
|
|
|
|
if (!bReadOnly)
|
|
{
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column( SPackagesDialogDefs::ColumnID_CheckBoxLabel )
|
|
[
|
|
SNew(SBox)
|
|
.Padding(FMargin(6,3,6,3))
|
|
.HAlign(HAlign_Center)
|
|
[
|
|
SAssignNew( ToggleSelectedCheckBox, SCheckBox )
|
|
.IsChecked(this, &SPackagesDialog::GetToggleSelectedState)
|
|
.OnCheckStateChanged(this, &SPackagesDialog::OnToggleSelectedCheckBox)
|
|
]
|
|
]
|
|
.FixedWidth( SPackagesDialogDefs::CheckBoxColumnWidth )
|
|
);
|
|
}
|
|
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column( SPackagesDialogDefs::ColumnID_IconLabel )
|
|
[
|
|
SNew(SSpacer)
|
|
]
|
|
.SortMode( this, &SPackagesDialog::GetColumnSortMode, SPackagesDialogDefs::ColumnID_IconLabel )
|
|
.OnSort( this, &SPackagesDialog::OnColumnSortModeChanged )
|
|
.FixedWidth( SPackagesDialogDefs::IconColumnWidth )
|
|
);
|
|
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column( SPackagesDialogDefs::ColumnID_AssetLabel )
|
|
.DefaultLabel( LOCTEXT("AssetColumnLabel", "Asset" ) )
|
|
.SortMode( this, &SPackagesDialog::GetColumnSortMode, SPackagesDialogDefs::ColumnID_AssetLabel )
|
|
.OnSort( this, &SPackagesDialog::OnColumnSortModeChanged )
|
|
.FillWidth( 5.0f )
|
|
);
|
|
/*
|
|
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column(SPackagesDialogDefs::ColumnID_OwnerLabel)
|
|
.DefaultLabel(LOCTEXT("OwnerColumnLabel", "Owner"))
|
|
.SortMode(this, &SPackagesDialog::GetColumnSortMode, SPackagesDialogDefs::ColumnID_OwnerLabel)
|
|
.OnSort(this, &SPackagesDialog::OnColumnSortModeChanged)
|
|
.FillWidth(7.0f)
|
|
);
|
|
*/
|
|
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column( SPackagesDialogDefs::ColumnID_PackageLabel )
|
|
.DefaultLabel( LOCTEXT("FileColumnLabel", "File" ) )
|
|
.SortMode( this, &SPackagesDialog::GetColumnSortMode, SPackagesDialogDefs::ColumnID_PackageLabel )
|
|
.OnSort( this, &SPackagesDialog::OnColumnSortModeChanged )
|
|
.FillWidth( 7.0f )
|
|
);
|
|
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column( SPackagesDialogDefs::ColumnID_TypeLabel )
|
|
.DefaultLabel( LOCTEXT("TypeColumnLabel", "Type" ) )
|
|
.SortMode( this, &SPackagesDialog::GetColumnSortMode, SPackagesDialogDefs::ColumnID_TypeLabel )
|
|
.OnSort( this, &SPackagesDialog::OnColumnSortModeChanged )
|
|
.FillWidth( 2.0f )
|
|
);
|
|
|
|
if (bAllowSourceControlConnection)
|
|
{
|
|
HeaderRowWidget->AddColumn(
|
|
SHeaderRow::Column(SPackagesDialogDefs::ColumnID_CheckedOutByLabel)
|
|
.DefaultLabel(LOCTEXT("CheckedOutByColumnLabel", "Checked Out By"))
|
|
.SortMode(this, &SPackagesDialog::GetColumnSortMode, SPackagesDialogDefs::ColumnID_CheckedOutByLabel)
|
|
.OnSort(this, &SPackagesDialog::OnColumnSortModeChanged)
|
|
.FillWidth(4.0f)
|
|
);
|
|
}
|
|
|
|
this->ChildSlot
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FAppStyle::Get().GetBrush("Brushes.Panel"))
|
|
.Padding(FMargin(16))
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0.0f,0.0f,0.0f,8.0f)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SPackagesDialog::GetMessage)
|
|
.AutoWrapText(true)
|
|
]
|
|
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.8)
|
|
[
|
|
SAssignNew(ItemListView, SListView< TSharedPtr<FPackageItem> >)
|
|
.ListItemsSource(&Items)
|
|
.OnGenerateRow(this, &SPackagesDialog::MakePackageListItemWidget)
|
|
.OnContextMenuOpening(this, &SPackagesDialog::MakePackageListContextMenu)
|
|
.ItemHeight(20)
|
|
.HeaderRow( HeaderRowWidget )
|
|
.SelectionMode( ESelectionMode::None )
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.Padding(0, 16.0f, 0, 0)
|
|
.AutoHeight()
|
|
[
|
|
SNew(SWarningOrErrorBox)
|
|
.Visibility(this, &SPackagesDialog::GetWarningVisibility)
|
|
.Message(this, &SPackagesDialog::GetWarning)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0.0f, 16.0f, 0.0f, 0.0f)
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Bottom)
|
|
[
|
|
ButtonsBox.ToSharedRef()
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Removes all checkbox items from the dialog
|
|
*/
|
|
void SPackagesDialog::RemoveAll()
|
|
{
|
|
Items.Reset();
|
|
}
|
|
|
|
/**
|
|
* Adds a new checkbox item to the dialog
|
|
*
|
|
* @param Item The item to be added
|
|
*/
|
|
void SPackagesDialog::Add(TSharedPtr<FPackageItem> Item)
|
|
{
|
|
FSimpleDelegate RefreshCallback = FSimpleDelegate::CreateSP(this, &SPackagesDialog::RefreshButtons);
|
|
Item->SetRefreshCallback(RefreshCallback);
|
|
Items.Add(Item);
|
|
RequestSort();
|
|
}
|
|
|
|
/**
|
|
* Adds a new button to the dialog
|
|
*
|
|
* @param Button The button to be added
|
|
*/
|
|
void SPackagesDialog::AddButton(TSharedPtr<FPackageButton> Button)
|
|
{
|
|
Buttons.Add(Button);
|
|
|
|
ButtonsBox->AddSlot()
|
|
.AutoWidth()
|
|
.Padding(5, 0)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(&FAppStyle::Get(), (Button->GetType() == DRT_Save || Button->GetType() == DRT_CheckOut) ? "PrimaryButton" : "Button")
|
|
.TextStyle(&FAppStyle::Get(), (Button->GetType() == DRT_Save || Button->GetType() == DRT_CheckOut) ? "PrimaryButtonText" : "ButtonText")
|
|
.Text(Button->GetName())
|
|
.ToolTipText(Button->GetToolTip())
|
|
.IsEnabled(Button.Get(), &FPackageButton::IsEnabled)
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
.OnClicked(Button.Get(), &FPackageButton::OnButtonClicked)
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Sets the message of the widget
|
|
*
|
|
* @param InMessage The string that the message should be set to
|
|
*/
|
|
void SPackagesDialog::SetMessage(const FText& InMessage)
|
|
{
|
|
Message = InMessage;
|
|
}
|
|
|
|
/**
|
|
* Sets the warning message of the widget
|
|
*
|
|
* @param InMessage The string that the warning message should be set to
|
|
*/
|
|
void SPackagesDialog::SetWarning(const FText& InWarning)
|
|
{
|
|
Warning = InWarning;
|
|
}
|
|
|
|
/**
|
|
* Gets the return type of the dialog and it populates the package array results
|
|
*
|
|
* @param OutCheckedPackages Will be populated with the checked packages
|
|
* @param OutUncheckedPackages Will be populated with the unchecked packages
|
|
* @param OutUndeterminedPackages Will be populated with the undetermined packages
|
|
*
|
|
* @return returns the button that was pressed to remove the dialog
|
|
*/
|
|
EDialogReturnType SPackagesDialog::GetReturnType(OUT TArray<UPackage*>& OutCheckedPackages, OUT TArray<UPackage*>& OutUncheckedPackages, OUT TArray<UPackage*>& OutUndeterminedPackages)
|
|
{
|
|
/** Set the return type to which button was pressed */
|
|
EDialogReturnType ReturnType = DRT_None;
|
|
for( int32 ButtonIndex = 0; ButtonIndex < Buttons.Num(); ++ButtonIndex)
|
|
{
|
|
FPackageButton& Button = *Buttons[ButtonIndex];
|
|
if(Button.IsClicked())
|
|
{
|
|
ReturnType = Button.GetType();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/** Populate the results */
|
|
if(ReturnType != DRT_Cancel && ReturnType != DRT_None)
|
|
{
|
|
for( int32 ItemIndex = 0; ItemIndex < Items.Num(); ++ItemIndex)
|
|
{
|
|
FPackageItem& item = *Items[ItemIndex];
|
|
if(item.GetState() == ECheckBoxState::Checked)
|
|
{
|
|
OutCheckedPackages.Add(item.GetPackage());
|
|
}
|
|
else if(item.GetState() == ECheckBoxState::Unchecked)
|
|
{
|
|
OutUncheckedPackages.Add(item.GetPackage());
|
|
}
|
|
else
|
|
{
|
|
OutUndeterminedPackages.Add(item.GetPackage());
|
|
}
|
|
}
|
|
}
|
|
|
|
return ReturnType;
|
|
}
|
|
|
|
/**
|
|
* Gets the widget which is to have keyboard focus on activating the dialog
|
|
*
|
|
* @return returns the widget
|
|
*/
|
|
TSharedPtr< SWidget > SPackagesDialog::GetWidgetToFocusOnActivate() const
|
|
{
|
|
// Find the first visible button. That will be our widget to focus
|
|
FChildren* ButtonBoxChildren = ButtonsBox->GetChildren();
|
|
for( int ButtonIndex = 0; ButtonIndex < ButtonBoxChildren->Num(); ++ButtonIndex )
|
|
{
|
|
TSharedPtr<SWidget> ButtonWidget = ButtonBoxChildren->GetChildAt(ButtonIndex);
|
|
if(ButtonWidget.IsValid() && ButtonWidget->GetVisibility() == EVisibility::Visible)
|
|
{
|
|
return ButtonWidget;
|
|
}
|
|
}
|
|
|
|
return TSharedPtr< SWidget >();
|
|
}
|
|
|
|
/**
|
|
* Called when the checkbox items have changed state
|
|
*/
|
|
void SPackagesDialog::RefreshButtons()
|
|
{
|
|
int32 CheckedItems = 0;
|
|
int32 UncheckedItems = 0;
|
|
int32 UndeterminedItems = 0;
|
|
|
|
/** Count the number of checkboxes that we have for each state */
|
|
for( int32 ItemIndex = 0; ItemIndex < Items.Num(); ++ItemIndex)
|
|
{
|
|
FPackageItem& item = *Items[ItemIndex];
|
|
if(item.GetState() == ECheckBoxState::Checked)
|
|
{
|
|
CheckedItems++;
|
|
}
|
|
else if(item.GetState() == ECheckBoxState::Unchecked)
|
|
{
|
|
UncheckedItems++;
|
|
}
|
|
else
|
|
{
|
|
UndeterminedItems++;
|
|
}
|
|
}
|
|
|
|
/** Change the button state based on our selection */
|
|
for( int32 ButtonIndex = 0; ButtonIndex < Buttons.Num(); ++ButtonIndex)
|
|
{
|
|
FPackageButton& Button = *Buttons[ButtonIndex];
|
|
if(Button.GetType() == DRT_MakeWritable)
|
|
{
|
|
Button.SetDisabled(UndeterminedItems == 0 && CheckedItems == 0);
|
|
}
|
|
else if(Button.GetType() == DRT_CheckOut)
|
|
{
|
|
Button.SetDisabled(CheckedItems == 0);
|
|
}
|
|
else if (Button.GetType() == DRT_Skip)
|
|
{
|
|
Button.SetDisabled(CheckedItems > 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes the widget for the checkbox items in the list view
|
|
*/
|
|
TSharedRef<ITableRow> SPackagesDialog::MakePackageListItemWidget( TSharedPtr<FPackageItem> Item, const TSharedRef<STableViewBase>& OwnerTable)
|
|
{
|
|
return SNew( SPackageItemsListRow, OwnerTable )
|
|
.PackagesDialog( SharedThis( this ) )
|
|
.Item( Item );
|
|
}
|
|
|
|
|
|
TSharedRef<SWidget> SPackagesDialog::GenerateWidgetForItemAndColumn( TSharedPtr<FPackageItem> Item, const FName ColumnID ) const
|
|
{
|
|
check(Item.IsValid());
|
|
|
|
// Choose the icon based on the severity
|
|
const FSlateBrush* IconBrush = Item->GetIconName().IsEmpty() ? FStyleDefaults::GetNoBrush() : FAppStyle::GetBrush(*(Item->GetIconName()));
|
|
|
|
const FMargin RowPadding(3, 3, 3, 3);
|
|
|
|
// Extract the type and color for the package
|
|
FColor PackageColor;
|
|
FText PackageType;
|
|
Item->GetTypeNameAndColor(PackageType, PackageColor);
|
|
|
|
const FString AssetName = Item->GetAssetName();
|
|
const FString OwnerName = Item->GetOwnerName();
|
|
const FString PackageName = Item->GetPackageName();
|
|
const FString FileName = Item->GetFileName();
|
|
|
|
TSharedPtr<SWidget> ItemContentWidget;
|
|
|
|
if (ColumnID == SPackagesDialogDefs::ColumnID_CheckBoxLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.Padding(FMargin(10, 3, 6, 3))
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked(Item.Get(), &FPackageItem::OnGetDisplayCheckState)
|
|
.OnCheckStateChanged(Item.Get(), &FPackageItem::OnDisplayCheckStateChanged)
|
|
];
|
|
}
|
|
else if (ColumnID == SPackagesDialogDefs::ColumnID_IconLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SImage)
|
|
.Image( IconBrush )
|
|
.ToolTipText(FText::FromString(Item->GetToolTip()))
|
|
.IsEnabled(!Item->IsDisabled())
|
|
];
|
|
}
|
|
else if (ColumnID == SPackagesDialogDefs::ColumnID_AssetLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.Padding(RowPadding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(AssetName))
|
|
.IsEnabled(!Item->IsDisabled())
|
|
];
|
|
}
|
|
else if (ColumnID == SPackagesDialogDefs::ColumnID_OwnerLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.Padding(RowPadding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(OwnerName))
|
|
.ToolTipText(FText::FromString(OwnerName))
|
|
.IsEnabled(!Item->IsDisabled())
|
|
];
|
|
}
|
|
else if (ColumnID == SPackagesDialogDefs::ColumnID_PackageLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.Padding(RowPadding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(PackageName))
|
|
.ToolTipText(FText::FromString(FileName))
|
|
.IsEnabled(!Item->IsDisabled())
|
|
];
|
|
}
|
|
else if (ColumnID == SPackagesDialogDefs::ColumnID_TypeLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.Padding(RowPadding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(PackageType)
|
|
.ToolTipText(PackageType)
|
|
.IsEnabled(!Item->IsDisabled())
|
|
.ColorAndOpacity(PackageColor)
|
|
];
|
|
}
|
|
else if (ColumnID == SPackagesDialogDefs::ColumnID_CheckedOutByLabel)
|
|
{
|
|
check(bAllowSourceControlConnection);
|
|
|
|
FString CheckedOutByString = Item->GetCheckedOutByString();
|
|
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(RowPadding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(CheckedOutByString))
|
|
.ToolTipText(FText::FromString(CheckedOutByString))
|
|
.IsEnabled(!Item->IsDisabled())
|
|
];
|
|
}
|
|
|
|
return ItemContentWidget.ToSharedRef();
|
|
}
|
|
|
|
TSharedPtr<SWidget> SPackagesDialog::MakePackageListContextMenu() const
|
|
{
|
|
FMenuBuilder MenuBuilder( true, NULL );
|
|
|
|
const TArray< TSharedPtr<FPackageItem> > SelectedItems = GetSelectedItems( false );
|
|
if( SelectedItems.Num() > 0 )
|
|
{
|
|
MenuBuilder.BeginSection("FilePackage", LOCTEXT("PackageHeading", "Asset"));
|
|
{
|
|
MenuBuilder.AddMenuEntry(
|
|
LOCTEXT("SCCDiffAgainstDepot", "Diff Against Depot"),
|
|
LOCTEXT("SCCDiffAgainstDepotTooltip", "Look at differences between your version of the asset and that in source control."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateSP( this, &SPackagesDialog::ExecuteSCCDiffAgainstDepot ),
|
|
FCanExecuteAction::CreateSP( this, &SPackagesDialog::CanExecuteSCCDiffAgainstDepot )
|
|
)
|
|
);
|
|
}
|
|
MenuBuilder.EndSection();
|
|
}
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
bool SPackagesDialog::CanExecuteSCCDiffAgainstDepot() const
|
|
{
|
|
return ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable();
|
|
}
|
|
|
|
void SPackagesDialog::ExecuteSCCDiffAgainstDepot() const
|
|
{
|
|
const FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
|
|
|
|
const TArray< TSharedPtr<FPackageItem> > SelectedItems = GetSelectedItems( false );
|
|
for(int32 ItemIdx=0; ItemIdx<SelectedItems.Num(); ItemIdx++)
|
|
{
|
|
const TSharedPtr<FPackageItem> SelectedItem = SelectedItems[ItemIdx];
|
|
check( SelectedItem.IsValid() );
|
|
|
|
UObject* Object = SelectedItem->GetPackageObject();
|
|
if( Object )
|
|
{
|
|
const FString PackagePath = SelectedItem->GetFileName();
|
|
const FString PackageName = FPaths::GetBaseFilename( PackagePath );
|
|
AssetToolsModule.Get().DiffAgainstDepot( Object, PackagePath, PackageName );
|
|
}
|
|
}
|
|
}
|
|
|
|
TArray< TSharedPtr<FPackageItem> > SPackagesDialog::GetSelectedItems( bool bAllIfNone ) const
|
|
{
|
|
//get the list of highlighted packages
|
|
TArray< TSharedPtr<FPackageItem> > SelectedItems = ItemListView->GetSelectedItems();
|
|
if ( SelectedItems.Num() == 0 && bAllIfNone )
|
|
{
|
|
//If no packages are explicitly highlighted, return all packages in the list.
|
|
SelectedItems = Items;
|
|
}
|
|
|
|
return SelectedItems;
|
|
}
|
|
|
|
ECheckBoxState SPackagesDialog::GetToggleSelectedState() const
|
|
{
|
|
//default to a Checked state
|
|
ECheckBoxState PendingState = ECheckBoxState::Checked;
|
|
|
|
TArray< TSharedPtr<FPackageItem> > SelectedItems = GetSelectedItems( true );
|
|
|
|
//Iterate through the list of selected packages
|
|
for ( auto SelectedItem = SelectedItems.CreateConstIterator(); SelectedItem; ++SelectedItem )
|
|
{
|
|
if ( SelectedItem->Get()->GetState() == ECheckBoxState::Unchecked )
|
|
{
|
|
//if any package in the selection is Unchecked, then represent the entire set of highlighted packages as Unchecked,
|
|
//so that the first (user) toggle of ToggleSelectedCheckBox consistently Checks all highlighted packages
|
|
PendingState = ECheckBoxState::Unchecked;
|
|
}
|
|
}
|
|
|
|
return PendingState;
|
|
}
|
|
|
|
void SPackagesDialog::OnToggleSelectedCheckBox(ECheckBoxState InNewState)
|
|
{
|
|
TArray< TSharedPtr<FPackageItem> > SelectedItems = GetSelectedItems( true );
|
|
|
|
for ( auto SelectedItem = SelectedItems.CreateConstIterator(); SelectedItem; ++SelectedItem )
|
|
{
|
|
FPackageItem *item = (*SelectedItem).Get();
|
|
if (InNewState == ECheckBoxState::Checked)
|
|
{
|
|
if(item->IsDisabled())
|
|
{
|
|
item->SetState(ECheckBoxState::Undetermined);
|
|
}
|
|
else
|
|
{
|
|
item->SetState(ECheckBoxState::Checked);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item->SetState(ECheckBoxState::Unchecked);
|
|
}
|
|
}
|
|
|
|
ItemListView->RequestListRefresh();
|
|
}
|
|
|
|
void SPackagesDialog::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
|
|
{
|
|
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
|
|
|
|
if(bSortDirty)
|
|
{
|
|
bSortDirty = false;
|
|
|
|
// Sort the list of root items
|
|
SortTree();
|
|
|
|
ItemListView->RequestListRefresh();
|
|
}
|
|
}
|
|
|
|
|
|
FReply SPackagesDialog::OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent )
|
|
{
|
|
if( InKeyEvent.GetKey() == EKeys::Escape )
|
|
{
|
|
for( int32 ButtonIndex = 0; ButtonIndex < Buttons.Num(); ++ButtonIndex )
|
|
{
|
|
FPackageButton& Button = *Buttons[ ButtonIndex ];
|
|
if( Button.GetType() == DRT_Cancel )
|
|
{
|
|
return Button.OnButtonClicked();
|
|
}
|
|
}
|
|
}
|
|
|
|
return SCompoundWidget::OnKeyDown( MyGeometry, InKeyEvent );
|
|
}
|
|
|
|
EVisibility SPackagesDialog::GetConnectToSourceControlVisibility() const
|
|
{
|
|
if(bAllowSourceControlConnection)
|
|
{
|
|
if(!ISourceControlModule::Get().IsEnabled() || !ISourceControlModule::Get().GetProvider().IsAvailable())
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
}
|
|
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
FReply SPackagesDialog::OnConnectToSourceControlClicked() const
|
|
{
|
|
ISourceControlModule::Get().ShowLoginDialog(FSourceControlLoginClosed(), ELoginWindowMode::Modal);
|
|
OnSourceControlStateChanged.ExecuteIfBound();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
void SPackagesDialog::PopulateIgnoreForSaveItems( const TSet<FString>& InIgnorePackages )
|
|
{
|
|
for( auto ItItem=Items.CreateIterator(); ItItem; ++ItItem )
|
|
{
|
|
const FString& ItemName = (*ItItem)->GetFileName();
|
|
|
|
const ECheckBoxState CheckedStatus = (InIgnorePackages.Find(ItemName) != NULL) ? ECheckBoxState::Unchecked : ECheckBoxState::Checked;
|
|
|
|
if (!(*ItItem)->IsDisabled())
|
|
{
|
|
(*ItItem)->SetState(CheckedStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SPackagesDialog::PopulateIgnoreForSaveArray( OUT TSet<FString>& InOutIgnorePackages ) const
|
|
{
|
|
for( auto ItItem=Items.CreateConstIterator(); ItItem; ++ItItem )
|
|
{
|
|
if((*ItItem)->GetState()==ECheckBoxState::Unchecked)
|
|
{
|
|
InOutIgnorePackages.Add( (*ItItem)->GetFileName() );
|
|
}
|
|
else
|
|
{
|
|
InOutIgnorePackages.Remove( (*ItItem)->GetFileName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SPackagesDialog::Reset()
|
|
{
|
|
for( int32 ButtonIndex = 0; ButtonIndex < Buttons.Num(); ++ButtonIndex)
|
|
{
|
|
Buttons[ButtonIndex]->Reset();
|
|
}
|
|
}
|
|
|
|
FText SPackagesDialog::GetMessage() const
|
|
{
|
|
return Message;
|
|
}
|
|
|
|
FText SPackagesDialog::GetWarning() const
|
|
{
|
|
return Warning;
|
|
}
|
|
|
|
EVisibility SPackagesDialog::GetWarningVisibility() const
|
|
{
|
|
return (Warning.IsEmpty()) ? EVisibility::Collapsed : EVisibility::HitTestInvisible;
|
|
}
|
|
|
|
EColumnSortMode::Type SPackagesDialog::GetColumnSortMode( const FName ColumnId ) const
|
|
{
|
|
if ( SortByColumn != ColumnId )
|
|
{
|
|
return EColumnSortMode::None;
|
|
}
|
|
|
|
return SortMode;
|
|
}
|
|
|
|
void SPackagesDialog::OnColumnSortModeChanged( const EColumnSortPriority::Type SortPriority, const FName& ColumnId, const EColumnSortMode::Type InSortMode )
|
|
{
|
|
SortByColumn = ColumnId;
|
|
SortMode = InSortMode;
|
|
|
|
RequestSort();
|
|
}
|
|
|
|
void SPackagesDialog::RequestSort()
|
|
{
|
|
bSortDirty = true;
|
|
}
|
|
|
|
void SPackagesDialog::SortTree()
|
|
{
|
|
if (SortByColumn == SPackagesDialogDefs::ColumnID_AssetLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetAssetName() < B->GetAssetName(); } );
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetAssetName() >= B->GetAssetName(); } );
|
|
}
|
|
}
|
|
else if (SortByColumn == SPackagesDialogDefs::ColumnID_OwnerLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetOwnerName() < B->GetOwnerName(); } );
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetOwnerName() >= B->GetOwnerName(); } );
|
|
}
|
|
}
|
|
else if (SortByColumn == SPackagesDialogDefs::ColumnID_PackageLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetPackageName() < B->GetPackageName(); } );
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetPackageName() >= B->GetPackageName(); } );
|
|
}
|
|
}
|
|
else if (SortByColumn == SPackagesDialogDefs::ColumnID_TypeLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetTypeName().CompareTo(B->GetTypeName()) < 0; } );
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetTypeName().CompareTo(B->GetTypeName()) >= 0; } );
|
|
}
|
|
}
|
|
else if (SortByColumn == SPackagesDialogDefs::ColumnID_IconLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetIconName() < B->GetIconName(); } );
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetIconName() >= B->GetIconName(); } );
|
|
}
|
|
}
|
|
else if (SortByColumn == SPackagesDialogDefs::ColumnID_CheckedOutByLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetCheckedOutByString() < B->GetCheckedOutByString(); });
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
Items.Sort([](const TSharedPtr<FPackageItem>& A, const TSharedPtr<FPackageItem>& B) {
|
|
return A->GetCheckedOutByString() >= B->GetCheckedOutByString(); });
|
|
}
|
|
}
|
|
}
|
|
|
|
void SPackageItemsListRow::Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView )
|
|
{
|
|
PackagesDialogWeak = InArgs._PackagesDialog;
|
|
Item = InArgs._Item;
|
|
|
|
SMultiColumnTableRow< TSharedPtr<FPackageItem> >::Construct(
|
|
FSuperRowType::FArguments()
|
|
,InOwnerTableView );
|
|
}
|
|
|
|
TSharedRef<SWidget> SPackageItemsListRow::GenerateWidgetForColumn( const FName& ColumnName )
|
|
{
|
|
// Create the widget for this item
|
|
auto PackagesDialogShared = PackagesDialogWeak.Pin();
|
|
if (PackagesDialogShared.IsValid())
|
|
{
|
|
return PackagesDialogShared->GenerateWidgetForItemAndColumn( Item, ColumnName );
|
|
}
|
|
|
|
// Packages dialog no longer valid; return a valid, null widget.
|
|
return SNullWidget::NullWidget;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|