Files
UnrealEngine/Engine/Source/Developer/MessageLog/Public/Model/MessageLogListingModel.h
2025-05-18 13:04:45 +08:00

185 lines
6.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Containers/List.h"
#include "Logging/TokenizedMessage.h"
#define UE_API MESSAGELOG_API
/** Define the container type for all the messages */
typedef TArray< TSharedRef<FTokenizedMessage> > MessageContainer;
/** This class represents a set of rich tokenized messages for a particular system */
class FMessageLogListingModel : public TSharedFromThis< FMessageLogListingModel >
{
protected:
struct FPage
{
FPage( const FText& InTitle )
: Title( InTitle )
{
}
/** The title of this page */
FText Title;
/** The list of messages in this log listing */
MessageContainer Messages;
TSet<uint32> MessagesHashes;
};
public:
virtual ~FMessageLogListingModel() {}
/**
* Factory method which creates a new FMessageLogListingModel object
*
* @param InLogName The name of the log
*/
static TSharedRef< FMessageLogListingModel > Create( const FName& InLogName )
{
TSharedRef< FMessageLogListingModel > NewLogListing( new FMessageLogListingModel( InLogName ) );
return NewLogListing;
}
/** Broadcasts whenever the message log listing changes */
DECLARE_EVENT( FMessageLogListingModel, FChangedEvent )
FChangedEvent& OnChanged() { return ChangedEvent; }
/** Retrieves the name identifier for this log listing */
const FName& GetName() const { return LogName; }
/** Returns the message at the specified index */
UE_API const TSharedPtr<FTokenizedMessage> GetMessageAtIndex( const uint32 PageIndex, const int32 MessageIndex ) const;
/** Gets all messages as a string */
UE_API FString GetAllMessagesAsString(const uint32 PageIndex) const;
/** Obtains a const iterator to the message data structure */
UE_API MessageContainer::TConstIterator GetMessageIterator(uint32 PageIndex) const;
/** Replaces the message at the given index */
UE_API int32 ReplaceMessage( const TSharedRef< FTokenizedMessage >& NewMessage, const uint32 PageIndex, const int32 MessageIndex );
/** Appends a message */
UE_API void AddMessage( const TSharedRef< FTokenizedMessage >& NewMessage, bool bMirrorToOutputLog = true, bool bDiscardDuplicates = false );
/** Appends multiple messages */
UE_API void AddMessages( const TArray< TSharedRef< FTokenizedMessage > >& NewMessages, bool bMirrorToOutputLog = true, bool bDiscardDuplicates = false );
/** Clears all messages */
UE_API void ClearMessages();
/**
* Add a new page. Old pages are only kept around if they contain messages, so if the current
* page is empty, this call does nothing.
* @param InTitle The title that will be displayed for this page.
* @param InMaxPages The maximum number of pages we keep around. If the count is exceeded,
* we discard the oldest page.
*/
UE_API void NewPage( const FText& InTitle, uint32 InMaxPages );
/**
* Sets the current page to the one specified by the title. If the page does not exist, creates a new page.
* @param InTitle The title of the page to search for, or create
* @param InMaxPages The maximum number of pages we keep around. If the count is exceeded,
* we discard the oldest page.
* @returns true if the page has changed (either switched or created a new one).
*/
UE_API bool SetCurrentPage( const FText& InTitle, uint32 InMaxPages );
/**
* Sets the current page to the one specified by the index. If the page does not exist, creates a new page.
* The page will move to index 0.
* @param InTitle The title of the page to search for, or create
* @param InMaxPages The maximum number of pages we keep around. If the count is exceeded,
* we discard the oldest page.
* @returns true if the page has changed (either switched or created a new one).
*/
UE_API bool SetCurrentPage( const uint32 InOldPageIndex );
/** Get the number of pages contained in this log */
UE_API uint32 NumPages() const;
/** Get the number of messages on the passed-in page */
UE_API uint32 NumMessages( uint32 PageIndex ) const;
/**
* Get the title of the page at the specified index
* @param PageIndex The index of the page
*/
UE_API const FText& GetPageTitle( const uint32 PageIndex ) const;
/** Helper function for RemoveDuplicates(), exposed so the ViewModel can use it too */
static UE_API bool AreMessagesEqual(const TSharedRef< FTokenizedMessage >& Message0, const TSharedRef< FTokenizedMessage >& Message1);
/** Remove any messages that are duplicates of one another - O(n) */
UE_API void RemoveDuplicates(uint32 PageIndex);
protected:
/** Will broadcast to all registered observers informing them of a change */
virtual void Notify() { ChangedEvent.Broadcast(); }
/** Access the current page (we only add messages to this page */
UE_API FPage& CurrentPage() const;
/** Get a page by index - uses cache to speed up linked list access */
UE_API FPage* PageAtIndex(const uint32 PageIndex) const;
/** Create a new page if we have one pending */
UE_API void CreateNewPageIfRequired();
private:
/**
* FMessageLogListingModel Constructor
*
* @param InLogName The name of the log
*/
FMessageLogListingModel( const FName& InLogName )
: LogName( InLogName )
, bIsPrintingToOutputLog( false )
{
check( LogName != NAME_None );
// create default page
Pages.AddTail(FPage(FText::FromName(LogName)));
CachedPage = &Pages.GetTail()->GetValue();
CachedPageIndex = 0;
}
/** Helper function for AddMessage and AddMessages */
UE_API void AddMessageInternal( const TSharedRef<FTokenizedMessage>& NewMessage, bool bMirrorToOutputLog, bool bDiscardDuplicates );
private:
/** The name of a pending page */
FText PendingPageName;
/** The cap on the number of pages we have */
uint32 MaxPages;
/** The list of pages in this log listing */
TDoubleLinkedList<FPage> Pages;
/** Name of the listing, for identification */
FName LogName;
/** Delegate to call when data is changed */
FChangedEvent ChangedEvent;
// Are we currently processing the output log mirror? If so, we drop any additional messages we receive, as they are duplicates
bool bIsPrintingToOutputLog;
/** Cached page index */
mutable uint32 CachedPageIndex;
/** Cached page */
mutable FPage* CachedPage;
};
#undef UE_API