2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-06-06 05:27:30 -04:00
# include "BlueprintGraphPrivatePCH.h"
# include "KismetCompiler.h"
//#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
# include "Kismet/DataTableFunctionLibrary.h"
2014-07-14 19:56:30 -04:00
# include "BlueprintNodeSpawner.h"
2014-07-14 16:05:25 -04:00
# include "EditorCategoryUtils.h"
2014-08-23 20:16:29 -04:00
# include "BlueprintActionDatabaseRegistrar.h"
2014-06-06 05:27:30 -04:00
# define LOCTEXT_NAMESPACE "K2Node_GetDataTableRow"
struct UK2Node_GetDataTableRowHelper
{
static FString DataTablePinName ;
static FString RowNamePinName ;
static FString RowNotFoundPinName ;
} ;
FString UK2Node_GetDataTableRowHelper : : DataTablePinName ( LOCTEXT ( " DataTablePinName " , " DataTable " ) . ToString ( ) ) ;
FString UK2Node_GetDataTableRowHelper : : RowNotFoundPinName ( LOCTEXT ( " RowNotFoundPinName " , " RowNotFound " ) . ToString ( ) ) ;
FString UK2Node_GetDataTableRowHelper : : RowNamePinName ( LOCTEXT ( " RowNamePinName " , " RowName " ) . ToString ( ) ) ;
2014-10-14 10:29:11 -04:00
UK2Node_GetDataTableRow : : UK2Node_GetDataTableRow ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-06-06 05:27:30 -04:00
{
2014-09-03 18:14:09 -04:00
NodeTooltip = LOCTEXT ( " NodeTooltip " , " Attempts to retrieve a TableRow from a DataTable via it's RowName " ) ;
2014-06-06 05:27:30 -04:00
}
void UK2Node_GetDataTableRow : : AllocateDefaultPins ( )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
// Add execution pins
CreatePin ( EGPD_Input , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Execute ) ;
2014-06-09 11:11:12 -04:00
UEdGraphPin * RowFoundPin = CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Then ) ;
RowFoundPin - > PinFriendlyName = LOCTEXT ( " GetDataTableRow Row Found Exec pin " , " Row Found " ) ;
2014-06-06 05:27:30 -04:00
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , UK2Node_GetDataTableRowHelper : : RowNotFoundPinName ) ;
// Add DataTable pin
UEdGraphPin * DataTablePin = CreatePin ( EGPD_Input , K2Schema - > PC_Object , TEXT ( " " ) , UDataTable : : StaticClass ( ) , false , false , UK2Node_GetDataTableRowHelper : : DataTablePinName ) ;
SetPinToolTip ( * DataTablePin , LOCTEXT ( " DataTablePinDescription " , " The DataTable you want to retreive a row from " ) ) ;
// Row Name pin
2014-08-21 23:21:25 -04:00
UEdGraphPin * RowNamePin = CreatePin ( EGPD_Input , K2Schema - > PC_Name , TEXT ( " " ) , NULL , false , false , UK2Node_GetDataTableRowHelper : : RowNamePinName ) ;
SetPinToolTip ( * RowNamePin , LOCTEXT ( " RowNamePinDescription " , " The name of the row to retrieve from the DataTable " ) ) ;
2014-06-06 05:27:30 -04:00
// Result pin
UEdGraphPin * ResultPin = CreatePin ( EGPD_Output , K2Schema - > PC_Struct , TEXT ( " " ) , FTableRowBase : : StaticStruct ( ) , false , false , K2Schema - > PN_ReturnValue ) ;
2014-06-09 11:11:12 -04:00
ResultPin - > PinFriendlyName = LOCTEXT ( " GetDataTableRow Output Row " , " Out Row " ) ;
2014-06-06 05:27:30 -04:00
SetPinToolTip ( * ResultPin , LOCTEXT ( " ResultPinDescription " , " The returned TableRow, if found " ) ) ;
Super : : AllocateDefaultPins ( ) ;
}
void UK2Node_GetDataTableRow : : SetPinToolTip ( UEdGraphPin & MutatablePin , const FText & PinDescription ) const
{
2014-09-05 13:06:18 -04:00
MutatablePin . PinToolTip = UEdGraphSchema_K2 : : TypeToText ( MutatablePin . PinType ) . ToString ( ) ;
2014-06-06 05:27:30 -04:00
UEdGraphSchema_K2 const * const K2Schema = Cast < const UEdGraphSchema_K2 > ( GetSchema ( ) ) ;
if ( K2Schema ! = nullptr )
{
MutatablePin . PinToolTip + = TEXT ( " " ) ;
2015-01-07 09:52:40 -05:00
MutatablePin . PinToolTip + = K2Schema - > GetPinDisplayName ( & MutatablePin ) . ToString ( ) ;
2014-06-06 05:27:30 -04:00
}
MutatablePin . PinToolTip + = FString ( TEXT ( " \n " ) ) + PinDescription . ToString ( ) ;
}
void UK2Node_GetDataTableRow : : SetReturnTypeForStruct ( UScriptStruct * RowStruct )
{
2014-08-19 02:27:41 -04:00
if ( RowStruct = = NULL )
{
RowStruct = FTableRowBase : : StaticStruct ( ) ;
}
2014-06-06 05:27:30 -04:00
2014-08-21 23:21:25 -04:00
UScriptStruct * NewRowStruct = RowStruct ;
UScriptStruct * OldRowStruct = GetReturnTypeForStruct ( ) ;
// If new Data Table uses a different struct type for it's rows
if ( NewRowStruct ! = OldRowStruct )
{
// Doing this just to force the row name drop down to refresh
ReconstructNode ( ) ;
2015-03-06 16:58:44 -05:00
UEdGraphPin * ResultPin = GetResultPin ( ) ;
2014-08-21 23:21:25 -04:00
// Because the Return Value struct type has changed, we break the output link
ResultPin - > BreakAllPinLinks ( ) ;
// Change class of output pin
ResultPin - > PinType . PinSubCategoryObject = RowStruct ;
// When the DataTable pin gets a new value assigned, we need to update the Slate UI so that SGraphNodeCallParameterCollectionFunction will update the ParameterName drop down
UEdGraph * Graph = GetGraph ( ) ;
Graph - > NotifyGraphChanged ( ) ;
UEdGraphPin * OldRowNamePin = GetRowNamePin ( ) ;
// Mark dirty
FBlueprintEditorUtils : : MarkBlueprintAsModified ( GetBlueprint ( ) ) ;
}
2014-06-06 05:27:30 -04:00
}
2014-08-19 02:27:41 -04:00
UScriptStruct * UK2Node_GetDataTableRow : : GetReturnTypeForStruct ( )
{
UScriptStruct * ReturnStructType = ( UScriptStruct * ) ( GetResultPin ( ) - > PinType . PinSubCategoryObject . Get ( ) ) ;
return ReturnStructType ;
}
2014-06-06 05:27:30 -04:00
UScriptStruct * UK2Node_GetDataTableRow : : GetDataTableRowStructType ( const TArray < UEdGraphPin * > * InPinsToSearch /*=NULL*/ ) const
{
UScriptStruct * RowStructType = NULL ;
const TArray < UEdGraphPin * > * PinsToSearch = InPinsToSearch ? InPinsToSearch : & Pins ;
UEdGraphPin * DataTablePin = GetDataTablePin ( PinsToSearch ) ;
if ( DataTablePin & & DataTablePin - > DefaultObject ! = NULL & & DataTablePin - > LinkedTo . Num ( ) = = 0 )
{
if ( DataTablePin - > DefaultObject - > IsA ( UDataTable : : StaticClass ( ) ) )
{
UDataTable * DataTable = ( UDataTable * ) DataTablePin - > DefaultObject ;
2014-08-21 23:21:25 -04:00
if ( DataTable )
{
RowStructType = DataTable - > RowStruct ;
}
2014-06-06 05:27:30 -04:00
}
}
return RowStructType ;
}
2014-11-25 09:36:31 -05:00
void UK2Node_GetDataTableRow : : OnDataTableRowListChanged ( const UDataTable * DataTable )
2014-08-21 23:21:25 -04:00
{
2014-11-25 09:36:31 -05:00
UEdGraphPin * DataTablePin = GetDataTablePin ( ) ;
if ( DataTable & & DataTablePin & & DataTable = = DataTablePin - > DefaultObject )
2014-08-21 23:21:25 -04:00
{
2014-11-25 09:36:31 -05:00
auto RowNamePin = GetRowNamePin ( ) ;
const bool TryRefresh = RowNamePin & & ! RowNamePin - > LinkedTo . Num ( ) ;
const FName CurrentName = RowNamePin ? FName ( * RowNamePin - > GetDefaultAsString ( ) ) : NAME_None ;
if ( TryRefresh & & RowNamePin & & ! DataTable - > GetRowNames ( ) . Contains ( CurrentName ) )
2014-08-21 23:21:25 -04:00
{
2014-11-25 09:36:31 -05:00
if ( auto BP = GetBlueprint ( ) )
2014-08-21 23:21:25 -04:00
{
2014-11-25 09:36:31 -05:00
FBlueprintEditorUtils : : MarkBlueprintAsModified ( BP ) ;
2014-08-21 23:21:25 -04:00
}
}
}
}
2014-06-06 05:27:30 -04:00
void UK2Node_GetDataTableRow : : ReallocatePinsDuringReconstruction ( TArray < UEdGraphPin * > & OldPins )
{
Super : : ReallocatePinsDuringReconstruction ( OldPins ) ;
2014-10-23 12:05:41 -04:00
if ( UEdGraphPin * DataTablePin = GetDataTablePin ( & OldPins ) )
{
if ( UDataTable * DataTable = Cast < UDataTable > ( DataTablePin - > DefaultObject ) )
{
// make sure to properly load the data-table object so that we can
// farm the "RowStruct" property from it (below, in GetDataTableRowStructType)
PreloadObject ( DataTable ) ;
}
}
2014-06-06 05:27:30 -04:00
UScriptStruct * RowStruct = GetDataTableRowStructType ( & OldPins ) ;
2014-08-21 23:21:25 -04:00
if ( RowStruct ! = NULL )
2014-06-06 05:27:30 -04:00
{
SetReturnTypeForStruct ( RowStruct ) ;
}
}
2014-08-23 20:16:29 -04:00
void UK2Node_GetDataTableRow : : GetMenuActions ( FBlueprintActionDatabaseRegistrar & ActionRegistrar ) const
2014-07-14 16:05:25 -04:00
{
2014-09-10 17:09:26 -04:00
// actions get registered under specific object-keys; the idea is that
// actions might have to be updated (or deleted) if their object-key is
// mutated (or removed)... here we use the node's class (so if the node
// type disappears, then the action should go with it)
UClass * ActionKey = GetClass ( ) ;
// to keep from needlessly instantiating a UBlueprintNodeSpawner, first
// check to make sure that the registrar is looking for actions of this type
// (could be regenerating actions for a specific asset, and therefore the
// registrar would only accept actions corresponding to that asset)
if ( ActionRegistrar . IsOpenForRegistration ( ActionKey ) )
{
UBlueprintNodeSpawner * NodeSpawner = UBlueprintNodeSpawner : : Create ( GetClass ( ) ) ;
check ( NodeSpawner ! = nullptr ) ;
2014-07-14 16:05:25 -04:00
2014-09-10 17:09:26 -04:00
ActionRegistrar . AddBlueprintAction ( ActionKey , NodeSpawner ) ;
}
2014-07-14 16:05:25 -04:00
}
FText UK2Node_GetDataTableRow : : GetMenuCategory ( ) const
{
return FEditorCategoryUtils : : GetCommonCategory ( FCommonEditorCategory : : Utilities ) ;
}
2014-10-14 13:03:29 -04:00
bool UK2Node_GetDataTableRow : : IsConnectionDisallowed ( const UEdGraphPin * MyPin , const UEdGraphPin * OtherPin , FString & OutReason ) const
2014-08-21 23:21:25 -04:00
{
2014-10-14 13:03:29 -04:00
if ( MyPin & & MyPin - > PinName = = UK2Node_GetDataTableRowHelper : : DataTablePinName )
2014-08-21 23:21:25 -04:00
{
2014-10-14 13:03:29 -04:00
OutReason = LOCTEXT ( " OnlyLiteralDTSupported " , " Only literal data table is supported " ) . ToString ( ) ;
return true ;
2014-08-21 23:21:25 -04:00
}
2014-10-14 13:03:29 -04:00
return false ;
2014-08-21 23:21:25 -04:00
}
2014-06-06 05:27:30 -04:00
void UK2Node_GetDataTableRow : : PinDefaultValueChanged ( UEdGraphPin * ChangedPin )
{
2014-08-21 23:21:25 -04:00
if ( ChangedPin & & ChangedPin - > PinName = = UK2Node_GetDataTableRowHelper : : DataTablePinName )
2014-06-06 05:27:30 -04:00
{
UScriptStruct * RowStruct = GetDataTableRowStructType ( ) ;
2014-08-19 02:27:41 -04:00
SetReturnTypeForStruct ( RowStruct ) ;
2014-10-14 13:03:29 -04:00
auto RowNamePin = GetRowNamePin ( ) ;
auto DataTable = Cast < UDataTable > ( ChangedPin - > DefaultObject ) ;
if ( RowNamePin & & RowNamePin - > DefaultValue . IsEmpty ( ) & & DataTable )
{
auto Iterator = DataTable - > RowMap . CreateConstIterator ( ) ;
RowNamePin - > DefaultValue = Iterator ? Iterator . Key ( ) . ToString ( ) : FString ( ) ;
}
2014-06-06 05:27:30 -04:00
}
}
2014-09-03 18:14:09 -04:00
FText UK2Node_GetDataTableRow : : GetTooltipText ( ) const
2014-06-06 05:27:30 -04:00
{
return NodeTooltip ;
}
UEdGraphPin * UK2Node_GetDataTableRow : : GetThenPin ( ) const
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
UEdGraphPin * Pin = FindPinChecked ( K2Schema - > PN_Then ) ;
check ( Pin - > Direction = = EGPD_Output ) ;
return Pin ;
}
UEdGraphPin * UK2Node_GetDataTableRow : : GetDataTablePin ( const TArray < UEdGraphPin * > * InPinsToSearch /*= NULL*/ ) const
{
const TArray < UEdGraphPin * > * PinsToSearch = InPinsToSearch ? InPinsToSearch : & Pins ;
UEdGraphPin * Pin = NULL ;
for ( auto PinIt = PinsToSearch - > CreateConstIterator ( ) ; PinIt ; + + PinIt )
{
UEdGraphPin * TestPin = * PinIt ;
if ( TestPin & & TestPin - > PinName = = UK2Node_GetDataTableRowHelper : : DataTablePinName )
{
Pin = TestPin ;
break ;
}
}
check ( Pin = = NULL | | Pin - > Direction = = EGPD_Input ) ;
return Pin ;
}
UEdGraphPin * UK2Node_GetDataTableRow : : GetRowNamePin ( ) const
{
UEdGraphPin * Pin = FindPinChecked ( UK2Node_GetDataTableRowHelper : : RowNamePinName ) ;
check ( Pin - > Direction = = EGPD_Input ) ;
return Pin ;
}
UEdGraphPin * UK2Node_GetDataTableRow : : GetRowNotFoundPin ( ) const
{
UEdGraphPin * Pin = FindPinChecked ( UK2Node_GetDataTableRowHelper : : RowNotFoundPinName ) ;
check ( Pin - > Direction = = EGPD_Output ) ;
return Pin ;
}
UEdGraphPin * UK2Node_GetDataTableRow : : GetResultPin ( ) const
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
UEdGraphPin * Pin = FindPinChecked ( K2Schema - > PN_ReturnValue ) ;
check ( Pin - > Direction = = EGPD_Output ) ;
return Pin ;
}
FText UK2Node_GetDataTableRow : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
{
2014-09-16 15:01:38 -04:00
if ( TitleType = = ENodeTitleType : : MenuTitle )
2014-07-14 16:05:25 -04:00
{
2014-09-02 19:08:09 -04:00
return LOCTEXT ( " ListViewTitle " , " Get Data Table Row " ) ;
2014-07-14 16:05:25 -04:00
}
2014-09-02 19:08:09 -04:00
else if ( UEdGraphPin * DataTablePin = GetDataTablePin ( ) )
{
if ( DataTablePin - > LinkedTo . Num ( ) > 0 )
{
return NSLOCTEXT ( " K2Node " , " DataTable_Title_Unknown " , " Get Data Table Row " ) ;
}
else if ( DataTablePin - > DefaultObject = = nullptr )
{
return NSLOCTEXT ( " K2Node " , " DataTable_Title_None " , " Get Data Table Row NONE " ) ;
}
2015-04-02 11:16:23 -04:00
else if ( CachedNodeTitle . IsOutOfDate ( this ) )
2014-09-02 19:08:09 -04:00
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " DataTableName " ) , FText : : FromString ( DataTablePin - > DefaultObject - > GetName ( ) ) ) ;
2014-07-14 16:05:25 -04:00
2014-09-02 19:08:09 -04:00
FText LocFormat = NSLOCTEXT ( " K2Node " , " DataTable " , " Get Data Table Row {DataTableName} " ) ;
// FText::Format() is slow, so we cache this to save on performance
2015-04-02 11:16:23 -04:00
CachedNodeTitle . SetCachedText ( FText : : Format ( LocFormat , Args ) , this ) ;
2014-09-02 19:08:09 -04:00
}
}
else
{
return NSLOCTEXT ( " K2Node " , " DataTable_Title_None " , " Get Data Table Row NONE " ) ;
}
return CachedNodeTitle ;
2014-06-06 05:27:30 -04:00
}
void UK2Node_GetDataTableRow : : ExpandNode ( class FKismetCompilerContext & CompilerContext , UEdGraph * SourceGraph )
{
Super : : ExpandNode ( CompilerContext , SourceGraph ) ;
2014-10-17 06:37:11 -04:00
const UEdGraphSchema_K2 * Schema = CompilerContext . GetSchema ( ) ;
UEdGraphPin * OriginalDataTableInPin = GetDataTablePin ( ) ;
UDataTable * Table = ( OriginalDataTableInPin ! = NULL ) ? Cast < UDataTable > ( OriginalDataTableInPin - > DefaultObject ) : NULL ;
if ( ( 0 = = OriginalDataTableInPin - > LinkedTo . Num ( ) ) & & ( NULL = = Table ) )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " GetDataTableRowNoDataTable_Error " , " GetDataTableRow must have a DataTable specified. " ) . ToString ( ) , this ) ;
// we break exec links so this is the only error we get
BreakAllNodeLinks ( ) ;
return ;
}
// FUNCTION NODE
const FName FunctionName = GET_FUNCTION_NAME_CHECKED ( UDataTableFunctionLibrary , GetDataTableRowFromName ) ;
UK2Node_CallFunction * GetDataTableRowFunction = CompilerContext . SpawnIntermediateNode < UK2Node_CallFunction > ( this , SourceGraph ) ;
GetDataTableRowFunction - > FunctionReference . SetExternalMember ( FunctionName , UDataTableFunctionLibrary : : StaticClass ( ) ) ;
GetDataTableRowFunction - > AllocateDefaultPins ( ) ;
CompilerContext . MovePinLinksToIntermediate ( * GetExecPin ( ) , * ( GetDataTableRowFunction - > GetExecPin ( ) ) ) ;
// Connect the input of our GetDataTableRow to the Input of our Function pin
UEdGraphPin * DataTableInPin = GetDataTableRowFunction - > FindPinChecked ( TEXT ( " Table " ) ) ;
if ( OriginalDataTableInPin - > LinkedTo . Num ( ) > 0 )
2014-06-06 05:27:30 -04:00
{
2014-10-17 06:37:11 -04:00
// Copy the connection
CompilerContext . MovePinLinksToIntermediate ( * OriginalDataTableInPin , * DataTableInPin ) ;
2014-06-06 05:27:30 -04:00
}
2014-10-17 06:37:11 -04:00
else
{
// Copy literal
DataTableInPin - > DefaultObject = OriginalDataTableInPin - > DefaultObject ;
}
UEdGraphPin * RowNameInPin = GetDataTableRowFunction - > FindPinChecked ( TEXT ( " RowName " ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * GetRowNamePin ( ) , * RowNameInPin ) ;
// Get some pins to work with
UEdGraphPin * OriginalOutRowPin = FindPinChecked ( Schema - > PN_ReturnValue ) ;
UEdGraphPin * FunctionOutRowPin = GetDataTableRowFunction - > FindPinChecked ( TEXT ( " OutRow " ) ) ;
UEdGraphPin * FunctionReturnPin = GetDataTableRowFunction - > FindPinChecked ( Schema - > PN_ReturnValue ) ;
UEdGraphPin * FunctionThenPin = GetDataTableRowFunction - > GetThenPin ( ) ;
// Set the type of the OutRow pin on this expanded mode to match original
FunctionOutRowPin - > PinType = OriginalOutRowPin - > PinType ;
FunctionOutRowPin - > PinType . PinSubCategoryObject = OriginalOutRowPin - > PinType . PinSubCategoryObject ;
//BRANCH NODE
UK2Node_IfThenElse * BranchNode = CompilerContext . SpawnIntermediateNode < UK2Node_IfThenElse > ( this , SourceGraph ) ;
BranchNode - > AllocateDefaultPins ( ) ;
// Hook up inputs to branch
FunctionThenPin - > MakeLinkTo ( BranchNode - > GetExecPin ( ) ) ;
FunctionReturnPin - > MakeLinkTo ( BranchNode - > GetConditionPin ( ) ) ;
// Hook up outputs
CompilerContext . MovePinLinksToIntermediate ( * GetThenPin ( ) , * ( BranchNode - > GetThenPin ( ) ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * GetRowNotFoundPin ( ) , * ( BranchNode - > GetElsePin ( ) ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * OriginalOutRowPin , * FunctionOutRowPin ) ;
BreakAllNodeLinks ( ) ;
2014-06-06 05:27:30 -04:00
}
2014-11-26 06:26:02 -05:00
void UK2Node_GetDataTableRow : : EarlyValidation ( class FCompilerResultsLog & MessageLog ) const
2014-11-25 09:36:31 -05:00
{
const auto DataTablePin = GetDataTablePin ( ) ;
const auto RowNamePin = GetRowNamePin ( ) ;
if ( ! DataTablePin | | ! RowNamePin )
{
MessageLog . Error ( * LOCTEXT ( " MissingPins " , " Missing pins in @@ " ) . ToString ( ) , this ) ;
return ;
}
const auto DataTable = Cast < UDataTable > ( DataTablePin - > DefaultObject ) ;
if ( ! DataTable )
{
MessageLog . Error ( * LOCTEXT ( " NoDataTable " , " No DataTable in @@ " ) . ToString ( ) , this ) ;
return ;
}
2014-11-26 06:26:02 -05:00
if ( ! RowNamePin - > LinkedTo . Num ( ) )
2014-11-25 09:36:31 -05:00
{
2014-11-26 06:26:02 -05:00
const FName CurrentName = FName ( * RowNamePin - > GetDefaultAsString ( ) ) ;
if ( ! DataTable - > GetRowNames ( ) . Contains ( CurrentName ) )
{
const FString Msg = FString : : Printf (
* LOCTEXT ( " WronRowName " , " '%s' row name is not stored in '%s'. @@ " ) . ToString ( )
, * CurrentName . ToString ( )
, * GetFullNameSafe ( DataTable ) ) ;
MessageLog . Error ( * Msg , this ) ;
return ;
}
2014-11-25 09:36:31 -05:00
}
}
2014-06-06 05:27:30 -04:00
# undef LOCTEXT_NAMESPACE