using System.Collections.Generic; using Codice.Client.Commands; using Codice.Client.Common; using Codice.CM.Common; using Codice.Utils; using PlasticGui; using PlasticGui.Diff; using PlasticGui.WorkspaceWindow.Diff; namespace Unity.PlasticSCM.Editor.Views.Diff { internal class UnityDiffTree { internal UnityDiffTree() { mInnerTree = new DiffTree(); mMetaCache = new MetaCache(); } internal void BuildCategories( WorkspaceInfo wkInfo, List diffs, BranchResolver brResolver, bool skipMergeTracking) { mInnerTree.BuildCategories( RevisionInfoCodeReviewAdapter.CalculateCodeReviewEntries( wkInfo, diffs, brResolver, skipMergeTracking), brResolver); mMetaCache.Build(mInnerTree.GetNodes()); } internal List GetNodes() { return mInnerTree.GetNodes(); } internal bool HasMeta(ClientDiffInfo difference) { return mMetaCache.ContainsMeta(difference); } internal ClientDiffInfo GetMetaDiff(ClientDiffInfo diff) { return mMetaCache.GetExistingMeta(diff); } internal void FillWithMeta(List diffs) { diffs.AddRange( mMetaCache.GetExistingMeta(diffs)); } internal void Sort(string key, bool sortAscending) { mInnerTree.Sort(key, sortAscending); } internal void Filter(Filter filter, List columnNames) { mInnerTree.Filter(filter, columnNames); } MetaCache mMetaCache = new MetaCache(); DiffTree mInnerTree; class MetaCache { internal void Build(List categories) { mCache.Clear(); HashSet indexedKeys = BuildIndexedKeys( GetClientDiffInfos.FromCategories(categories)); for (int i = 0; i < categories.Count; i++) { ExtractToMetaCache( (ITreeViewNode)categories[i], i, mCache, indexedKeys); } } internal bool ContainsMeta(ClientDiffInfo diff) { return mCache.ContainsKey( BuildKey.ForMetaDiff(diff)); } internal ClientDiffInfo GetExistingMeta(ClientDiffInfo diff) { ClientDiffInfo result; if (!mCache.TryGetValue(BuildKey.ForMetaDiff(diff), out result)) return null; return result; } internal List GetExistingMeta(List diffs) { List result = new List(); foreach (ClientDiffInfo diff in diffs) { string key = BuildKey.ForMetaDiff(diff); ClientDiffInfo metaDiff; if (!mCache.TryGetValue(key, out metaDiff)) continue; result.Add(metaDiff); } return result; } static void ExtractToMetaCache( ITreeViewNode node, int nodeIndex, Dictionary cache, HashSet indexedKeys) { if (node is ClientDiffInfo) { ClientDiffInfo diff = (ClientDiffInfo)node; string path = diff.DiffWithMount.Difference.Path; if (!MetaPath.IsMetaPath(path)) return; string realPath = MetaPath.GetPathFromMetaPath(path); if (!indexedKeys.Contains(BuildKey.BuildCacheKey( BuildKey.GetCategoryGroup(diff), BuildKey.GetChangeCategory(diff), realPath))) return; // found foo.c and foo.c.meta // with the same chage types - move .meta to cache cache.Add(BuildKey.ForDiff(diff), diff); ((ChangeCategory)node.GetParent()).RemoveDiffAt(nodeIndex); } for (int i = node.GetChildrenCount() - 1; i >= 0; i--) { ExtractToMetaCache( node.GetChild(i), i, cache, indexedKeys); } } HashSet BuildIndexedKeys(List diffs) { HashSet result = new HashSet(); foreach (ClientDiffInfo diff in diffs) { if (MetaPath.IsMetaPath(diff.DiffWithMount.Difference.Path)) continue; result.Add(BuildKey.ForDiff(diff)); } return result; } Dictionary mCache = new Dictionary(); static class BuildKey { internal static string ForDiff( ClientDiffInfo diff) { return BuildCacheKey( GetCategoryGroup(diff), GetChangeCategory(diff), diff.DiffWithMount.Difference.Path); } internal static string ForMetaDiff( ClientDiffInfo diff) { return BuildCacheKey( GetCategoryGroup(diff), GetChangeCategory(diff), MetaPath.GetMetaPath(diff.DiffWithMount.Difference.Path)); } internal static string BuildCacheKey( CategoryGroup categoryGroup, ChangeCategory changeCategory, string path) { string result = string.Concat(changeCategory.Type, ":", path); if (categoryGroup == null) return result; return string.Concat(categoryGroup.GetHeaderText(), ":", result); } internal static ChangeCategory GetChangeCategory(ClientDiffInfo diff) { return (ChangeCategory)diff.GetParent(); } internal static CategoryGroup GetCategoryGroup(ClientDiffInfo diff) { ChangeCategory changeCategory = GetChangeCategory(diff); ITreeViewNode categoryGroup = changeCategory.GetParent(); if (categoryGroup == null) return null; return (CategoryGroup)categoryGroup; } } } } }