Commit 1c847220 authored by jang dong hyeok's avatar jang dong hyeok
Browse files

.

parent 076f0c68
using System;
using System.Collections.Generic;
using Codice.Client.BaseCommands;
using Codice.Client.Commands;
using Codice.Client.Common;
using Codice.Client.Common.Threading;
using Codice.Client.GameUI;
using Codice.Client.GameUI.Update;
using Codice.CM.Common;
using Codice.CM.Common.Merge;
using Codice.Utils;
using GluonGui.WorkspaceWindow.Views;
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
{
internal class RemoteStatusCache
{
internal RemoteStatusCache(
WorkspaceInfo wkInfo,
bool isGluonMode,
Action repaintProjectWindow)
{
mWkInfo = wkInfo;
mIsGluonMode = isGluonMode;
mRepaintProjectWindow = repaintProjectWindow;
}
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;
}
}
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 (waiter.Exception != null)
{
ExceptionsHandler.LogException(
"RemoteStatusCache",
waiter.Exception);
return;
}
if (cancelToken.IsCancelled())
return;
lock (mLock)
{
mStatusByPathCache = statusByPathCache;
}
mRepaintProjectWindow();
});
}
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())
{
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 Action mRepaintProjectWindow;
readonly bool mIsGluonMode;
readonly WorkspaceInfo mWkInfo;
static object mLock = new object();
}
}
using System;
using System.Collections.Generic;
using Codice.Client.Commands.WkTree;
using Codice.Client.Common;
using Codice.Client.Common.Locks;
using Codice.Client.Common.WkTree;
using Codice.CM.Common;
using Codice.CM.WorkspaceServer.DataStore.Guids;
namespace Unity.PlasticSCM.Editor.AssetsOverlays.Cache
{
internal static class SearchLocks
{
internal static Dictionary<WorkspaceTreeNode, LockInfo> GetLocksInfo(
WorkspaceInfo wkInfo,
Dictionary<RepositorySpec, List<WorkspaceTreeNode>> locksCandidates)
{
Dictionary<WorkspaceTreeNode, LockInfo> result =
new Dictionary<WorkspaceTreeNode, LockInfo>();
Dictionary<string, Dictionary<Guid, LockInfo>> locksByItemByServer =
new Dictionary<string, Dictionary<Guid, LockInfo>>(
StringComparer.InvariantCultureIgnoreCase);
foreach (KeyValuePair<RepositorySpec, List<WorkspaceTreeNode>> each in locksCandidates)
{
FillRepositoryLocks(
wkInfo, each.Key, each.Value,
locksByItemByServer, result);
}
return result;
}
static void FillRepositoryLocks(
WorkspaceInfo wkInfo,
RepositorySpec repSpec,
List<WorkspaceTreeNode> candidates,
Dictionary<string, Dictionary<Guid, LockInfo>> locksByItemByServer,
Dictionary<WorkspaceTreeNode, LockInfo> locks)
{
if (candidates.Count == 0)
return;
LockRule lockRule = ServerLocks.GetLockRule(repSpec);
if (lockRule == null)
return;
candidates = GetLockableCandidates(candidates, lockRule);
if (candidates.Count == 0)
return;
string lockServer = string.IsNullOrEmpty(lockRule.LockServer) ?
repSpec.Server : lockRule.LockServer;
Dictionary<Guid, LockInfo> serverlocksByItem =
ServerLocks.GetServerLocksByItem(
lockServer, locksByItemByServer);
if (serverlocksByItem == null || serverlocksByItem.Count == 0)
return;
IList<Guid> candidatesGuids = GetCandidatesGuids(
wkInfo, repSpec, candidates);
for (int index = 0; index < candidates.Count; index++)
{
LockInfo serverLock;
if (!serverlocksByItem.TryGetValue(
candidatesGuids[index], out serverLock))
continue;
locks[candidates[index]] = serverLock;
}
}
static List<WorkspaceTreeNode> GetLockableCandidates(
List<WorkspaceTreeNode> candidates,
LockRule lockRule)
{
List<WorkspaceTreeNode> result = new List<WorkspaceTreeNode>();
LockedFilesFilter filter = new LockedFilesFilter(lockRule.Rules);
foreach (WorkspaceTreeNode candidate in candidates)
{
string cmPath = WorkspaceNodeOperations.GetCmPath(candidate);
if (cmPath == null)
{
//The node could not be on the head tree (like copied items) so when we
//cannot calculate the path we assume that it's lockable.
result.Add(candidate);
continue;
}
if (filter.IsLockable(cmPath))
result.Add(candidate);
}
return result;
}
static IList<Guid> GetCandidatesGuids(
WorkspaceInfo wkInfo,
RepositorySpec repSpec,
List<WorkspaceTreeNode> candidates)
{
RepositoryInfo repInfo = RepositorySpecResolverProvider.
Get().GetRepInfo(repSpec);
IList<long> ids = new List<long>(candidates.Count);
foreach (WorkspaceTreeNode candidate in candidates)
ids.Add(candidate.RevInfo.ItemId);
return GuidResolver.Get().GetObjectGuids(repInfo, wkInfo, ids);
}
}
}
using System;
using UnityEditor;
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.AssetsOverlays
{
internal static class DrawAssetOverlay
{
internal static void Initialize(
IAssetStatusCache cache,
Action repaintProjectWindow)
{
mAssetStatusCache = cache;
mRepaintProjectWindow = repaintProjectWindow;
EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemGUI;
mRepaintProjectWindow();
}
internal static void Dispose()
{
EditorApplication.projectWindowItemOnGUI -= OnProjectWindowItemGUI;
if (mRepaintProjectWindow != null)
mRepaintProjectWindow();
}
internal static void ClearCache()
{
mAssetStatusCache.Clear();
mRepaintProjectWindow();
}
internal static AssetStatus GetStatusesToDraw(AssetStatus status)
{
if (status.HasFlag(AssetStatus.Checkout) &&
status.HasFlag(AssetStatus.Locked))
return status & ~AssetStatus.Checkout;
if (status.HasFlag(AssetStatus.DeletedOnServer) &&
status.HasFlag(AssetStatus.LockedRemote))
return status & ~AssetStatus.LockedRemote;
return status;
}
internal static string GetStatusString(AssetStatus statusValue)
{
switch (statusValue)
{
case AssetStatus.Private:
return PlasticLocalization.GetString(
PlasticLocalization.Name.Private);
case AssetStatus.Ignored:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusIgnored);
case AssetStatus.Added:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusAdded);
case AssetStatus.Checkout:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusCheckout);
case AssetStatus.OutOfDate:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusOutOfDate);
case AssetStatus.Conflicted:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusConflicted);
case AssetStatus.DeletedOnServer:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusDeletedOnServer);
case AssetStatus.Locked:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusLockedMe);
case AssetStatus.LockedRemote:
return PlasticLocalization.GetString(
PlasticLocalization.Name.StatusLockedRemote);
}
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 = 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.AssetOverlayTooltipWorkspace,
lockStatusData.WorkspaceName));
return string.Format(
"{0}" + Environment.NewLine +
"{1}" + Environment.NewLine +
"{2}",
line1,
line2,
line3);
}
static void OnProjectWindowItemGUI(string guid, Rect selectionRect)
{
if (string.IsNullOrEmpty(guid))
return;
if (Event.current.type != EventType.Repaint)
return;
AssetStatus statusesToDraw = GetStatusesToDraw(
mAssetStatusCache.GetStatusForGuid(guid));
foreach (AssetStatus status in Enum.GetValues(typeof(AssetStatus)))
{
if (status == AssetStatus.None)
continue;
if (!statusesToDraw.HasFlag(status))
continue;
LockStatusData lockStatusData =
ClassifyAssetStatus.IsLockedRemote(status) ?
mAssetStatusCache.GetLockStatusData(guid) :
null;
string tooltipText = GetTooltipText(
status,
lockStatusData);
DrawOverlayIcon.ForStatus(
selectionRect,
status,
tooltipText);
}
}
internal static class DrawOverlayIcon
{
internal static void ForStatus(
Rect selectionRect,
AssetStatus status,
string tooltipText)
{
Texture overlayIcon = GetOverlayIcon(status);
if (overlayIcon == null)
return;
Rect overlayRect = GetOverlayRect(
selectionRect, overlayIcon, status);
GUI.DrawTexture(
overlayRect, overlayIcon, ScaleMode.ScaleToFit);
Rect tooltipRect = GetTooltipRect(selectionRect, overlayRect);
GUI.Label(tooltipRect, new GUIContent(string.Empty, tooltipText));
}
internal static Texture GetOverlayIcon(AssetStatus status)
{
switch (status)
{
case AssetStatus.Ignored:
return Images.GetImage(Images.Name.Ignored);
case AssetStatus.Private:
return Images.GetPrivatedOverlayIcon();
case AssetStatus.Added:
return Images.GetAddedOverlayIcon();
case AssetStatus.Checkout:
return Images.GetCheckedOutOverlayIcon();
case AssetStatus.OutOfDate:
return Images.GetOutOfSyncOverlayIcon();
case AssetStatus.Conflicted:
return Images.GetConflictedOverlayIcon();
case AssetStatus.DeletedOnServer:
return Images.GetDeletedRemoteOverlayIcon();
case AssetStatus.Locked:
return Images.GetLockedLocalOverlayIcon();
case AssetStatus.LockedRemote:
return Images.GetLockedRemoteOverlayIcon();
}
return null;
}
static Rect Inflate(Rect rect, float width, float height)
{
return new Rect(
rect.x - width,
rect.y - height,
rect.width + 2 * width,
rect.height + 2 * height);
}
static Rect GetOverlayRect(
Rect selectionRect,
Texture overlayIcon,
AssetStatus status)
{
OverlayAlignment alignment = GetIconPosition(status);
if (selectionRect.width > selectionRect.height)
return GetOverlayRectForSmallestSize(
selectionRect, overlayIcon, alignment);
return GetOverlayRectForOtherSizes(
selectionRect, overlayIcon, alignment);
}
static Rect GetTooltipRect(
Rect selectionRect,
Rect overlayRect)
{
if (selectionRect.width > selectionRect.height)
{
return overlayRect;
}
return Inflate(overlayRect, 3, 3);
}
static Rect GetOverlayRectForSmallestSize(
Rect selectionRect,
Texture overlayIcon,
OverlayAlignment alignment)
{
float xOffset = IsLeftAligned(alignment) ? -5 : 5;
float yOffset = IsTopAligned(alignment) ? -4 : 4;
return new Rect(
selectionRect.x + xOffset,
selectionRect.y + yOffset,
OVERLAY_ICON_SIZE,
OVERLAY_ICON_SIZE);
}
static Rect GetOverlayRectForOtherSizes(
Rect selectionRect,
Texture overlayIcon,
OverlayAlignment alignment)
{
float xOffset = IsLeftAligned(alignment) ?
0 : selectionRect.width - overlayIcon.width;
float yOffset = IsTopAligned(alignment) ?
0 : selectionRect.height - overlayIcon.height - 12;
return new Rect(
selectionRect.x + xOffset,
selectionRect.y + yOffset,
OVERLAY_ICON_SIZE,
OVERLAY_ICON_SIZE);
}
static OverlayAlignment GetIconPosition(AssetStatus status)
{
if (status == AssetStatus.Checkout ||
status == AssetStatus.Locked)
return OverlayAlignment.TopLeft;
if (status == AssetStatus.DeletedOnServer ||
status == AssetStatus.LockedRemote)
return OverlayAlignment.TopRight;
if (status == AssetStatus.OutOfDate)
return OverlayAlignment.BottomRight;
return OverlayAlignment.BottomLeft;
}
static bool IsLeftAligned(OverlayAlignment alignment)
{
return alignment == OverlayAlignment.BottomLeft ||
alignment == OverlayAlignment.TopLeft;
}
static bool IsTopAligned(OverlayAlignment alignment)
{
return alignment == OverlayAlignment.TopLeft ||
alignment == OverlayAlignment.TopRight;
}
enum OverlayAlignment
{
TopLeft,
BottomLeft,
TopRight,
BottomRight
}
}
static IAssetStatusCache mAssetStatusCache;
static Action mRepaintProjectWindow;
const float OVERLAY_ICON_SIZE = 16;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment