Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Source/LoreSourceControl/LoreSourceControl.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public LoreSourceControl(ReadOnlyTargetRules Target) : base(Target)
"DesktopWidgets",
"DeveloperSettings",
"Engine",
"InputCore",
"Json",
"MainFrame",
"SourceControl",
Expand Down
94 changes: 92 additions & 2 deletions Source/LoreSourceControl/Private/LoreSourceControlModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "LoreSourceControlOperations.h"
#include "LoreSourceControlProvider.h"
#include "LoreSourceControlUtils.h"
#include "SLoreBranchHistory.h"
#include "Misc/App.h"
#include "Modules/ModuleManager.h"
#include "Features/IModularFeatures.h"
Expand All @@ -20,7 +21,9 @@
#include "Logging/MessageLog.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/Docking/TabManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/SWindow.h"
#include "Widgets/Input/SComboButton.h"
#include "Widgets/Layout/SScrollBox.h"
Expand All @@ -43,6 +46,7 @@
#define LOCTEXT_NAMESPACE "LoreSourceControl"

#if SOURCE_CONTROL_WITH_SLATE
static const FName LoreBranchHistoryTabName(TEXT("LoreSourceControl.BranchHistory"));
static TWeakPtr<SNotificationItem> ShowLoreProgressNotification(const FText& Text)
{
FNotificationInfo Info(Text);
Expand Down Expand Up @@ -108,6 +112,7 @@ void FLoreSourceControlModule::StartupModule()
LoreSourceControlProvider.RegisterWorker("Unlock", FLoreGetSourceControlWorker::CreateStatic(&CreateLoreWorker<FLoreUnlockWorker>));
LoreSourceControlProvider.RegisterWorker("LorePrintStatus", FLoreGetSourceControlWorker::CreateStatic(&CreateLoreWorker<FLorePrintStatusWorker>));
LoreSourceControlProvider.RegisterWorker("LoreRefreshBranches", FLoreGetSourceControlWorker::CreateStatic(&CreateLoreWorker<FLoreRefreshBranchesWorker>));
LoreSourceControlProvider.RegisterWorker("LoreRefreshBranchHistory", FLoreGetSourceControlWorker::CreateStatic(&CreateLoreWorker<FLoreRefreshBranchHistoryWorker>));
LoreSourceControlProvider.RegisterWorker("LoreSwitchBranch", FLoreGetSourceControlWorker::CreateStatic(&CreateLoreWorker<FLoreSwitchBranchWorker>));

// Load settings (binary path, etc.)
Expand Down Expand Up @@ -159,8 +164,7 @@ void FLoreSourceControlModule::StartupModule()
#if SOURCE_CONTROL_WITH_SLATE
if (ISourceControlModule::Get().GetProvider().GetName() == LoreSourceControlProvider.GetName())
{
// Same dialog as the toolbar's "Submit Content" - drives our CheckIn worker and pushes when a remote is configured.
FSourceControlWindows::ChoosePackagesToCheckIn();
OpenLoreCommitDialog();
}
#endif
}),
Expand All @@ -173,6 +177,19 @@ void FLoreSourceControlModule::StartupModule()
if (FSlateApplication::IsInitialized())
{
FLoreSourceControlCommands::Register();
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(
LoreBranchHistoryTabName,
FOnSpawnTab::CreateRaw(this, &FLoreSourceControlModule::SpawnBranchHistoryTab))
.SetDisplayName(LOCTEXT("LoreBranchHistoryTabTitle", "Branch History"))
.SetTooltipText(LOCTEXT("LoreBranchHistoryTabTooltip", "View revisions on the current Lore branch"))
.SetIcon(FSlateIcon(FRevisionControlStyleManager::GetStyleSetName(), "RevisionControl.ChangelistsTab"))
.SetMenuType(ETabSpawnerMenuType::Hidden);

LoreBranchHistoryCommand = IConsoleManager::Get().RegisterConsoleCommand(
TEXT("LoreSourceControl.FocusBranchHistory"),
TEXT("Open the Lore branch history tab."),
FConsoleCommandDelegate::CreateRaw(this, &FLoreSourceControlModule::ShowBranchHistoryTab),
ECVF_Default);

// The engine's own Revision Control widget registers inside SStatusBar::Construct(), which only runs once the level editor's main tab is built - well after this module loads.
// Registering via UToolMenus::RegisterStartupCallback (module load time) would be too early for that widget to exist yet, so wait for the main frame instead.
Expand Down Expand Up @@ -220,6 +237,12 @@ void FLoreSourceControlModule::ShutdownModule()
LoreCommitCommand = nullptr;
}

