You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
[FYI] Steve.Robb Original CL Desc ----------------------------------------------------------------- TMap and TSet can now be declared as members with forward-declared key and value parameters. KeyFuncs::KeyInitType and KeyFuncs::ElementInitType typedefs are no longer used and user-defined KeyFuncs do not need to provide them. Deprecated placeholders for these typedefs exist though they may not be defined exactly as they were before. A new KeyType typedef needs to be provided by custom KeyFuncs which don't already inherit from BaseKeyFuncs or TDefaultMapKeyFuncs. KeyConstPointerType, KeyInitType, ValueInitType and ElementInitType typedefs have been deprecated across TMap, TSet and TSortedMap. Regular C++ parameter-passing semantics should be used instead (const T& Ref or T Value, depending on T). Added missing FSetElementId::operator!=(). [FYI] steve.robb #rb james.hopkin [FYI] henrik.karlsson #preflight 635a56c15d49a96f7b31938f [CL 22850782 by graeme thornton in ue5-main branch]
298 lines
7.7 KiB
C++
298 lines
7.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Model/MessageLogListingModel.h"
|
|
#include "Logging/MessageLog.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "Developer.MessageLog"
|
|
|
|
|
|
MessageContainer::TConstIterator FMessageLogListingModel::GetMessageIterator(const uint32 PageIndex) const
|
|
{
|
|
return PageAtIndex(PageIndex)->Messages.CreateConstIterator();
|
|
}
|
|
|
|
const TSharedPtr< FTokenizedMessage > FMessageLogListingModel::GetMessageAtIndex( const uint32 PageIndex, const int32 MessageIndex ) const
|
|
{
|
|
TSharedPtr<FTokenizedMessage> FoundMessage = nullptr;
|
|
FPage* Page = PageAtIndex(PageIndex);
|
|
if( Page->Messages.IsValidIndex( MessageIndex ) )
|
|
{
|
|
FoundMessage = Page->Messages[MessageIndex];
|
|
}
|
|
return FoundMessage;
|
|
}
|
|
|
|
FString FMessageLogListingModel::GetAllMessagesAsString( const uint32 PageIndex ) const
|
|
{
|
|
// Go through all the messages and add it to the compiled one.
|
|
FPage* Page = PageAtIndex(PageIndex);
|
|
TArray<FString> AllLines;
|
|
for( int32 MessageID = 0; MessageID < Page->Messages.Num(); MessageID++ )
|
|
{
|
|
AllLines.Add(Page->Messages[ MessageID ]->ToText().ToString());
|
|
}
|
|
|
|
return FString::Join(AllLines, TEXT("\n"));
|
|
}
|
|
|
|
void FMessageLogListingModel::AddMessageInternal( const TSharedRef<FTokenizedMessage>& NewMessage, bool bMirrorToOutputLog, bool bDiscardDuplicates )
|
|
{
|
|
if (bIsPrintingToOutputLog)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (bDiscardDuplicates)
|
|
{
|
|
bool bIsAlreadyInSet;
|
|
CurrentPage().MessagesHashes.Add(GetTypeHash(NewMessage->ToText().ToString()), &bIsAlreadyInSet);
|
|
if (bIsAlreadyInSet)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
CurrentPage().Messages.Add( NewMessage );
|
|
|
|
if (bMirrorToOutputLog)
|
|
{
|
|
// Prevent re-entrancy from the output log to message log mirroring code
|
|
TGuardValue<bool> PrintToOutputLogBool(bIsPrintingToOutputLog, true);
|
|
|
|
const TCHAR* const LogColor = FMessageLog::GetLogColor(NewMessage->GetSeverity());
|
|
if (LogColor)
|
|
{
|
|
SET_WARN_COLOR(LogColor);
|
|
}
|
|
|
|
FMsg::Logf(__FILE__, __LINE__, *LogName.ToString(), FMessageLog::GetLogVerbosity(NewMessage->GetSeverity()), TEXT("%s"), *NewMessage->ToText().ToString());
|
|
|
|
CLEAR_WARN_COLOR();
|
|
}
|
|
}
|
|
|
|
void FMessageLogListingModel::AddMessage( const TSharedRef<FTokenizedMessage>& NewMessage, bool bMirrorToOutputLog, bool bDiscardDuplicates )
|
|
{
|
|
CreateNewPageIfRequired();
|
|
|
|
AddMessageInternal( NewMessage, bMirrorToOutputLog, bDiscardDuplicates );
|
|
|
|
Notify();
|
|
}
|
|
|
|
void FMessageLogListingModel::AddMessages( const TArray< TSharedRef<class FTokenizedMessage> >& NewMessages, bool bMirrorToOutputLog, bool bDiscardDuplicates )
|
|
{
|
|
CreateNewPageIfRequired();
|
|
|
|
for( int32 MessageIdx = 0; MessageIdx < NewMessages.Num(); MessageIdx++ )
|
|
{
|
|
AddMessageInternal( NewMessages[MessageIdx], bMirrorToOutputLog, bDiscardDuplicates );
|
|
}
|
|
Notify();
|
|
}
|
|
|
|
void FMessageLogListingModel::ClearMessages()
|
|
{
|
|
CurrentPage().Messages.Empty();
|
|
CurrentPage().MessagesHashes.Empty();
|
|
Notify();
|
|
}
|
|
|
|
void FMessageLogListingModel::NewPage( const FText& InTitle, uint32 InMaxPages )
|
|
{
|
|
FMsg::Logf(__FILE__, __LINE__, *LogName.ToString(), ELogVerbosity::Log, TEXT("New page: %s"), *InTitle.ToString());
|
|
|
|
// store the name of the page we will add if a new message is pushed
|
|
PendingPageName = InTitle;
|
|
MaxPages = InMaxPages;
|
|
|
|
// if the current output page has messages, we create a new page now
|
|
if( CurrentPage().Messages.Num() > 0 )
|
|
{
|
|
CreateNewPageIfRequired();
|
|
}
|
|
}
|
|
|
|
bool FMessageLogListingModel::SetCurrentPage(const FText& InTitle, uint32 InMaxPages )
|
|
{
|
|
if (CurrentPage().Title.CompareTo(InTitle) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (TDoubleLinkedList<FPage>::TIterator it = begin(Pages); it != end(Pages); ++it)
|
|
{
|
|
if (it.GetNode()->GetValue().Title.CompareTo(InTitle) == 0)
|
|
{
|
|
TDoubleLinkedList<FPage>::TDoubleLinkedListNode* SelectedNode = it.GetNode();
|
|
Pages.RemoveNode(SelectedNode, false);
|
|
Pages.AddHead(SelectedNode);
|
|
|
|
// invalidate cache as all indices will change
|
|
CachedPage = nullptr;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If the page does not exist yet, create a new one
|
|
NewPage(InTitle, InMaxPages);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FMessageLogListingModel::SetCurrentPage( const uint32 InOldPageIndex )
|
|
{
|
|
if (InOldPageIndex == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (InOldPageIndex >= NumPages())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FPage* PageToSwitch = PageAtIndex(InOldPageIndex);
|
|
return SetCurrentPage(PageToSwitch->Title, MaxPages);
|
|
}
|
|
|
|
uint32 FMessageLogListingModel::NumPages() const
|
|
{
|
|
return Pages.Num();
|
|
}
|
|
|
|
uint32 FMessageLogListingModel::NumMessages( uint32 PageIndex ) const
|
|
{
|
|
return PageAtIndex(PageIndex)->Messages.Num();
|
|
}
|
|
|
|
FMessageLogListingModel::FPage& FMessageLogListingModel::CurrentPage() const
|
|
{
|
|
check(Pages.Num() > 0);
|
|
return Pages.GetHead()->GetValue();
|
|
}
|
|
|
|
FMessageLogListingModel::FPage* FMessageLogListingModel::PageAtIndex(const uint32 PageIndex) const
|
|
{
|
|
check(PageIndex < (uint32)Pages.Num());
|
|
if(CachedPage != nullptr && CachedPageIndex == PageIndex)
|
|
{
|
|
return CachedPage;
|
|
}
|
|
else
|
|
{
|
|
uint32 CurrentIndex = 0;
|
|
for(auto Node = Pages.GetHead(); Node; Node = Node->GetNextNode())
|
|
{
|
|
if(CurrentIndex == PageIndex)
|
|
{
|
|
CachedPage = &Node->GetValue();
|
|
CachedPageIndex = CurrentIndex;
|
|
return CachedPage;
|
|
}
|
|
CurrentIndex++;
|
|
}
|
|
}
|
|
|
|
check(false); // Should never get here!
|
|
return nullptr;
|
|
}
|
|
|
|
const FText& FMessageLogListingModel::GetPageTitle( const uint32 PageIndex ) const
|
|
{
|
|
return PageAtIndex(PageIndex)->Title;
|
|
}
|
|
|
|
void FMessageLogListingModel::CreateNewPageIfRequired()
|
|
{
|
|
if(!PendingPageName.IsEmpty())
|
|
{
|
|
// dont create a new page if the current is empty, just change its name
|
|
if(CurrentPage().Messages.Num() != 0)
|
|
{
|
|
// remove any pages that exceed the max page count
|
|
while(Pages.Num() >= (int32)MaxPages)
|
|
{
|
|
Pages.RemoveNode(Pages.GetTail());
|
|
}
|
|
Pages.AddHead(FPage(PendingPageName));
|
|
|
|
// invalidate cache as all indices will change
|
|
CachedPage = nullptr;
|
|
}
|
|
else
|
|
{
|
|
CurrentPage().Title = PendingPageName;
|
|
}
|
|
|
|
PendingPageName = FText::GetEmpty();
|
|
}
|
|
}
|
|
|
|
bool FMessageLogListingModel::AreMessagesEqual(const TSharedRef< FTokenizedMessage >& MessageA, const TSharedRef< FTokenizedMessage >& MessageB)
|
|
{
|
|
if(MessageA->GetMessageTokens().Num() == MessageB->GetMessageTokens().Num())
|
|
{
|
|
auto TokenItA(MessageA->GetMessageTokens().CreateConstIterator());
|
|
auto TokenItB(MessageB->GetMessageTokens().CreateConstIterator());
|
|
for( ; TokenItA && TokenItB; ++TokenItA, ++TokenItB)
|
|
{
|
|
TSharedRef<IMessageToken> TokenA = *TokenItA;
|
|
TSharedRef<IMessageToken> TokenB = *TokenItB;
|
|
if ( TokenA->GetType() != TokenB->GetType() || !TokenA->ToText().EqualTo( TokenB->ToText() ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Specialized KeyFunc for TSharedRef<FTokenizedMessage> usage in TSet
|
|
struct FTokenizedMessageKeyFunc
|
|
{
|
|
typedef typename TCallTraits<TSharedRef<FTokenizedMessage>>::ParamType KeyInitType;
|
|
typedef typename TCallTraits<TSharedRef<FTokenizedMessage>>::ParamType ElementInitType;
|
|
|
|
enum { bAllowDuplicateKeys = false };
|
|
|
|
static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
|
|
{
|
|
return Element;
|
|
}
|
|
|
|
static FORCEINLINE bool Matches(KeyInitType A, KeyInitType B)
|
|
{
|
|
return FMessageLogListingModel::AreMessagesEqual(A, B);
|
|
}
|
|
|
|
static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
|
|
{
|
|
return GetTypeHash(Key->ToText().ToString());
|
|
}
|
|
};
|
|
|
|
void FMessageLogListingModel::RemoveDuplicates(uint32 PageIndex)
|
|
{
|
|
FPage* Page = PageAtIndex(PageIndex);
|
|
|
|
if (Page != nullptr && Page->Messages.Num() > 0)
|
|
{
|
|
TSet<TSharedRef<FTokenizedMessage>, FTokenizedMessageKeyFunc> MessageSet(Page->Messages);
|
|
Page->Messages = MessageSet.Array();
|
|
|
|
// Also needs to rebuild array of hashes
|
|
Page->MessagesHashes.Empty(Page->Messages.Num());
|
|
for(int32 MessageID = 0; MessageID < Page->Messages.Num(); MessageID++)
|
|
{
|
|
const TSharedPtr< FTokenizedMessage > Message = Page->Messages[MessageID];
|
|
Page->MessagesHashes.Add(GetTypeHash(Message->ToText().ToString()));
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|