Newer
Older
Stanley Goldman
committed
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace GitHub.Unity
{
class ProjectWindowInterface : AssetPostprocessor
{
private static readonly List<GitStatusEntry> entries = new List<GitStatusEntry>();
private static List<GitLock> locks = new List<GitLock>();
private static readonly List<string> guids = new List<string>();
private static readonly List<string> guidsLocks = new List<string>();
private static bool initialized = false;
private static IRepository repository;
private static bool isBusy = false;
Stanley Goldman
committed
private static ILogging logger;
private static ILogging Logger { get { return logger = logger ?? Logging.GetLogger<ProjectWindowInterface>(); } }
public static void Initialize(IRepository repo)
{
EditorApplication.projectWindowItemOnGUI -= OnProjectWindowItemGUI;
EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemGUI;
initialized = true;
Stanley Goldman
committed
repository = repo;
if (repository != null)
{
repository.OnRepositoryChanged += RunStatusUpdateOnMainThread;
repository.OnLocksUpdated += RunLocksUpdateOnMainThread;
}
}
[MenuItem("Assets/Request Lock", true)]
private static bool ContextMenu_CanLock()
{
if (isBusy)
return false;
if (repository == null || !repository.CurrentRemote.HasValue)
return false;
var selected = Selection.activeObject;
if (selected == null)
return false;
if (locks == null)
return false;
NPath assetPath = AssetDatabase.GetAssetPath(selected.GetInstanceID()).ToNPath();
NPath repositoryPath = EntryPoint.Environment.GetRepositoryPath(assetPath);
var alreadyLocked = locks.Any(x =>
{
return repositoryPath == x.Path.ToNPath();
});
GitFileStatus status = GitFileStatus.None;
if (entries != null)
{
status = entries.FirstOrDefault(x => repositoryPath == x.Path.ToNPath()).Status;
}
return !alreadyLocked && status != GitFileStatus.Untracked && status != GitFileStatus.Ignored;
}
[MenuItem("Assets/Request Lock")]
private static void ContextMenu_Lock()
{
isBusy = true;
var selected = Selection.activeObject;
NPath assetPath = AssetDatabase.GetAssetPath(selected.GetInstanceID()).ToNPath();
NPath repositoryPath = EntryPoint.Environment.GetRepositoryPath(assetPath);
repository
.RequestLock(repositoryPath)
{
isBusy = false;
Selection.activeGameObject = null;
EditorApplication.RepaintProjectWindow();
}
[MenuItem("Assets/Release lock", true, 1000)]
private static bool ContextMenu_CanUnlock()
{
if (isBusy)
return false;
if (repository == null || !repository.CurrentRemote.HasValue)
return false;
var selected = Selection.activeObject;
if (selected == null)
return false;
if (locks == null || locks.Count == 0)
return false;
NPath assetPath = AssetDatabase.GetAssetPath(selected.GetInstanceID()).ToNPath();
NPath repositoryPath = EntryPoint.Environment.GetRepositoryPath(assetPath);
var isLocked = locks.Any(x => repositoryPath == x.Path.ToNPath());
return isLocked;
}
[MenuItem("Assets/Release lock", false, 1000)]
private static void ContextMenu_Unlock()
{
isBusy = true;
var selected = Selection.activeObject;
NPath assetPath = AssetDatabase.GetAssetPath(selected.GetInstanceID()).ToNPath();
NPath repositoryPath = EntryPoint.Environment.GetRepositoryPath(assetPath);
repository
.ReleaseLock(repositoryPath, false)
{
isBusy = false;
Selection.activeGameObject = null;
EditorApplication.RepaintProjectWindow();
}
public static void Run()
{
Refresh();
}
private static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moveDestination, string[] moveSource)
{
Refresh();
}
private static void Refresh()
{
if (initialized)
{
if (!DefaultEnvironment.OnWindows)
{
repository.Refresh();
}
}
}
private static void RunLocksUpdateOnMainThread(IEnumerable<GitLock> update)
{
new ActionTask(EntryPoint.ApplicationManager.TaskManager.Token, _ => OnLocksUpdate(update))
.ScheduleUI(EntryPoint.ApplicationManager.TaskManager);
}
private static void OnLocksUpdate(IEnumerable<GitLock> update)
{
if (update == null)
{
return;
}
locks = update.ToList();
Stanley Goldman
committed
guidsLocks.Clear();
foreach (var lck in locks)
{
NPath repositoryPath = lck.Path.ToNPath();
NPath assetPath = EntryPoint.Environment.GetAssetPath(repositoryPath);
var g = AssetDatabase.AssetPathToGUID(assetPath);
Stanley Goldman
committed
guidsLocks.Add(g);
}
}
private static void RunStatusUpdateOnMainThread(GitStatus update)
{
EntryPoint.ApplicationManager.TaskManager.ScheduleUI(new ActionTask(EntryPoint.ApplicationManager.TaskManager.Token, _ => OnStatusUpdate(update)));
}
private static void OnStatusUpdate(GitStatus update)
{
if (update.Entries == null)
{
return;
}
entries.Clear();
entries.AddRange(update.Entries);
guids.Clear();
for (var index = 0; index < entries.Count; ++index)
{
Stanley Goldman
committed
var gitStatusEntry = entries[index];
var path = gitStatusEntry.ProjectPath;
if (gitStatusEntry.Status == GitFileStatus.Ignored)
Stanley Goldman
committed
continue;
}
if (!path.StartsWith("Assets", StringComparison.CurrentCultureIgnoreCase))
{
continue;
}
if (path.EndsWith(".meta", StringComparison.CurrentCultureIgnoreCase))
{
continue;
}
var guid = AssetDatabase.AssetPathToGUID(path);
Stanley Goldman
committed
guids.Add(guid);
}
EditorApplication.RepaintProjectWindow();
}
private static void OnProjectWindowItemGUI(string guid, Rect itemRect)
{
if (Event.current.type != EventType.Repaint || string.IsNullOrEmpty(guid))
{
return;
}
var index = guids.IndexOf(guid);
var indexLock = guidsLocks.IndexOf(guid);
if (index < 0 && indexLock < 0)
{
return;
}
GitStatusEntry? gitStatusEntry = null;
GitFileStatus status = GitFileStatus.None;
Stanley Goldman
committed
if (index >= 0)
{
gitStatusEntry = entries[index];
status = gitStatusEntry.Value.Status;
}
Stanley Goldman
committed
var isLocked = indexLock >= 0;
var texture = Styles.GetFileStatusIcon(status, isLocked);
if (texture == null)
{
var path = gitStatusEntry.HasValue ? gitStatusEntry.Value.Path : string.Empty;
Logger.Warning("Unable to retrieve texture for Guid:{0} EntryPath:{1} Status: {2} IsLocked:{3}", guid, path, status.ToString(), isLocked);
Stanley Goldman
committed
return;
}
Rect rect;
// End of row placement
if (itemRect.width > itemRect.height)
{
rect = new Rect(itemRect.xMax - texture.width, itemRect.y, texture.width,
Mathf.Min(texture.height, EditorGUIUtility.singleLineHeight));
}
// Corner placement
// TODO: Magic numbers that need reviewing. Make sure this works properly with long filenames and wordwrap.
else
{
var scale = itemRect.height / 90f;
var size = new Vector2(texture.width * scale, texture.height * scale);
var offset = new Vector2(itemRect.width * Mathf.Min(.4f * scale, .2f), itemRect.height * Mathf.Min(.2f * scale, .2f));
rect = new Rect(itemRect.center.x - size.x * .5f + offset.x, itemRect.center.y - size.y * .5f + offset.y, size.x, size.y);
}
GUI.DrawTexture(rect, texture, ScaleMode.ScaleToFit);
}
}
}