Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new View Locks window similar to the recent View Branches #107

Merged
merged 20 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
89a14bc
Add a new View Locks window similar to the recent View Branches
SRombautsU Jan 17, 2024
0d76766
Fix existing lock list parser to filter upfront by --repository
SRombautsU Jan 18, 2024
b766f52
Refactor FSmartLockInfoParser to use the new FPlasticSourceControlLoc…
SRombautsU Jan 18, 2024
35c06df
NOTE: --dateformat was added to smartlocks a couple of releases later…
SRombautsU Jan 23, 2024
296fcc1
New "GetLocks" operation, and binding to the existing PlasticSourceCo…
SRombautsU Jan 22, 2024
0e74824
Implement OnReleaseLocksClicked() and OnRemovedLocksClicked() with Ex…
SRombautsU Jan 22, 2024
553a470
Also register for any source control change to detect new local locks…
SRombautsU Jan 22, 2024
7110526
Also display the current branch in the View locks window as it's impo…
SRombautsU Jan 24, 2024
52717b3
Micro optimization with reserve allocation on the XML branch parser
SRombautsU Jan 25, 2024
71d349e
Change the "Unlock" operation to uses strings for ItemIds
SRombautsU Jan 25, 2024
d5d7d71
Refactor ParseFileinfoResults() to handle multiple matching locks in …
SRombautsU Jan 26, 2024
40cd6db
FPlasticSourceControlState::CanCheckout() now let the user try to che…
SRombautsU Jan 29, 2024
5bdd5a6
Update README.md with a screenshot of the new View Locks window.
SRombautsU Jan 30, 2024
cc74262
Fix crash when trying to sort by Destination Branch
SRombautsU Jan 30, 2024
892f3f4
Fix a typo AssetDataToFileNames() instead of AssetDateXxx
SRombautsU Jan 31, 2024
11636a2
Refactor and simplify FPlasticUnlockWorker::Execute() to prepare the …
SRombautsU Jan 31, 2024
b71e17d
Fix SPlasticSourceControlLocksWidget::ExecuteUnlock() to also fill in…
SRombautsU Feb 1, 2024
4950b9c
Fix for multiple locks of the same asset, using the undocumented argu…
SRombautsU Feb 2, 2024
7f1cd2e
Implement comparison operators designed to detect and report only mea…
SRombautsU Feb 2, 2024
32ea377
Implement a cache in PlasticSourceControlUtils::RunListLocks() and an…
SRombautsU Feb 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ Warning when trying to modify an asset that has been modified in another branch:

#### Branches

The plugin now offers full support for branches, including the ability to create, switch to and merge branches from within the Unreal Editor,
The plugin now offers full support for branches, with a new window to list and filter them, and the ability to create, switch to and merge branches from within the Unreal Editor,
reloading assets and the current level as appropriate.

To open it, use the "View Branches" menu item in the Revision Control menu, or click on the name of the current branch in the status bar.
Expand All @@ -433,6 +433,13 @@ Deleting the selected branches:

[Meet Smart Locks, a new way to reduce merge conflicts with Unity Version Control](https://blog.unity.com/engine-platform/unity-version-control-smart-locks)

The plugin now offers full support for Smart Locks, with a new window to list and filter them, and the ability to release or remove them selectively.

To open it, use the "View Locks" menu item in the Revision Control menu.

View Locks window:
![View Locks window](Screenshots/UEPlasticPlugin-Locks-Menu.png)

Smart Locks administrator context menu to configure lock rules or unlock an asset:
![Smart Locks admin context menu](Screenshots/UEPlasticPlugin-SmartLocks-Menu.png)

Expand Down
Binary file modified Screenshots/UE5PlasticPlugin-RevisionControlMenu.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/UEPlasticPlugin-Locks-Menu.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Source/PlasticSourceControl/Private/PackageUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static UWorld* GetCurrentWorld()
return nullptr;
}

