An unidentified "Document" tab is being created

There was a problem when repeating the BehaviorTreeEditor module. For some reason, the “Document” tab is called. As I managed to find out, an additional area is being created somewhere. This can be seen in the EditorLayout.json, despite the unambiguity of the mod and its Layout.

During the study, it was revealed that when finding this Layout in the config(EditorLayout.json), it loads all the information from there. However, even when cleaning, there are no changes.

What does the problem look like:

In addition, the tabs are not attached yet. However, in the other mode (Inkwell) everything works as it should:

The logs also show that something should have happened, but it didn’t work out:

The tab "Document" attempted to spawn in layout 'Standalone_NarrativeTree_Layout_v1' but failed for some reason. An "unrecognized tab" will be returned instead.

EditorInit:

void FNarrativeTreeEditor::InitNarrativeTreeEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost,
    UObject* InObject)
{
    UE_LOG(LogNarrativeTreeEditor, Log, TEXT("InitNarrativeTreeEditor"));

    auto* NarrativeTreeToEdit = Cast<UNarrativeTree>(InObject);
    if (NarrativeTreeToEdit)
    {
        NarrativeTree = NarrativeTreeToEdit;
    }

    TSharedPtr<FNarrativeTreeEditor> ThisPtr(SharedThis(this));
    if (!DocumentManager.IsValid())
    {
        DocumentManager = MakeShareable(new FDocumentTracker);
        DocumentManager->Initialize(ThisPtr);

        // Register the document factories
        TSharedRef<FDocumentTabFactory> GraphEditorFactory = MakeShareable(new FNTGraphEditorSummoner(
            ThisPtr,
            FNTGraphEditorSummoner::FOnCreateGraphEditorWidget::CreateSP(this, &FNarrativeTreeEditor::CreateGraphEditorWidget)));

        GraphEditorTabFactoryPtr = GraphEditorFactory;
        DocumentManager->RegisterDocumentFactory(GraphEditorFactory);
    }

    TArray<UObject*> ObjectsToEdit;
    if (NarrativeTree)
    {
        ObjectsToEdit.Add(NarrativeTree);
    }

    if (!ToolbarBuilder.IsValid())
    {
        ToolbarBuilder = MakeShareable(new FNarrativeTreeEditorToolbar(ThisPtr));
    }

    const TArray<UObject*>* EditedObjects = GetObjectsCurrentlyBeingEdited();
    if (!EditedObjects || EditedObjects->Num() == 0)
    {
        FGraphEditorCommands::Register();

        InitAssetEditor(
            Mode,
            InitToolkitHost,
            FNarrativeTreeEditorModule::NarrativeTreeEditorAppIdentifier,
            FTabManager::FLayout::NullLayout,
            true,
            true,
            ObjectsToEdit);

        FNarrativeTreeEditorModule& NarrativeTreeEditorModule = FModuleManager::LoadModuleChecked<FNarrativeTreeEditorModule>(
            "NarrativeTreeEditor");
        AddMenuExtender(
            NarrativeTreeEditorModule.GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));

        AddApplicationMode(NarrativeTreeMode, MakeShareable(new FNarrativeTreeEditorApplicationMode(ThisPtr)));
        AddApplicationMode(InkwellMode, MakeShareable(new FInkwellEditorApplicationMode(ThisPtr)));
    }
    else
    {
        for (UObject* ObjectToEdit : ObjectsToEdit)
        {
            if (!EditedObjects->Contains(ObjectToEdit))
            {
                AddEditingObject(ObjectToEdit);
            }
        }
    }

    if (NarrativeTreeToEdit)
    {
        SetCurrentMode(NarrativeTreeMode);
    }

    RegenerateMenusAndToolbars();
}

Mode:

FNarrativeTreeEditorApplicationMode::FNarrativeTreeEditorApplicationMode(TSharedPtr<FNarrativeTreeEditor> InNarrativeTreeEditor)
    : FApplicationMode(FNarrativeTreeEditor::NarrativeTreeMode, FNarrativeTreeEditor::GetLocalizedMode)
{
    NarrativeTreeEditor = InNarrativeTreeEditor;

    TabLayout = FTabManager::NewLayout("Standalone_NarrativeTree_Layout_v1")
        ->AddArea
        (
            FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
                                         ->Split
                                         (

                                             FTabManager::NewStack()
                                             ->AddTab(FNarrativeTreeEditorTabs::GraphEditorID,
                                                 ETabState::ClosedTab)

                                             )
            );

    InNarrativeTreeEditor->GetToolbarBuilder()->AddModesToolbar(ToolbarExtender);
    InNarrativeTreeEditor->GetToolbarBuilder()->AddNarrativeTreeToolbar(ToolbarExtender);
}

