init project
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
|
||||
using PlasticGui;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays
|
||||
{
|
||||
internal static class AssetOverlay
|
||||
{
|
||||
internal static string GetStatusString(AssetStatus assetStatus)
|
||||
{
|
||||
if (ClassifyAssetStatus.IsPrivate(assetStatus))
|
||||
return PlasticLocalization.Name.Private.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsIgnored(assetStatus))
|
||||
return PlasticLocalization.Name.StatusIgnored.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsAdded(assetStatus))
|
||||
return PlasticLocalization.Name.StatusAdded.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsConflicted(assetStatus))
|
||||
return PlasticLocalization.Name.StatusConflicted.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsDeletedOnServer(assetStatus))
|
||||
return PlasticLocalization.Name.StatusDeletedOnServer.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsLockedRemote(assetStatus))
|
||||
return PlasticLocalization.Name.StatusLockedRemote.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsOutOfDate(assetStatus))
|
||||
return PlasticLocalization.Name.StatusOutOfDate.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsLocked(assetStatus))
|
||||
return PlasticLocalization.Name.StatusLockedByMe.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsRetained(assetStatus))
|
||||
return PlasticLocalization.Name.StatusRetained.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsCheckedOut(assetStatus))
|
||||
return PlasticLocalization.Name.StatusCheckout.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsChanged(assetStatus))
|
||||
return PlasticLocalization.Name.ChangedStatus.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.ContainsChanges(assetStatus))
|
||||
return PlasticLocalization.Name.ContainsChanges.GetString();
|
||||
|
||||
if (ClassifyAssetStatus.IsControlled(assetStatus))
|
||||
return PlasticLocalization.Name.Controlled.GetString();
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
internal static string GetTooltipText(
|
||||
AssetStatus statusValue,
|
||||
LockStatusData lockStatusData)
|
||||
{
|
||||
string statusText = GetStatusString(statusValue);
|
||||
|
||||
if (lockStatusData == null)
|
||||
return statusText;
|
||||
|
||||
// example:
|
||||
// Changed by:
|
||||
// * dani_pen@hotmail.com
|
||||
// * workspace wkLocal"
|
||||
|
||||
char bulletCharacter = '\u25cf';
|
||||
|
||||
string line1 = ClassifyAssetStatus.IsLocked(statusValue) ?
|
||||
statusText + ":" :
|
||||
PlasticLocalization.GetString(
|
||||
PlasticLocalization.Name.AssetOverlayTooltipStatus,
|
||||
statusText);
|
||||
|
||||
string line2 = string.Format("{0} {1}",
|
||||
bulletCharacter,
|
||||
lockStatusData.LockedBy);
|
||||
|
||||
string line3 = string.Format("{0} {1}",
|
||||
bulletCharacter,
|
||||
PlasticLocalization.GetString(
|
||||
PlasticLocalization.Name.AssetOverlayTooltipOn,
|
||||
lockStatusData.HolderBranchName));
|
||||
|
||||
return string.Format(
|
||||
"{0}" + Environment.NewLine +
|
||||
"{1}" + Environment.NewLine +
|
||||
"{2}",
|
||||
line1,
|
||||
line2,
|
||||
line3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 408f89d90a01494cbef838c7d21449a9
|
||||
timeCreated: 1750849696
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays
|
||||
{
|
||||
[Flags]
|
||||
internal enum AssetStatus
|
||||
{
|
||||
None = 0,
|
||||
Private = 1 << 0,
|
||||
Ignored = 1 << 2,
|
||||
Added = 1 << 3,
|
||||
Checkout = 1 << 4,
|
||||
Controlled = 1 << 5,
|
||||
UpToDate = 1 << 6,
|
||||
Changed = 1 << 7,
|
||||
ContainsChanges = 1 << 8,
|
||||
OutOfDate = 1 << 9,
|
||||
Conflicted = 1 << 10,
|
||||
DeletedOnServer = 1 << 11,
|
||||
Locked = 1 << 12,
|
||||
LockedRemote = 1 << 13,
|
||||
Retained = 1 << 14,
|
||||
HiddenChanged = 1 << 15,
|
||||
}
|
||||
|
||||
internal class LockStatusData
|
||||
{
|
||||
internal readonly AssetStatus Status;
|
||||
internal readonly string LockedBy;
|
||||
internal readonly string HolderBranchName;
|
||||
|
||||
internal LockStatusData(
|
||||
AssetStatus status,
|
||||
string lockedBy,
|
||||
string holderBranchName)
|
||||
{
|
||||
Status = status;
|
||||
LockedBy = lockedBy;
|
||||
HolderBranchName = holderBranchName;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClassifyAssetStatus
|
||||
{
|
||||
internal static bool IsPrivate(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Private);
|
||||
}
|
||||
|
||||
internal static bool IsIgnored(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Ignored);
|
||||
}
|
||||
|
||||
internal static bool IsControlled(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Controlled);
|
||||
}
|
||||
|
||||
internal static bool IsLocked(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Locked);
|
||||
}
|
||||
|
||||
internal static bool IsLockedRemote(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.LockedRemote);
|
||||
}
|
||||
|
||||
internal static bool IsRetained(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Retained);
|
||||
}
|
||||
|
||||
internal static bool IsOutOfDate(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.OutOfDate);
|
||||
}
|
||||
|
||||
internal static bool IsDeletedOnServer(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.DeletedOnServer);
|
||||
}
|
||||
|
||||
internal static bool IsConflicted(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Conflicted);
|
||||
}
|
||||
|
||||
internal static bool IsAdded(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Added);
|
||||
}
|
||||
|
||||
internal static bool IsCheckedOut(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Checkout);
|
||||
}
|
||||
|
||||
internal static bool IsChanged(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.Changed);
|
||||
}
|
||||
|
||||
internal static bool ContainsChanges(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.ContainsChanges);
|
||||
}
|
||||
|
||||
internal static bool IsHiddenChanged(AssetStatus status)
|
||||
{
|
||||
return ContainsAny(status, AssetStatus.HiddenChanged);
|
||||
}
|
||||
|
||||
static bool ContainsAny(AssetStatus status, AssetStatus matchTo)
|
||||
{
|
||||
return (status & matchTo) != AssetStatus.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 062535eac3e5dd1409b6a50b0d043e2c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a94a55dca335c547ac65bd4b85d2a55
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
using Codice.CM.Common;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
|
||||
{
|
||||
internal interface IAssetStatusCache
|
||||
{
|
||||
AssetStatus GetStatus(string fullPath);
|
||||
LockStatusData GetLockStatusData(string fullPath);
|
||||
void Clear();
|
||||
void ClearLocks();
|
||||
void Cancel();
|
||||
}
|
||||
|
||||
internal class AssetStatusCache : IAssetStatusCache
|
||||
{
|
||||
internal AssetStatusCache(
|
||||
WorkspaceInfo wkInfo,
|
||||
bool isGluonMode)
|
||||
{
|
||||
mLocalStatusCache = new LocalStatusCache(wkInfo);
|
||||
mRemoteStatusCache = new RemoteStatusCache(wkInfo, isGluonMode);
|
||||
mLockStatusCache = new LockStatusCache(wkInfo);
|
||||
}
|
||||
|
||||
AssetStatus IAssetStatusCache.GetStatus(string fullPath)
|
||||
{
|
||||
AssetStatus localStatus = mLocalStatusCache.GetStatus(fullPath);
|
||||
|
||||
if (!ClassifyAssetStatus.IsControlled(localStatus))
|
||||
return localStatus;
|
||||
|
||||
AssetStatus remoteStatus = mRemoteStatusCache.GetStatus(fullPath);
|
||||
|
||||
AssetStatus lockStatus = mLockStatusCache.GetStatus(fullPath);
|
||||
|
||||
return localStatus | remoteStatus | lockStatus;
|
||||
}
|
||||
|
||||
LockStatusData IAssetStatusCache.GetLockStatusData(string fullPath)
|
||||
{
|
||||
return mLockStatusCache.GetLockStatusData(fullPath);
|
||||
}
|
||||
|
||||
void IAssetStatusCache.Clear()
|
||||
{
|
||||
mLocalStatusCache.Clear();
|
||||
mRemoteStatusCache.Clear();
|
||||
mLockStatusCache.Clear();
|
||||
}
|
||||
|
||||
void IAssetStatusCache.ClearLocks()
|
||||
{
|
||||
mLockStatusCache.Clear();
|
||||
}
|
||||
|
||||
void IAssetStatusCache.Cancel()
|
||||
{
|
||||
mRemoteStatusCache.Cancel();
|
||||
mLockStatusCache.Cancel();
|
||||
}
|
||||
|
||||
readonly LocalStatusCache mLocalStatusCache;
|
||||
readonly RemoteStatusCache mRemoteStatusCache;
|
||||
readonly LockStatusCache mLockStatusCache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f227b28cf424364489edd67fce697bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Codice.Utils;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
|
||||
{
|
||||
internal static class BuildPathDictionary
|
||||
{
|
||||
internal static Dictionary<string, T> ForPlatform<T>()
|
||||
{
|
||||
if (PlatformIdentifier.IsWindows())
|
||||
return new Dictionary<string, T>(
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return new Dictionary<string, T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c963b5d17c74314eb7105e71377cdb8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Codice;
|
||||
using Codice.CM.Common;
|
||||
using Codice.Client.BaseCommands;
|
||||
using Codice.Client.Commands.WkTree;
|
||||
using PlasticGui.WorkspaceWindow;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
|
||||
{
|
||||
internal class LocalStatusCache
|
||||
{
|
||||
internal LocalStatusCache(WorkspaceInfo wkInfo)
|
||||
{
|
||||
mWkInfo = wkInfo;
|
||||
}
|
||||
|
||||
internal AssetStatus GetStatus(string fullPath)
|
||||
{
|
||||
AssetStatus result;
|
||||
|
||||
if (mStatusByPathCache.TryGetValue(fullPath, out result))
|
||||
return result;
|
||||
|
||||
result = CalculateStatus(
|
||||
mWkInfo,
|
||||
fullPath,
|
||||
FilterManager.Get().GetIgnoredFilter(),
|
||||
FilterManager.Get().GetHiddenChangesFilter());
|
||||
|
||||
mStatusByPathCache.Add(fullPath, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
mStatusByPathCache.Clear();
|
||||
}
|
||||
|
||||
static AssetStatus CalculateStatus(
|
||||
WorkspaceInfo wkInfo,
|
||||
string fullPath,
|
||||
IgnoredFilesFilter ignoredFilter,
|
||||
HiddenChangesFilesFilter hiddenChangesFilter)
|
||||
{
|
||||
WorkspaceTreeNode node = PlasticGui.Plastic.API.GetWorkspaceTreeNode(
|
||||
wkInfo, fullPath);
|
||||
|
||||
if (CheckWorkspaceTreeNodeStatus.IsPrivate(node))
|
||||
{
|
||||
return ignoredFilter.IsIgnored(fullPath) ?
|
||||
AssetStatus.Ignored : AssetStatus.Private;
|
||||
}
|
||||
|
||||
if (CheckWorkspaceTreeNodeStatus.IsAdded(node))
|
||||
return AssetStatus.Added;
|
||||
|
||||
AssetStatus status = AssetStatus.Controlled;
|
||||
|
||||
status |= CalculateControlledFlags(wkInfo, fullPath, node);
|
||||
status |= GetHiddenChangeFlag(fullPath, hiddenChangesFilter);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static AssetStatus CalculateControlledFlags(
|
||||
WorkspaceInfo wkInfo,
|
||||
string fullPath,
|
||||
WorkspaceTreeNode node)
|
||||
{
|
||||
if (CheckWorkspaceTreeNodeStatus.IsCheckedOut(node))
|
||||
return AssetStatus.Checkout;
|
||||
|
||||
if (CheckWorkspaceTreeNodeStatus.IsDirectory(node))
|
||||
return PlasticGui.Plastic.API.IsOnChangedTree(wkInfo, fullPath)
|
||||
? AssetStatus.ContainsChanges
|
||||
: AssetStatus.None;
|
||||
|
||||
return ChangedFileChecker.IsChanged(node.LocalInfo, fullPath, wkInfo.IsDynamic, false)
|
||||
? AssetStatus.Changed
|
||||
: AssetStatus.None;
|
||||
}
|
||||
|
||||
static AssetStatus GetHiddenChangeFlag(
|
||||
string fullPath,
|
||||
HiddenChangesFilesFilter hiddenChangesFilter)
|
||||
{
|
||||
return hiddenChangesFilter.IsHiddenChanged(fullPath)
|
||||
? AssetStatus.HiddenChanged
|
||||
: AssetStatus.None;
|
||||
}
|
||||
|
||||
readonly WorkspaceInfo mWkInfo;
|
||||
readonly Dictionary<string, AssetStatus> mStatusByPathCache =
|
||||
BuildPathDictionary.ForPlatform<AssetStatus>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 226459a134855504d841db6b61519d2b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,184 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Codice;
|
||||
using Codice.Client.Commands.WkTree;
|
||||
using Codice.Client.Common;
|
||||
using Codice.Client.Common.Locks;
|
||||
using Codice.Client.Common.Threading;
|
||||
using Codice.Client.Common.WkTree;
|
||||
using Codice.CM.Common;
|
||||
using Codice.CM.Common.Mount;
|
||||
using Codice.Utils;
|
||||
using PlasticGui.WorkspaceWindow;
|
||||
using PlasticGui.WorkspaceWindow.Items.Locks;
|
||||
using Unity.PlasticSCM.Editor.AssetUtils;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
|
||||
{
|
||||
internal class LockStatusCache
|
||||
{
|
||||
internal LockStatusCache(
|
||||
WorkspaceInfo wkInfo)
|
||||
{
|
||||
mWkInfo = wkInfo;
|
||||
}
|
||||
|
||||
internal AssetStatus GetStatus(string fullPath)
|
||||
{
|
||||
LockStatusData lockStatusData = GetLockStatusData(fullPath);
|
||||
|
||||
if (lockStatusData == null)
|
||||
return AssetStatus.None;
|
||||
|
||||
return lockStatusData.Status;
|
||||
}
|
||||
|
||||
internal LockStatusData GetLockStatusData(string fullPath)
|
||||
{
|
||||
lock (mLock)
|
||||
{
|
||||
if (mStatusByPathCache == null)
|
||||
{
|
||||
mStatusByPathCache = BuildPathDictionary.ForPlatform<LockStatusData>();
|
||||
|
||||
mCurrentCancelToken.Cancel();
|
||||
mCurrentCancelToken = new CancelToken();
|
||||
AsyncCalculateStatus(mCurrentCancelToken);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
LockStatusData result;
|
||||
|
||||
if (mStatusByPathCache.TryGetValue(fullPath, out result))
|
||||
return result;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
lock (mLock)
|
||||
{
|
||||
mCurrentCancelToken.Cancel();
|
||||
|
||||
mStatusByPathCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Cancel()
|
||||
{
|
||||
lock (mLock)
|
||||
{
|
||||
mCurrentCancelToken.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncCalculateStatus(CancelToken cancelToken)
|
||||
{
|
||||
Dictionary<string, LockStatusData> statusByPathCache = null;
|
||||
|
||||
IThreadWaiter waiter = ThreadWaiter.GetWaiter(50);
|
||||
waiter.Execute(
|
||||
/*threadOperationDelegate*/ delegate
|
||||
{
|
||||
Dictionary<MountPointWithPath, List<WorkspaceTreeNode>> lockCandidates =
|
||||
new Dictionary<MountPointWithPath, List<WorkspaceTreeNode>>();
|
||||
|
||||
FillLockCandidates.ForTree(mWkInfo, lockCandidates);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
Dictionary<WorkspaceTreeNode, LockInfo> lockInfoByNode =
|
||||
SearchLocks.GetLocksInfo(mWkInfo, lockCandidates);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
statusByPathCache = BuildStatusByNodeCache.
|
||||
ForLocks(mWkInfo.ClientPath, lockInfoByNode);
|
||||
},
|
||||
/*afterOperationDelegate*/ delegate
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
if (waiter.Exception != null)
|
||||
{
|
||||
ExceptionsHandler.LogException(
|
||||
"LockStatusCache",
|
||||
waiter.Exception);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (mLock)
|
||||
{
|
||||
mStatusByPathCache = statusByPathCache;
|
||||
}
|
||||
|
||||
RepaintEditor.AllWindowsWithOverlays();
|
||||
});
|
||||
}
|
||||
|
||||
static class BuildStatusByNodeCache
|
||||
{
|
||||
internal static Dictionary<string, LockStatusData> ForLocks(
|
||||
string wkPath,
|
||||
Dictionary<WorkspaceTreeNode, LockInfo> lockInfoByNode)
|
||||
{
|
||||
Dictionary<string, LockStatusData> result =
|
||||
BuildPathDictionary.ForPlatform<LockStatusData>();
|
||||
|
||||
LockOwnerNameResolver nameResolver = new LockOwnerNameResolver();
|
||||
|
||||
foreach (WorkspaceTreeNode node in lockInfoByNode.Keys)
|
||||
{
|
||||
LockStatusData lockStatusData = BuildLockStatusData(
|
||||
node, lockInfoByNode[node], nameResolver);
|
||||
|
||||
string nodeWkPath = WorkspacePath.GetWorkspacePathFromCmPath(
|
||||
wkPath,
|
||||
WorkspaceNodeOperations.GetCmPath(node),
|
||||
PathHelper.GetDirectorySeparatorChar(wkPath));
|
||||
|
||||
result.Add(nodeWkPath, lockStatusData);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static LockStatusData BuildLockStatusData(
|
||||
WorkspaceTreeNode node,
|
||||
LockInfo lockInfo,
|
||||
LockOwnerNameResolver nameResolver)
|
||||
{
|
||||
return new LockStatusData(
|
||||
GetAssetStatus(node, lockInfo),
|
||||
nameResolver.GetSeidName(lockInfo.SEIDData),
|
||||
BranchInfoCache.GetProtectedBranchName(
|
||||
node.RepSpec, lockInfo.HolderBranchId));
|
||||
}
|
||||
|
||||
static AssetStatus GetAssetStatus(
|
||||
WorkspaceTreeNode node,
|
||||
LockInfo lockInfo)
|
||||
{
|
||||
if (lockInfo.Status == LockInfo.LockStatus.Retained)
|
||||
return AssetStatus.Retained;
|
||||
|
||||
return CheckWorkspaceTreeNodeStatus.IsCheckedOut(node) ?
|
||||
AssetStatus.Locked : AssetStatus.LockedRemote;
|
||||
}
|
||||
}
|
||||
|
||||
CancelToken mCurrentCancelToken = new CancelToken();
|
||||
|
||||
Dictionary<string, LockStatusData> mStatusByPathCache;
|
||||
|
||||
readonly WorkspaceInfo mWkInfo;
|
||||
|
||||
static object mLock = new object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 953c29d2e0dece647a64940343c91547
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,181 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Codice.Client.Common;
|
||||
using Codice.Client.Common.Threading;
|
||||
using Codice.CM.Common;
|
||||
using Codice.CM.Common.Merge;
|
||||
using Codice.CM.Common.Mount;
|
||||
using Codice.CM.Common.Partial;
|
||||
using Codice.CM.Common.Update.Partial;
|
||||
using Codice.Utils;
|
||||
using GluonGui.WorkspaceWindow.Views;
|
||||
using Unity.PlasticSCM.Editor.AssetUtils;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
|
||||
{
|
||||
internal class RemoteStatusCache
|
||||
{
|
||||
internal RemoteStatusCache(
|
||||
WorkspaceInfo wkInfo,
|
||||
bool isGluonMode)
|
||||
{
|
||||
mWkInfo = wkInfo;
|
||||
mIsGluonMode = isGluonMode;
|
||||
}
|
||||
|
||||
internal AssetStatus GetStatus(string fullPath)
|
||||
{
|
||||
if (!mIsGluonMode)
|
||||
return AssetStatus.UpToDate;
|
||||
|
||||
lock(mLock)
|
||||
{
|
||||
if (mStatusByPathCache == null)
|
||||
{
|
||||
mStatusByPathCache = BuildPathDictionary.ForPlatform<AssetStatus>();
|
||||
|
||||
mCurrentCancelToken.Cancel();
|
||||
mCurrentCancelToken = new CancelToken();
|
||||
AsyncCalculateStatus(mCurrentCancelToken);
|
||||
|
||||
return AssetStatus.UpToDate;
|
||||
}
|
||||
|
||||
AssetStatus result;
|
||||
if (mStatusByPathCache.TryGetValue(fullPath, out result))
|
||||
return result;
|
||||
|
||||
return AssetStatus.UpToDate;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
lock (mLock)
|
||||
{
|
||||
mCurrentCancelToken.Cancel();
|
||||
mStatusByPathCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Cancel()
|
||||
{
|
||||
lock (mLock)
|
||||
{
|
||||
mCurrentCancelToken.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncCalculateStatus(CancelToken cancelToken)
|
||||
{
|
||||
Dictionary<string, AssetStatus> statusByPathCache = null;
|
||||
|
||||
IThreadWaiter waiter = ThreadWaiter.GetWaiter(50);
|
||||
waiter.Execute(
|
||||
/*threadOperationDelegate*/ delegate
|
||||
{
|
||||
OutOfDateItems outOfDateItems =
|
||||
OutOfDateUpdater.CalculateOutOfDateItems(
|
||||
mWkInfo, new List<ErrorMessage>(),
|
||||
OutOfDateCalculator.Options.IsIncomingChanges);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
statusByPathCache = BuildStatusByPathCache.
|
||||
ForOutOfDateItems(outOfDateItems, mWkInfo.ClientPath);
|
||||
},
|
||||
/*afterOperationDelegate*/ delegate
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
if (waiter.Exception != null)
|
||||
{
|
||||
ExceptionsHandler.LogException(
|
||||
"RemoteStatusCache",
|
||||
waiter.Exception);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (mLock)
|
||||
{
|
||||
mStatusByPathCache = statusByPathCache;
|
||||
}
|
||||
|
||||
RepaintEditor.AllWindowsWithOverlays();
|
||||
});
|
||||
}
|
||||
|
||||
static class BuildStatusByPathCache
|
||||
{
|
||||
internal static Dictionary<string, AssetStatus> ForOutOfDateItems(
|
||||
OutOfDateItems outOfDateItems,
|
||||
string wkPath)
|
||||
{
|
||||
Dictionary<string, AssetStatus> result =
|
||||
BuildPathDictionary.ForPlatform<AssetStatus>();
|
||||
|
||||
if (outOfDateItems == null)
|
||||
return result;
|
||||
|
||||
foreach (OutOfDateItemsByMount diffs in
|
||||
outOfDateItems.GetOutOfDateItemsByMountList(PathHelper.GetPathSorter()))
|
||||
{
|
||||
foreach (Difference diff in diffs.Changed)
|
||||
{
|
||||
if (diff is DiffXlinkChanged)
|
||||
continue;
|
||||
|
||||
string path = GetPathForDiff(wkPath, diffs.Mount, diff.Path);
|
||||
result.Add(path, AssetStatus.OutOfDate);
|
||||
}
|
||||
|
||||
foreach (Difference diff in diffs.Deleted)
|
||||
{
|
||||
string path = GetPathForDiff(wkPath, diffs.Mount, diff.Path);
|
||||
result.Add(path, AssetStatus.DeletedOnServer);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GluonFileConflict fileConflict in
|
||||
outOfDateItems.GetFileConflicts())
|
||||
{
|
||||
string path = GetPathForConflict(wkPath, fileConflict.CmPath);
|
||||
result.Add(path, AssetStatus.Conflicted);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static string GetPathForDiff(
|
||||
string wkPath,
|
||||
MountPointWithPath mountPoint,
|
||||
string cmSubPath)
|
||||
{
|
||||
return WorkspacePath.GetWorkspacePathFromCmPath(
|
||||
wkPath,
|
||||
WorkspacePath.ComposeMountPath(mountPoint.MountPath, cmSubPath),
|
||||
PathHelper.GetDirectorySeparatorChar(wkPath));
|
||||
}
|
||||
|
||||
static string GetPathForConflict(
|
||||
string wkPath,
|
||||
string cmPath)
|
||||
{
|
||||
return WorkspacePath.GetWorkspacePathFromCmPath(
|
||||
wkPath, cmPath,
|
||||
PathHelper.GetDirectorySeparatorChar(wkPath));
|
||||
}
|
||||
}
|
||||
|
||||
CancelToken mCurrentCancelToken = new CancelToken();
|
||||
|
||||
Dictionary<string, AssetStatus> mStatusByPathCache;
|
||||
|
||||
readonly bool mIsGluonMode;
|
||||
readonly WorkspaceInfo mWkInfo;
|
||||
|
||||
static object mLock = new object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9acb575a60d7e045ad7fadd3e3e137d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,86 @@
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.PlasticSCM.Editor.UI;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays
|
||||
{
|
||||
internal static class DrawAssetOverlayIcon
|
||||
{
|
||||
internal static void ForStatus(
|
||||
Rect selectionRect,
|
||||
AssetStatus status,
|
||||
string tooltipText)
|
||||
{
|
||||
Texture overlayIcon = GetOverlayIcon(status);
|
||||
|
||||
if (overlayIcon == null)
|
||||
return;
|
||||
|
||||
Rect overlayRect = GetOverlayRect.ForSelectionRect(selectionRect);
|
||||
|
||||
GUI.DrawTexture(overlayRect, overlayIcon, ScaleMode.ScaleToFit);
|
||||
|
||||
Rect tooltipRect = GetTooltipRect(selectionRect, overlayRect);
|
||||
|
||||
GUI.Label(tooltipRect, new GUIContent(string.Empty, tooltipText));
|
||||
}
|
||||
|
||||
internal static Texture GetOverlayIcon(AssetStatus assetStatus)
|
||||
{
|
||||
if (ClassifyAssetStatus.IsPrivate(assetStatus))
|
||||
return Images.GetPrivateOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsIgnored(assetStatus))
|
||||
return Images.GetIgnoredOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsAdded(assetStatus))
|
||||
return Images.GetAddedOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsConflicted(assetStatus))
|
||||
return Images.GetConflictedOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsDeletedOnServer(assetStatus))
|
||||
return Images.GetDeletedRemoteOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsLockedRemote(assetStatus))
|
||||
return Images.GetLockedRemoteOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsOutOfDate(assetStatus))
|
||||
return Images.GetOutOfSyncOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsLocked(assetStatus))
|
||||
return Images.GetLockedLocalOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsRetained(assetStatus))
|
||||
return Images.GetRetainedOverlayIcon();
|
||||
|
||||
if (ClassifyAssetStatus.IsCheckedOut(assetStatus) ||
|
||||
ClassifyAssetStatus.IsChanged(assetStatus) ||
|
||||
ClassifyAssetStatus.ContainsChanges(assetStatus))
|
||||
return Images.GetCheckedOutOverlayIcon();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Rect Inflate(Rect rect, float width, float height)
|
||||
{
|
||||
return new Rect(
|
||||
rect.x - width,
|
||||
rect.y - height,
|
||||
rect.width + 2f * width,
|
||||
rect.height + 2f * height);
|
||||
}
|
||||
|
||||
static Rect GetTooltipRect(
|
||||
Rect selectionRect,
|
||||
Rect overlayRect)
|
||||
{
|
||||
if (selectionRect.width > selectionRect.height)
|
||||
{
|
||||
return overlayRect;
|
||||
}
|
||||
|
||||
return Inflate(overlayRect, 3f, 3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a92f7c4434405984a811b4e7c316594e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,210 @@
|
||||
using System;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
using Codice.Client.Common.Threading;
|
||||
using Codice.LogWrapper;
|
||||
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
|
||||
using Unity.PlasticSCM.Editor.AssetUtils;
|
||||
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays
|
||||
{
|
||||
internal static class DrawHierarchyOverlay
|
||||
{
|
||||
internal interface IGetAssetPathFromInstance
|
||||
{
|
||||
bool TryGetAssetPath(int instanceID, out string assetPath);
|
||||
}
|
||||
|
||||
internal static IGetAssetPathFromInstance GetSubSceneAssetPath;
|
||||
|
||||
internal static void Enable(
|
||||
string wkPath,
|
||||
IAssetStatusCache assetStatusCache)
|
||||
{
|
||||
if (mIsEnabled)
|
||||
return;
|
||||
|
||||
mLog.Debug("Enable");
|
||||
|
||||
mWkPath = wkPath;
|
||||
mAssetStatusCache = assetStatusCache;
|
||||
|
||||
mIsEnabled = true;
|
||||
|
||||
#if UNITY_6000_4_OR_NEWER
|
||||
EditorApplication.hierarchyWindowItemByEntityIdOnGUI += OnHierarchyGUIByEntityId;
|
||||
#else
|
||||
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
|
||||
#endif
|
||||
|
||||
RepaintEditor.HierarchyWindow();
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
{
|
||||
mLog.Debug("Disable");
|
||||
|
||||
mIsEnabled = false;
|
||||
|
||||
#if UNITY_6000_4_OR_NEWER
|
||||
EditorApplication.hierarchyWindowItemByEntityIdOnGUI -= OnHierarchyGUIByEntityId;
|
||||
#else
|
||||
EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyGUI;
|
||||
#endif
|
||||
|
||||
RepaintEditor.HierarchyWindow();
|
||||
|
||||
mWkPath = null;
|
||||
mAssetStatusCache = null;
|
||||
}
|
||||
|
||||
#if UNITY_6000_4_OR_NEWER
|
||||
static void OnHierarchyGUIByEntityId(EntityId entityId, Rect selectionRect)
|
||||
{
|
||||
OnHierarchyGUI((int)entityId.GetRawData(), selectionRect);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void OnHierarchyGUI(int instanceID, Rect selectionRect)
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
string assetPath = GetAssetPathFromInstanceID(instanceID);
|
||||
|
||||
if (assetPath == null)
|
||||
return;
|
||||
|
||||
string assetFullPath = AssetsPath.GetFullPathUnderWorkspace.ForAsset(mWkPath, assetPath);
|
||||
|
||||
if (assetFullPath == null)
|
||||
return;
|
||||
|
||||
DrawOverlayForAsset(assetFullPath, selectionRect, mAssetStatusCache);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExceptionsHandler.LogException(typeof(DrawHierarchyOverlay).Name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
static string GetAssetPathFromInstanceID(int instanceID)
|
||||
{
|
||||
string sceneAssetPath;
|
||||
if (TryGetAssetPathForScene(instanceID, out sceneAssetPath))
|
||||
{
|
||||
return sceneAssetPath;
|
||||
}
|
||||
|
||||
string subSceneAssetPath;
|
||||
if (TryGetAssetPathForSubScene(instanceID, out subSceneAssetPath))
|
||||
{
|
||||
return subSceneAssetPath;
|
||||
}
|
||||
|
||||
string prefabAssetPath;
|
||||
if (TryGetAssetPathForPrefab(instanceID, out prefabAssetPath))
|
||||
{
|
||||
return prefabAssetPath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool TryGetAssetPathForScene(int instanceID, out string assetPath)
|
||||
{
|
||||
assetPath = null;
|
||||
|
||||
if (FindUnityObject.ForInstanceID(instanceID) != null)
|
||||
return false;
|
||||
|
||||
assetPath = FindScenePathForHandle(instanceID);
|
||||
|
||||
return assetPath != null;
|
||||
}
|
||||
|
||||
static string FindScenePathForHandle(int sceneHandle)
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
|
||||
#if UNITY_6000_4_OR_NEWER
|
||||
if (scene.handle == SceneHandle.FromRawData((ulong)sceneHandle) && scene.path != null)
|
||||
#else
|
||||
if (scene.handle == sceneHandle && scene.path != null)
|
||||
#endif
|
||||
{
|
||||
return scene.path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool TryGetAssetPathForSubScene(int instanceID, out string assetPath)
|
||||
{
|
||||
assetPath = null;
|
||||
|
||||
string subSceneAssetPath;
|
||||
if (GetSubSceneAssetPath != null &&
|
||||
GetSubSceneAssetPath.TryGetAssetPath(instanceID, out subSceneAssetPath))
|
||||
{
|
||||
assetPath = subSceneAssetPath;
|
||||
}
|
||||
|
||||
return assetPath != null;
|
||||
}
|
||||
|
||||
static bool TryGetAssetPathForPrefab(int instanceID, out string assetPath)
|
||||
{
|
||||
assetPath = null;
|
||||
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
if (prefabStage == null)
|
||||
return false;
|
||||
|
||||
Object hierarchyObject = FindUnityObject.ForInstanceID(instanceID);
|
||||
|
||||
if (hierarchyObject == null)
|
||||
return false;
|
||||
|
||||
if (prefabStage.prefabContentsRoot == hierarchyObject)
|
||||
assetPath = prefabStage.assetPath;
|
||||
|
||||
return assetPath != null;
|
||||
}
|
||||
|
||||
static void DrawOverlayForAsset(
|
||||
string assetFullPath,
|
||||
Rect selectionRect,
|
||||
IAssetStatusCache assetStatusCache)
|
||||
{
|
||||
AssetStatus assetStatus = assetStatusCache.GetStatus(assetFullPath);
|
||||
|
||||
string tooltipText = AssetOverlay.GetTooltipText(
|
||||
assetStatus,
|
||||
assetStatusCache.GetLockStatusData(assetFullPath));
|
||||
|
||||
DrawAssetOverlayIcon.ForStatus(
|
||||
selectionRect,
|
||||
assetStatus,
|
||||
tooltipText);
|
||||
}
|
||||
|
||||
static bool mIsEnabled;
|
||||
static IAssetStatusCache mAssetStatusCache;
|
||||
static string mWkPath;
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("DrawHierarchyOverlay");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68f2f2587930106408dd3b00fb4974ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Codice.Client.Common.Threading;
|
||||
using Codice.LogWrapper;
|
||||
using PlasticGui;
|
||||
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
|
||||
using Unity.PlasticSCM.Editor.AssetUtils;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetsOverlays
|
||||
{
|
||||
internal static class DrawProjectOverlay
|
||||
{
|
||||
internal static void Enable(
|
||||
string wkPath,
|
||||
IAssetStatusCache assetStatusCache)
|
||||
{
|
||||
if (mIsEnabled)
|
||||
return;
|
||||
|
||||
mLog.Debug("Enable");
|
||||
|
||||
mWkPath = wkPath;
|
||||
mAssetStatusCache = assetStatusCache;
|
||||
|
||||
mIsEnabled = true;
|
||||
|
||||
EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemGUI;
|
||||
|
||||
RepaintEditor.ProjectWindow();
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
{
|
||||
mLog.Debug("Disable");
|
||||
|
||||
mIsEnabled = false;
|
||||
|
||||
EditorApplication.projectWindowItemOnGUI -= OnProjectWindowItemGUI;
|
||||
|
||||
RepaintEditor.ProjectWindow();
|
||||
|
||||
mWkPath = null;
|
||||
mAssetStatusCache = null;
|
||||
}
|
||||
|
||||
static void OnProjectWindowItemGUI(string guid, Rect selectionRect)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(guid))
|
||||
return;
|
||||
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return;
|
||||
|
||||
string fullPath = AssetsPath.GetFullPathUnderWorkspace.ForGuid(mWkPath, guid);
|
||||
|
||||
if (fullPath == null)
|
||||
return;
|
||||
|
||||
AssetStatus assetStatus = mAssetStatusCache.GetStatus(fullPath);
|
||||
|
||||
string tooltipText = AssetOverlay.GetTooltipText(
|
||||
assetStatus,
|
||||
mAssetStatusCache.GetLockStatusData(fullPath));
|
||||
|
||||
DrawAssetOverlayIcon.ForStatus(
|
||||
selectionRect,
|
||||
assetStatus,
|
||||
tooltipText);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExceptionsHandler.LogException(typeof(DrawProjectOverlay).Name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
static bool mIsEnabled;
|
||||
static IAssetStatusCache mAssetStatusCache;
|
||||
static string mWkPath;
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("DrawProjectOverlay");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d30dfeb72257204458e1e8e1576b84ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user