TArray<FString> AssetDateToFileNames(const TArray<FAssetData>& InAssetObjectPaths)
TArray<FString> AssetDataToFileNames(const TArray<FAssetData>& InAssetObjectPaths)
{
TArray<FString> FileNames;
FileNames.Reserve(InAssetObjectPaths.Num());
Expand Down
2 changes: 1 addition & 1 deletion Source/PlasticSourceControl/Private/PackageUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace PackageUtils
{
TArray<FString> AssetDateToFileNames(const TArray<FAssetData>& InAssetObjectPaths);
TArray<FString> AssetDataToFileNames(const TArray<FAssetData>& InAssetObjectPaths);

bool SaveDirtyPackages();
TArray<FString> ListAllPackages();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@
class FPlasticSourceControlBranch
{
public:
FPlasticSourceControlBranch() = default;
FPlasticSourceControlBranch(const FString& InName, const FString& InRepository, const FString& InCreatedBy, const FDateTime& InDate, const FString& InComment)
: Name(InName)
, Repository(InRepository)
, CreatedBy(InCreatedBy)
, Date(InDate)
, Comment(InComment)
{}
FString Name;
FString Repository;
FString CreatedBy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@
#include "PlasticSourceControlStyle.h"
#include "SPlasticSourceControlBranchesWidget.h"

#define LOCTEXT_NAMESPACE "PlasticSourceControlWindow"
#define LOCTEXT_NAMESPACE "PlasticSourceControlBranchesWindow"

static const FName PlasticSourceControlWindowTabName("PlasticSourceControlWindow");
static const FName PlasticSourceControlBranchesWindowTabName("PlasticSourceControlBranchesWindow");

void FPlasticSourceControlBranchesWindow::Register()
{
FPlasticSourceControlStyle::Initialize();
FPlasticSourceControlStyle::ReloadTextures();

FGlobalTabmanager::Get()->RegisterNomadTabSpawner(PlasticSourceControlWindowTabName, FOnSpawnTab::CreateRaw(this, &FPlasticSourceControlBranchesWindow::OnSpawnTab))
.SetDisplayName(LOCTEXT("PlasticSourceControlWindowTabTitle", "View Branches"))
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(PlasticSourceControlBranchesWindowTabName, FOnSpawnTab::CreateRaw(this, &FPlasticSourceControlBranchesWindow::OnSpawnTab))
.SetDisplayName(LOCTEXT("PlasticSourceControlBranchesWindowTabTitle", "View Branches"))
.SetMenuType(ETabSpawnerMenuType::Hidden)
.SetIcon(FSlateIcon(FPlasticSourceControlStyle::Get().GetStyleSetName(), "PlasticSourceControl.PluginIcon.Small"));
}

void FPlasticSourceControlBranchesWindow::Unregister()
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(PlasticSourceControlWindowTabName);
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(PlasticSourceControlBranchesWindowTabName);

FPlasticSourceControlStyle::Shutdown();
}
Expand All @@ -40,7 +40,7 @@ TSharedRef<SDockTab> FPlasticSourceControlBranchesWindow::OnSpawnTab(const FSpaw

void FPlasticSourceControlBranchesWindow::OpenTab()
{
FGlobalTabmanager::Get()->TryInvokeTab(PlasticSourceControlWindowTabName);
FGlobalTabmanager::Get()->TryInvokeTab(PlasticSourceControlBranchesWindowTabName);
}

TSharedPtr<SWidget> FPlasticSourceControlBranchesWindow::CreateBranchesWidget()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#if ENGINE_MAJOR_VERSION == 5

#include "ISourceControlChangelistState.h"
#include "ISourceControlState.h"

#include "PlasticSourceControlChangelist.h"

Expand Down
32 changes: 32 additions & 0 deletions Source/PlasticSourceControl/Private/PlasticSourceControlLock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2024 Unity Technologies

#pragma once

#include "CoreMinimal.h"

#include "ISourceControlState.h"

class FPlasticSourceControlLock
{
public:
int32 ItemId = ISourceControlState::INVALID_REVISION;
FString Path;
FString Status;
bool bIsLocked = false;
FDateTime Date;
FString Owner;
FString DestinationBranch;
FString Branch;
FString Workspace;

void PopulateSearchString(TArray<FString>& OutStrings) const
{
OutStrings.Emplace(Path);
OutStrings.Emplace(Owner);
OutStrings.Emplace(Branch);
OutStrings.Emplace(Workspace);
}
};

typedef TSharedRef<class FPlasticSourceControlLock, ESPMode::ThreadSafe> FPlasticSourceControlLockRef;
typedef TSharedPtr<class FPlasticSourceControlLock, ESPMode::ThreadSafe> FPlasticSourceControlLockPtr;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2024 Unity Technologies

#include "PlasticSourceControlLocksWindow.h"

#include "Widgets/Docking/SDockTab.h"

#include "PlasticSourceControlStyle.h"
#include "SPlasticSourceControlLocksWidget.h"

#define LOCTEXT_NAMESPACE "PlasticSourceControlLocksWindow"

static const FName PlasticSourceControlLocksWindowTabName("PlasticSourceControlLocksWindow");

void FPlasticSourceControlLocksWindow::Register()
{
FPlasticSourceControlStyle::Initialize();
FPlasticSourceControlStyle::ReloadTextures();

FGlobalTabmanager::Get()->RegisterNomadTabSpawner(PlasticSourceControlLocksWindowTabName, FOnSpawnTab::CreateRaw(this, &FPlasticSourceControlLocksWindow::OnSpawnTab))
.SetDisplayName(LOCTEXT("PlasticSourceControlLocksWindowTabTitle", "View Locks"))
.SetMenuType(ETabSpawnerMenuType::Hidden)
.SetIcon(FSlateIcon(FPlasticSourceControlStyle::Get().GetStyleSetName(), "PlasticSourceControl.PluginIcon.Small"));
}

void FPlasticSourceControlLocksWindow::Unregister()
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(PlasticSourceControlLocksWindowTabName);

FPlasticSourceControlStyle::Shutdown();
}

TSharedRef<SDockTab> FPlasticSourceControlLocksWindow::OnSpawnTab(const FSpawnTabArgs& SpawnTabArgs)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
CreateLocksWidget().ToSharedRef()
];
}

