Files
UnrealEngineUWP/Engine/Source/Editor/DataTableEditor/Private/SRowEditor.cpp
Ben Marsh 149375b14b Update copyright notices to 2015.
[CL 2379638 by Ben Marsh in Main branch]
2014-12-07 19:09:38 -05:00

346 lines
8.2 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "DataTableEditorPrivatePCH.h"
#include "SRowEditor.h"
#include "PropertyEditorModule.h"
#include "IStructureDetailsView.h"
#include "IDetailsView.h"
#include "DataTableEditorUtils.h"
#define LOCTEXT_NAMESPACE "SRowEditor"
class FStructFromDataTable : public FStructOnScope
{
TWeakObjectPtr<UDataTable> DataTable;
FName RowName;
public:
FStructFromDataTable(UDataTable* InDataTable, FName InRowName)
: FStructOnScope()
, DataTable(InDataTable)
, RowName(InRowName)
{}
virtual uint8* GetStructMemory() override
{
return (DataTable.IsValid() && !RowName.IsNone()) ? DataTable->FindRowUnchecked(RowName) : NULL;
}
virtual const uint8* GetStructMemory() const override
{
return (DataTable.IsValid() && !RowName.IsNone()) ? DataTable->FindRowUnchecked(RowName) : NULL;
}
virtual const UScriptStruct* GetStruct() const override
{
return DataTable.IsValid() ? DataTable->RowStruct : NULL;
}
virtual bool IsValid() const override
{
return !RowName.IsNone()
&& DataTable.IsValid()
&& DataTable->RowStruct
&& DataTable->FindRowUnchecked(RowName);
}
virtual void Destroy() override
{
DataTable = NULL;
RowName = NAME_None;
}
FName GetRowName() const
{
return RowName;
}
};
SRowEditor::SRowEditor() : SCompoundWidget()
{
}
SRowEditor::~SRowEditor()
{
}
void SRowEditor::OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent)
{
check(PropertyChangedEvent.MemberProperty
&& PropertyChangedEvent.MemberProperty->GetOwnerStruct()
&& (PropertyChangedEvent.MemberProperty->GetOwnerStruct() == GetScriptStruct()));
// TODO:
// FNotifyHook won't be called, because the struct has no "property-path" from DT object. THe struct is seen as detached.
// But the notification must be called somewhere.
FDataTableEditorUtils::BroadcastPostChange(DataTable.Get(), FDataTableEditorUtils::EDataTableChangeInfo::RowDataPostChangeOnly);
if (DataTable.IsValid())
{
DataTable->MarkPackageDirty();
}
}
void SRowEditor::PreChange(const class UUserDefinedStruct* Struct, FStructureEditorUtils::EStructureEditorChangeInfo Info)
{
if (Struct && (GetScriptStruct() == Struct))
{
CleanBeforeChange();
}
}
void SRowEditor::PostChange(const class UUserDefinedStruct* Struct, FStructureEditorUtils::EStructureEditorChangeInfo Info)
{
if (Struct && (GetScriptStruct() == Struct))
{
Restore();
}
}
void SRowEditor::PreChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info)
{
if ((Changed == DataTable.Get()) && (FDataTableEditorUtils::EDataTableChangeInfo::RowList == Info))
{
CleanBeforeChange();
}
}
void SRowEditor::PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info)
{
FStringAssetReference::InvalidateTag(); // Should be removed after UE-5615 is fixed
if ((Changed == DataTable.Get()) && (FDataTableEditorUtils::EDataTableChangeInfo::RowList == Info))
{
RefreshNameList();
Restore();
}
}
void SRowEditor::CleanBeforeChange()
{
if (StructureDetailsView.IsValid())
{
StructureDetailsView->SetStructureData(NULL);
}
if (CurrentRow.IsValid())
{
CurrentRow->Destroy();
CurrentRow.Reset();
}
}
void SRowEditor::RefreshNameList()
{
CachedRowNames.Empty();
if (DataTable.IsValid())
{
auto RowNames = DataTable->GetRowNames();
for (auto RowName : RowNames)
{
CachedRowNames.Add(MakeShareable(new FName(RowName)));
}
}
}
void SRowEditor::Restore()
{
if (SelectedName.IsValid())
{
auto CurrentName = *SelectedName;
SelectedName = NULL;
for (auto Element : CachedRowNames)
{
if (*Element == CurrentName)
{
SelectedName = Element;
break;
}
}
}
if (!SelectedName.IsValid() && CachedRowNames.Num() && CachedRowNames[0].IsValid())
{
SelectedName = CachedRowNames[0];
}
if (RowComboBox.IsValid())
{
RowComboBox->SetSelectedItem(SelectedName);
}
auto FinalName = SelectedName.IsValid() ? *SelectedName : NAME_None;
CurrentRow = MakeShareable(new FStructFromDataTable(DataTable.Get(), FinalName));
if (StructureDetailsView.IsValid())
{
StructureDetailsView->SetStructureData(CurrentRow);
}
}
UScriptStruct* SRowEditor::GetScriptStruct() const
{
return DataTable.IsValid() ? DataTable->RowStruct : NULL;
}
FName SRowEditor::GetCurrentName() const
{
return SelectedName.IsValid() ? *SelectedName : NAME_None;
}
FText SRowEditor::GetCurrentNameAsText() const
{
return FText::FromName(GetCurrentName());
}
FString SRowEditor::GetStructureDisplayName() const
{
const auto Struct = DataTable.IsValid() ? DataTable->RowStruct : NULL;
return Struct
? Struct->GetDisplayNameText().ToString()
: LOCTEXT("Error_UnknownStruct", "Error: Unknown Struct").ToString();
}
TSharedRef<SWidget> SRowEditor::OnGenerateWidget(TSharedPtr<FName> InItem)
{
return SNew(STextBlock).Text(FText::FromName(InItem.IsValid() ? *InItem : NAME_None));
}
void SRowEditor::OnSelectionChanged(TSharedPtr<FName> InItem, ESelectInfo::Type InSeletionInfo)
{
if (InItem != SelectedName)
{
CleanBeforeChange();
SelectedName = InItem;
Restore();
}
}
FReply SRowEditor::OnAddClicked()
{
if (DataTable.IsValid())
{
FName NewName = DataTable->MakeValidName(TEXT("NewRow"));
const TArray<FName> ExisitngNames = DataTable->GetRowNames();
while (ExisitngNames.Contains(NewName))
{
NewName.SetNumber(NewName.GetNumber() + 1);
}
SelectedName = MakeShareable(new FName(NewName));
FDataTableEditorUtils::AddRow(DataTable.Get(), NewName);
}
return FReply::Handled();
}
FReply SRowEditor::OnRemoveClicked()
{
if (DataTable.IsValid())
{
const FName RowToRemove = GetCurrentName();
FDataTableEditorUtils::RemoveRow(DataTable.Get(), RowToRemove);
}
return FReply::Handled();
}
void SRowEditor::OnRowRenamed(const FText& Text, ETextCommit::Type CommitType)
{
if (!GetCurrentNameAsText().EqualTo(Text) && DataTable.IsValid())
{
const FName OldName = GetCurrentName();
const FName NewName = DataTable->MakeValidName(Text.ToString());
SelectedName = MakeShareable(new FName(NewName));
FDataTableEditorUtils::RenameRow(DataTable.Get(), OldName, NewName);
}
}
void SRowEditor::Construct(const FArguments& InArgs, UDataTable* Changed)
{
DataTable = Changed;
{
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
FDetailsViewArgs ViewArgs;
ViewArgs.bAllowSearch = false;
ViewArgs.bHideSelectionTip = false;
ViewArgs.bShowActorLabel = false;
StructureDetailsView = PropertyModule.CreateStructureDetailView(ViewArgs, CurrentRow, false, LOCTEXT("RowValue", "Row Value"));
StructureDetailsView->GetOnFinishedChangingPropertiesDelegate().AddSP(this, &SRowEditor::OnFinishedChangingProperties);
}
RefreshNameList();
Restore();
ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2)
.VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock)
.Text(this, &SRowEditor::GetStructureDisplayName)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2)
[
SAssignNew(RowComboBox, SComboBox<TSharedPtr<FName>>)
.OptionsSource(&CachedRowNames)
.OnSelectionChanged(this, &SRowEditor::OnSelectionChanged)
.OnGenerateWidget(this, &SRowEditor::OnGenerateWidget)
.Content()
[
SNew(STextBlock).Text(this, &SRowEditor::GetCurrentNameAsText)
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2)
[
SNew(SButton)
.OnClicked(this, &SRowEditor::OnAddClicked)
.Content()
[
SNew(STextBlock).Text(LOCTEXT("AddRow", "Add"))
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2)
[
SNew(SButton)
.OnClicked(this, &SRowEditor::OnRemoveClicked)
.Content()
[
SNew(STextBlock).Text(LOCTEXT("RemoveRow", "Remove"))
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2)
.VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock).Text(LOCTEXT("RenameRow", "Rename:"))
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2)
[
SNew(SEditableTextBox)
.Text(this, &SRowEditor::GetCurrentNameAsText)
.OnTextCommitted(this, &SRowEditor::OnRowRenamed)
]
]
+ SVerticalBox::Slot()
.AutoHeight()
[
StructureDetailsView->GetWidget().ToSharedRef()
]
];
}