if (LoreBranchHistoryCommand)
{
ConsoleManager.UnregisterConsoleObject(LoreBranchHistoryCommand, false);
LoreBranchHistoryCommand = nullptr;
}

#if SOURCE_CONTROL_WITH_SLATE
if (IMainFrameModule* MainFrameModule = FModuleManager::GetModulePtr<IMainFrameModule>("MainFrame"))
{
Expand All @@ -231,6 +254,7 @@ void FLoreSourceControlModule::ShutdownModule()

if (FSlateApplication::IsInitialized())
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(LoreBranchHistoryTabName);
if (const TSharedPtr<SNotificationItem> Notification = SyncNotification.Pin())
{
Notification->ExpireAndFadeout();
Expand Down Expand Up @@ -307,6 +331,7 @@ void FLoreSourceControlModule::RefreshToolbarExtension() const
{
if (UToolMenus* ToolMenus = UToolMenus::TryGet())
{
ToolMenus->RefreshMenuWidget(TEXT("StatusBar.ToolBar.SourceControl"));
for (const FName& MenuName : RegisteredToolbarMenus)
{
ToolMenus->RefreshMenuWidget(MenuName);
Expand All @@ -316,6 +341,7 @@ void FLoreSourceControlModule::RefreshToolbarExtension() const

void FLoreSourceControlModule::RegisterToolbarExtension()
{
RegisterRevisionControlMenuExtension();
RegisterToolbarExtensionForMenu(TEXT("LevelEditor.StatusBar.ToolBar"));

// Asset editors (Blueprint, Material, etc.) don't share the level editor's status bar and have no fixed menu name to register against ahead of time.
Expand All @@ -329,6 +355,70 @@ void FLoreSourceControlModule::RegisterToolbarExtension()
}
}

void FLoreSourceControlModule::RegisterRevisionControlMenuExtension()
{
if (bRevisionControlMenuRegistered)
{
return;
}

FToolMenuOwnerScoped OwnerScoped(this);
UToolMenu* Menu = UToolMenus::Get()->ExtendMenu(TEXT("StatusBar.ToolBar.SourceControl"));
if (!Menu)
{
return;
}

bRevisionControlMenuRegistered = true;
FToolMenuSection& Section = Menu->FindOrAddSection(TEXT("SourceControlActions"));
Section.AddDynamicEntry(TEXT("LoreCommitChanges"), FNewToolMenuSectionDelegate::CreateLambda([this](FToolMenuSection& InSection)
{
const bool bLoreIsActiveProvider = ISourceControlModule::Get().GetProvider().GetName() == LoreSourceControlProvider.GetName();
if (!bLoreIsActiveProvider || !LoreSourceControlProvider.IsAvailable())
{
return;
}

InSection.AddMenuEntry(
TEXT("LoreCommitChanges"),
LOCTEXT("LoreCommitChanges", "View / Commit Changes..."),
LOCTEXT("LoreCommitChangesTooltip", "View pending Lore changes and optionally commit and push selected files"),
FSlateIcon(FRevisionControlStyleManager::GetStyleSetName(), TEXT("RevisionControl.Actions.Submit")),
FUIAction(
FExecuteAction::CreateRaw(this, &FLoreSourceControlModule::OpenLoreCommitDialog),
FCanExecuteAction::CreateRaw(this, &FLoreSourceControlModule::CanOpenLoreCommitDialog)));
}));
}

void FLoreSourceControlModule::OpenLoreCommitDialog() const
{
if (ISourceControlModule::Get().GetProvider().GetName() == LoreSourceControlProvider.GetName())
{
FSourceControlWindows::ChoosePackagesToCheckIn();
}
}

bool FLoreSourceControlModule::CanOpenLoreCommitDialog() const
{
return ISourceControlModule::Get().GetProvider().GetName() == LoreSourceControlProvider.GetName()
&& LoreSourceControlProvider.IsAvailable()
&& FSourceControlWindows::CanChoosePackagesToCheckIn();
}

TSharedRef<SDockTab> FLoreSourceControlModule::SpawnBranchHistoryTab(const FSpawnTabArgs& InArgs)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
SNew(SLoreBranchHistory, &LoreSourceControlProvider)
];
}

void FLoreSourceControlModule::ShowBranchHistoryTab() const
{
FGlobalTabmanager::Get()->TryInvokeTab(FTabId(LoreBranchHistoryTabName));
}

void FLoreSourceControlModule::OnAssetEditorOpened(UObject* InAsset, IAssetEditorInstance* InInstance)
{
if (!InInstance)
Expand Down
12 changes: 12 additions & 0 deletions Source/LoreSourceControl/Private/LoreSourceControlModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
#include "LoreSourceControlProvider.h"

class SWindow;
class SDockTab;
class SNotificationItem;
class FSlateStyleSet;
class FSpawnTabArgs;
struct IConsoleCommand;

class FLoreSourceControlModule : public IModuleInterface
Expand All @@ -24,6 +26,8 @@ class FLoreSourceControlModule : public IModuleInterface
#if SOURCE_CONTROL_WITH_SLATE
/** Adds the branch switcher combo button to the level editor's Source Control toolbar, and hooks up asset editors to get the same treatment as they open */
void RegisterToolbarExtension();
/** Adds Lore's View / Commit Changes action to Unreal's bottom Revision Control dropdown. */
void RegisterRevisionControlMenuExtension();

/** Extends a single status-bar toolbar menu with the branch switcher combo button; no-ops if that menu was already extended */
void RegisterToolbarExtensionForMenu(FName InMenuName);
Expand All @@ -33,6 +37,12 @@ class FLoreSourceControlModule : public IModuleInterface

/** Builds the dropdown menu content listing all local branches (called when the combo button is opened) */
TSharedRef<SWidget> GenerateBranchMenu();
/** Open the standard submit dialog through Lore. */
void OpenLoreCommitDialog() const;
bool CanOpenLoreCommitDialog() const;
/** Create and focus the dockable branch history tab used by UE6's built-in Lore action. */
TSharedRef<SDockTab> SpawnBranchHistoryTab(const FSpawnTabArgs& InArgs);
void ShowBranchHistoryTab() const;

/** Prompts for confirmation, then switches to the given branch (hot-reloading Content, or asking for a restart if Source/Config was touched) */
void OnBranchSelected(FString InBranchName);
Expand Down Expand Up @@ -76,11 +86,13 @@ class FLoreSourceControlModule : public IModuleInterface
TWeakPtr<SNotificationItem> SyncNotification;
TWeakPtr<SNotificationItem> BranchSwitchNotification;
TSharedPtr<FSlateStyleSet> BranchMenuStyle;
bool bRevisionControlMenuRegistered = false;
#endif

IConsoleCommand* LoreSyncCommand = nullptr;
IConsoleCommand* LoreStatusCommand = nullptr;
IConsoleCommand* LoreCommitCommand = nullptr;
IConsoleCommand* LoreBranchHistoryCommand = nullptr;

/** The one and only source control provider */
FLoreSourceControlProvider LoreSourceControlProvider;
Expand Down
17 changes: 17 additions & 0 deletions Source/LoreSourceControl/Private/LoreSourceControlOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,23 @@ bool FLoreCheckInWorker::UpdateStates() const
{
return FLoreSourceControlUtils::UpdateCachedStates(Provider, States, StateScanPaths, bApplyStateResults);
}
//-----------------------------------------------------------------------------
// Branch history
//-----------------------------------------------------------------------------
bool FLoreRefreshBranchHistoryWorker::Execute(FLoreSourceControlCommand& InCommand)
{
const TSharedRef<FLoreRefreshBranchHistoryOperation> Operation = StaticCastSharedRef<FLoreRefreshBranchHistoryOperation>(InCommand.Operation);

TArray<FLoreBranchHistoryEntry> History;
InCommand.bCommandSuccessful = FLoreSourceControlUtils::RunGetBranchHistory(
InCommand.PathToLoreBinary,
InCommand.PathToRepositoryRoot,
Operation->GetBranchName(),
History,
InCommand.ErrorMessages);
Operation->SetHistory(MoveTemp(History));
return InCommand.bCommandSuccessful;
}

//-----------------------------------------------------------------------------
// Sync
Expand Down
30 changes: 30 additions & 0 deletions Source/LoreSourceControl/Private/LoreSourceControlOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "CoreMinimal.h"
#include "ILoreSourceControlWorker.h"
#include "LoreSourceControlUtils.h"
#include "SourceControlOperationBase.h"

class FLoreSourceControlState;
Expand All @@ -26,6 +27,27 @@ class FLoreRefreshBranchesOperation : public FSourceControlOperationBase
virtual FText GetInProgressString() const override { return NSLOCTEXT("LoreSourceControl", "RefreshingBranches", "Refreshing Lore branches..."); }
};

/** Internal operation used by the branch history tab. */
class FLoreRefreshBranchHistoryOperation : public FSourceControlOperationBase
{
public:
explicit FLoreRefreshBranchHistoryOperation(FString InBranchName)
: BranchName(MoveTemp(InBranchName))
{
}

virtual FName GetName() const override { return "LoreRefreshBranchHistory"; }
virtual FText GetInProgressString() const override { return NSLOCTEXT("LoreSourceControl", "RefreshingBranchHistory", "Refreshing Lore branch history..."); }

const FString& GetBranchName() const { return BranchName; }
const TArray<FLoreBranchHistoryEntry>& GetHistory() const { return History; }
void SetHistory(TArray<FLoreBranchHistoryEntry>&& InHistory) { History = MoveTemp(InHistory); }

private:
FString BranchName;
TArray<FLoreBranchHistoryEntry> History;
};

/** Internal operation for a non-blocking branch switch. */
class FLoreSwitchBranchOperation : public FSourceControlOperationBase
{
Expand Down Expand Up @@ -181,6 +203,14 @@ class FLoreRefreshBranchesWorker : public ILoreSourceControlWorker
bool bRefreshSucceeded = false;
};

class FLoreRefreshBranchHistoryWorker : public ILoreSourceControlWorker
{
public:
virtual FName GetName() const override { return "LoreRefreshBranchHistory"; }
virtual bool Execute(FLoreSourceControlCommand& InCommand) override;
virtual bool UpdateStates() const override { return false; }
};

class FLoreSwitchBranchWorker : public ILoreSourceControlWorker
{
public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
#include "LoreSourceControlUtils.h"
#include "ISourceControlModule.h"
#include "HAL/FileManager.h"
#include "Logging/StructuredLog.h"
#include "Misc/Paths.h"

bool FLoreSourceControlRevision::Get(FString& InOutFilename, EConcurrency::Type InConcurrency) const
{
if (InConcurrency != EConcurrency::Synchronous)
{
UE_LOG(LogSourceControl, Warning, TEXT("FLoreSourceControlRevision::Get only supports EConcurrency::Synchronous."));
UE_LOGFMT(LogSourceControl, Warning, "FLoreSourceControlRevision::Get only supports EConcurrency::Synchronous.");
}

if (InOutFilename.IsEmpty())
Expand Down
Loading