void FPlasticSourceControlLocksWindow::OpenTab()
{
FGlobalTabmanager::Get()->TryInvokeTab(PlasticSourceControlLocksWindowTabName);
}

TSharedPtr<SWidget> FPlasticSourceControlLocksWindow::CreateLocksWidget()
{
return SNew(SPlasticSourceControlLocksWidget);
}

#undef LOCTEXT_NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) 2024 Unity Technologies

#pragma once

#include "CoreMinimal.h"

// Nomad tab window to hold the widget with the list of Locks, see SPlasticSourceControlLocksWidget
class FPlasticSourceControlLocksWindow
{
public:
void Register();
void Unregister();

void OpenTab();

private:
TSharedRef<class SDockTab> OnSpawnTab(const class FSpawnTabArgs& SpawnTabArgs);

TSharedPtr<SWidget> CreateLocksWidget();
};
45 changes: 39 additions & 6 deletions Source/PlasticSourceControl/Private/PlasticSourceControlMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

#include "PlasticSourceControlMenu.h"

#include "PlasticSourceControlBranchesWindow.h"
#include "PlasticSourceControlModule.h"
#include "PlasticSourceControlOperations.h"
#include "PlasticSourceControlProvider.h"
#include "PlasticSourceControlStyle.h"
#include "PlasticSourceControlUtils.h"
#include "PlasticSourceControlVersions.h"
#include "SPlasticSourceControlStatusBar.h"