EditorLayout.json:

"Standalone_NarrativeTree_Layout_v1":
	{
		"Type": "Layout",
		"Name": "Standalone_NarrativeTree_Layout_v1",
		"PrimaryAreaIndex": 0,
		"Areas": [
			{
				"SizeCoefficient": 1,
				"Type": "Area",
				"Orientation": "Orient_Vertical",
				"WindowPlacement": "Placement_NoWindow",
				"Nodes": [
					{
						"SizeCoefficient": 1,
						"Type": "Stack",
						"HideTabWell": false,
						"ForegroundTab": "None",
						"Tabs": [
							{
								"TabId": "NarrativeTreeGraph",
								"TabState": "ClosedTab"
							}
						]
					}
				]
			},
			{
				"SizeCoefficient": 1,
				"Type": "Area",
				"Orientation": "Orient_Horizontal",
				"WindowPlacement": "Placement_Specified",
				"WindowPosition_X": 457,
				"WindowPosition_Y": 217,
				"WindowSize_X": 1000,
				"WindowSize_Y": 600,
				"bIsMaximized": false,
				"Nodes": [
					{
						"SizeCoefficient": 1,
						"Type": "Stack",
						"HideTabWell": false,
						"ForegroundTab": "Document",
						"Tabs": [
							{
								"TabId": "Document",
								"TabState": "OpenedTab"
							}
						]
					}
				]
			}
		]
	}

It seems that the problem lies in the difference of tab summoners. However, everything works in the reference version, and as I understand it, this class is necessary for graphs:

struct FInkwellEditorSummoner : public FWorkflowTabFactory
{
public:
    FInkwellEditorSummoner(TSharedPtr<class FNarrativeTreeEditor> InNarrativeTreeEditorPtr);

    virtual TSharedRef<SWidget> CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override;
    virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override;

protected:
    TWeakPtr<class FNarrativeTreeEditor> NarrativeTreeEditorPtr;
};

struct FNTGraphEditorSummoner : public FDocumentTabFactoryForObjects<UEdGraph>
{
public:
    DECLARE_DELEGATE_RetVal_OneParam(TSharedRef<SGraphEditor>, FOnCreateGraphEditorWidget, UEdGraph*);
public:
    FNTGraphEditorSummoner(TSharedPtr<class FNarrativeTreeEditor> InNarrativeTreeEditorPtr, FOnCreateGraphEditorWidget CreateGraphEditorWidgetCallback);

    virtual void OnTabActivated(TSharedPtr<SDockTab> Tab) const override;
    virtual void OnTabRefreshed(TSharedPtr<SDockTab> Tab) const override;

protected:
    virtual TAttribute<FText> ConstructTabNameForObject(UEdGraph* DocumentID) const override;
    virtual TSharedRef<SWidget> CreateTabBodyForObject(const FWorkflowTabSpawnInfo& Info, UEdGraph* DocumentID) const override;
    virtual const FSlateBrush* GetTabIconForObject(const FWorkflowTabSpawnInfo& Info, UEdGraph* DocumentID) const override;
    virtual void SaveState(TSharedPtr<SDockTab> Tab, TSharedPtr<FTabPayload> Payload) const override;

protected:
    TWeakPtr<class FNarrativeTreeEditor> NarrativeTreeEditorPtr;
    FOnCreateGraphEditorWidget OnCreateGraphEditorWidget;
};
  1. Besides.there were json and .ini configs. in %AppData%/Local and in Engine\Saved\Config\WindowsEditor.
  2. Graph creates a placeholder, and its name was “Document”. The tab identifier is required to be “Document”. This was exactly the problem, my identifier was different and could not replace the placeholder.
TSharedPtr<SDockTab> FDocumentTracker::OpenNewTab(TSharedPtr<FGenericTabHistory> InTabHistory, EOpenDocumentCause InOpenCause)
{

...

if (InOpenCause == ForceOpenNewDocument  || InOpenCause == OpenNewDocument)
		{
			TabManager->InsertNewDocumentTab( "Document", FTabManager::ESearchPreference::RequireClosedTab, NewTab.ToSharedRef() );
		}
		else if (InOpenCause == RestorePreviousDocument)
		{
			TabManager->RestoreDocumentTab( "Document", FTabManager::ESearchPreference::RequireClosedTab, NewTab.ToSharedRef() );

			// Clear tab history before this so previous restores don't show up
			History.RemoveAt(0, History.Num() - 1, true);
			CurrentHistoryIndex = History.Num() - 1;
		}

...

}