#include "ISourceControlModule.h"
Expand Down Expand Up @@ -126,6 +126,7 @@ void FPlasticSourceControlMenu::ExtendRevisionControlMenu()
if (FToolMenuSection* Section = ToolsMenu->FindSection("Source Control"))
{
AddViewBranches(*Section);
AddViewLocks(*Section);
}
}
#endif
Expand Down Expand Up @@ -192,7 +193,7 @@ void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& Me
{
MenuBuilder.AddMenuEntry(
LOCTEXT("PlasticReleaseLock", "Release Lock"),
LOCTEXT("PlasticReleaseLockTooltip", "Release Lock(s) on the selected assets. Requires administrator privileges on the server."),
LOCTEXT("PlasticReleaseLockTooltip", "Release Lock(s) on the selected assets.\nReleasing locks will allow other users to keep working on these files and retrieve locks (on the same branch, in the latest revision)."),
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1
FSlateIcon(FAppStyle::GetAppStyleSetName(), "PropertyWindow.Unlocked"),
#else
Expand All @@ -208,7 +209,7 @@ void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& Me
{
MenuBuilder.AddMenuEntry(
LOCTEXT("PlasticRemoveLock", "Remove Lock"),
LOCTEXT("PlasticRemoveLockTooltip", "Remove/Delete Lock(s) on the selected assets. Requires administrator privileges on the server."),
LOCTEXT("PlasticRemoveLockTooltip", "Remove Lock(s) on the selected assets.\nRemoving locks will allow other users to edit these files anywhere (on any branch) increasing the risk of future merge conflicts."),
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1
FSlateIcon(FAppStyle::GetAppStyleSetName(), "PropertyWindow.Unlocked"),
#else
Expand Down Expand Up @@ -244,7 +245,7 @@ void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& Me

bool FPlasticSourceControlMenu::CanReleaseLocks(TArray<FAssetData> InAssetObjectPaths) const
{
const TArray<FString> Files = PackageUtils::AssetDateToFileNames(InAssetObjectPaths);
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);

for (const FString& File : Files)
{
Expand All @@ -262,7 +263,7 @@ bool FPlasticSourceControlMenu::CanReleaseLocks(TArray<FAssetData> InAssetObject

bool FPlasticSourceControlMenu::CanRemoveLocks(TArray<FAssetData> InAssetObjectPaths) const
{
const TArray<FString> Files = PackageUtils::AssetDateToFileNames(InAssetObjectPaths);
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);

for (const FString& File : Files)
{
Expand Down Expand Up @@ -292,7 +293,7 @@ void FPlasticSourceControlMenu::ExecuteUnlock(const TArray<FAssetData>& InAssetO
{
if (!Notification.IsInProgress())
{
const TArray<FString> Files = PackageUtils::AssetDateToFileNames(InAssetObjectPaths);
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);

// Launch a custom "Release/Remove Lock" operation
FPlasticSourceControlProvider& Provider = FPlasticSourceControlModule::Get().GetProvider();
Expand Down Expand Up @@ -552,6 +553,11 @@ void FPlasticSourceControlMenu::OpenBranchesWindow() const
FPlasticSourceControlModule::Get().GetBranchesWindow().OpenTab();
}

void FPlasticSourceControlMenu::OpenLocksWindow() const
{
FPlasticSourceControlModule::Get().GetLocksWindow().OpenTab();
}

void FPlasticSourceControlMenu::OnSyncAllOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult)
{
OnSourceControlOperationComplete(InOperation, InResult);
Expand Down Expand Up @@ -794,6 +800,7 @@ void FPlasticSourceControlMenu::AddMenuExtension(FToolMenuSection& Menu)
);

AddViewBranches(Menu);
AddViewLocks(Menu);
}

#if ENGINE_MAJOR_VERSION == 4
Expand Down Expand Up @@ -822,6 +829,32 @@ void FPlasticSourceControlMenu::AddViewBranches(FToolMenuSection& Menu)
);
}

#if ENGINE_MAJOR_VERSION == 4
void FPlasticSourceControlMenu::AddViewLocks(FMenuBuilder& Menu)
#elif ENGINE_MAJOR_VERSION == 5
void FPlasticSourceControlMenu::AddViewLocks(FToolMenuSection& Menu)
#endif
{
const bool bVersionSupportsSmartLocks = FPlasticSourceControlModule::Get().GetProvider().GetPlasticScmVersion() >= PlasticSourceControlVersions::SmartLocks;

Menu.AddMenuEntry(
#if ENGINE_MAJOR_VERSION == 5
TEXT("PlasticLocksWindow"),
#endif
LOCTEXT("PlasticLocksWindow", "View Locks"),
LOCTEXT("PlasticLocksWindowTooltip", "Open the Locks window."),
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1
FSlateIcon(FAppStyle::GetAppStyleSetName(), "PropertyWindow.Locked"),
#else
FSlateIcon(FEditorStyle::GetStyleSetName(), "PropertyWindow.Locked"),
#endif
FUIAction(
FExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::OpenLocksWindow),
FCanExecuteAction::CreateLambda([bVersionSupportsSmartLocks]() { return bVersionSupportsSmartLocks; })
)
);
}

#if ENGINE_MAJOR_VERSION == 4
TSharedRef<FExtender> FPlasticSourceControlMenu::OnExtendLevelEditorViewMenu(const TSharedRef<FUICommandList> CommandList)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,21 @@ class FPlasticSourceControlMenu
void VisitLockRulesURLClicked(const FString InOrganizationName) const;
void OpenDeskoptApp() const;
void OpenBranchesWindow() const;
void OpenLocksWindow() const;

private:
bool IsSourceControlConnected() const;

#if ENGINE_MAJOR_VERSION == 4
void AddMenuExtension(FMenuBuilder& Menu);
void AddViewBranches(FMenuBuilder& Menu);
void AddViewLocks(FMenuBuilder& Menu);

TSharedRef<class FExtender> OnExtendLevelEditorViewMenu(const TSharedRef<class FUICommandList> CommandList);
#elif ENGINE_MAJOR_VERSION == 5
void AddMenuExtension(FToolMenuSection& Menu);
void AddViewBranches(FToolMenuSection& Menu);
void AddViewLocks(FToolMenuSection& Menu);
#endif

/** Extends the UE5 toolbar with a status bar widget to display the current branch and open the branch tab */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ void FPlasticSourceControlModule::StartupModule()
// Bind our source control provider to the editor
IModularFeatures::Get().RegisterModularFeature("SourceControl", &PlasticSourceControlProvider);

/// Register our tab Window here as it needs to be ready for the editor to reload at startup
/// Register our tab windows here as they needs to be ready for the editor to reload at startup
PlasticSourceControlBranchesWindow.Register();
PlasticSourceControlLocksWindow.Register();
}

void FPlasticSourceControlModule::ShutdownModule()
Expand All @@ -29,6 +30,7 @@ void FPlasticSourceControlModule::ShutdownModule()
PlasticSourceControlProvider.Close();

PlasticSourceControlBranchesWindow.Unregister();
PlasticSourceControlLocksWindow.Unregister();

// unbind provider from editor
IModularFeatures::Get().UnregisterModularFeature("SourceControl", &PlasticSourceControlProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "PlasticSourceControlWorkspaceCreation.h"

#include "PlasticSourceControlBranchesWindow.h"
#include "PlasticSourceControlLocksWindow.h"

/**
* PlasticSourceControl is the official Unity Version Control Plugin for Unreal Engine
Expand Down Expand Up @@ -43,6 +44,11 @@ class FPlasticSourceControlModule : public IModuleInterface
return PlasticSourceControlBranchesWindow;
}

FPlasticSourceControlLocksWindow& GetLocksWindow()
{
return PlasticSourceControlLocksWindow;
}

/**
* Singleton-like access to this module's interface. This is just for convenience!
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
Expand All @@ -67,7 +73,9 @@ class FPlasticSourceControlModule : public IModuleInterface
/** The Plastic source control provider */
FPlasticSourceControlProvider PlasticSourceControlProvider;

/** Dockable windows adding advanced features to the plugin */
FPlasticSourceControlBranchesWindow PlasticSourceControlBranchesWindow;
FPlasticSourceControlLocksWindow PlasticSourceControlLocksWindow;

/** Logic to create a new workspace */
FPlasticSourceControlWorkspaceCreation PlasticSourceControlWorkspaceCreation;
Expand Down