Net-Game/Library/PackageCache/com.unity.collab-proxy@50ac96531b63/Editor/Views/Merge/Developer/MergeTreeView.cs
2025-03-28 08:33:16 -04:00

628 lines
19 KiB
C#

using System.Collections.Generic;
using System.IO;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using Codice.Client.BaseCommands.Merge;
using Codice.Client.Common;
using Codice.CM.Common;
using PlasticGui;
using PlasticGui.WorkspaceWindow.Merge;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.Tree;
using UnityEditor;
namespace Unity.PlasticSCM.Editor.Views.Merge.Developer
{
internal class MergeTreeView : TreeView
{
internal GenericMenu Menu { get { return mMenu.Menu; } }
internal MergeTreeView(
WorkspaceInfo wkInfo,
MergeTreeHeaderState headerState,
List<string> columnNames,
MergeViewMenu menu)
: base(new TreeViewState())
{
mWkInfo = wkInfo;
mColumnNames = columnNames;
mMenu = menu;
multiColumnHeader = new MultiColumnHeader(headerState);
multiColumnHeader.canSort = true;
multiColumnHeader.sortingChanged += SortingChanged;
customFoldoutYOffset = UnityConstants.TREEVIEW_FOLDOUT_Y_OFFSET;
rowHeight = UnityConstants.TREEVIEW_ROW_HEIGHT;
showAlternatingRowBackgrounds = false;
mCooldownFilterAction = new CooldownWindowDelayer(
DelayedSearchChanged, UnityConstants.SEARCH_DELAYED_INPUT_ACTION_INTERVAL);
}
public override IList<TreeViewItem> GetRows()
{
return mRows;
}
protected override bool CanChangeExpandedState(TreeViewItem item)
{
return item is ChangeCategoryTreeViewItem;
}
protected override TreeViewItem BuildRoot()
{
return new TreeViewItem(0, -1, string.Empty);
}
protected override IList<TreeViewItem> BuildRows(TreeViewItem rootItem)
{
try
{
RegenerateRows(
mMergeTree,
mTreeViewItemIds,
this,
rootItem,
mRows,
mExpandCategories);
}
finally
{
mExpandCategories = false;
}
return mRows;
}
protected override void CommandEventHandling()
{
// NOTE - empty override to prevent crash when pressing ctrl-a in the treeview
}
protected override void SearchChanged(string newSearch)
{
mCooldownFilterAction.Ping();
}
protected override void ContextClickedItem(int id)
{
mMenu.Popup();
Repaint();
}
public override void OnGUI(Rect rect)
{
base.OnGUI(rect);
Event e = Event.current;
if (e.type != EventType.KeyDown)
return;
bool isProcessed = mMenu.ProcessKeyActionIfNeeded(e);
if (isProcessed)
e.Use();
}
protected override void BeforeRowsGUI()
{
int firstRowVisible;
int lastRowVisible;
GetFirstAndLastVisibleRows(out firstRowVisible, out lastRowVisible);
GUI.DrawTexture(new Rect(0,
firstRowVisible * rowHeight,
GetRowRect(0).width,
(lastRowVisible * rowHeight) + 1000),
Images.GetTreeviewBackgroundTexture());
DrawTreeViewItem.InitializeStyles();
base.BeforeRowsGUI();
}
protected override void RowGUI(RowGUIArgs args)
{
if (args.item is ChangeCategoryTreeViewItem)
{
ChangeCategoryTreeViewItem categoryItem =
(ChangeCategoryTreeViewItem)args.item;
CategoryTreeViewItemGUI(
args.rowRect,
categoryItem,
GetSolvedChildrenCount(categoryItem.Category, mSolvedFileConflicts),
args.selected,
args.focused);
return;
}
if (args.item is ChangeTreeViewItem)
{
ChangeTreeViewItem changeTreeViewItem =
(ChangeTreeViewItem)args.item;
MergeChangeInfo changeInfo =
changeTreeViewItem.ChangeInfo;
bool isCurrentConflict = IsCurrent.Conflict(
changeInfo,
mMergeTree.GetMetaChange(changeInfo),
mSolvedFileConflicts);
bool isSolvedConflict = IsSolved.Conflict(
changeInfo,
mMergeTree.GetMetaChange(changeInfo),
mSolvedFileConflicts);
MergeTreeViewItemGUI(
mWkInfo.ClientPath,
mMergeTree,
this,
changeTreeViewItem,
args,
isCurrentConflict,
isSolvedConflict);
return;
}
base.RowGUI(args);
}
internal void SelectFirstUnsolvedDirectoryConflict()
{
foreach (MergeChangesCategory category in mMergeTree.GetNodes())
{
if (category.CategoryType != MergeChangesCategory.Type.DirectoryConflicts)
continue;
foreach (MergeChangeInfo changeInfo in category.GetChanges())
{
if (changeInfo.DirectoryConflict.IsResolved())
continue;
int itemId = -1;
if (mTreeViewItemIds.TryGetInfoItemId(changeInfo, out itemId))
{
SetSelection(new List<int>() { itemId });
return;
}
}
}
}
internal void BuildModel(UnityMergeTree tree)
{
mTreeViewItemIds.Clear();
mMergeTree = tree;
mSolvedFileConflicts = null;
mExpandCategories = true;
}
internal void Refilter()
{
Filter filter = new Filter(searchString);
mMergeTree.Filter(filter, mColumnNames);
mExpandCategories = true;
}
internal void Sort()
{
if (mMergeTree == null)
return;
int sortedColumnIdx = multiColumnHeader.state.sortedColumnIndex;
bool sortAscending = multiColumnHeader.IsSortedAscending(sortedColumnIdx);
mMergeTree.Sort(mColumnNames[sortedColumnIdx], sortAscending);
}
internal void UpdateSolvedFileConflicts(
MergeSolvedFileConflicts solvedFileConflicts)
{
mSolvedFileConflicts = solvedFileConflicts;
}
internal MergeChangeInfo GetMetaChange(MergeChangeInfo change)
{
if (change == null)
return null;
return mMergeTree.GetMetaChange(change);
}
internal void FillWithMeta(List<MergeChangeInfo> changes)
{
mMergeTree.FillWithMeta(changes);
}
internal bool SelectionHasMeta()
{
MergeChangeInfo selectedChangeInfo = GetSelectedMergeChange();
if (selectedChangeInfo == null)
return false;
return mMergeTree.HasMeta(selectedChangeInfo);
}
internal MergeChangeInfo GetSelectedMergeChange()
{
IList<int> selectedIds = GetSelection();
if (selectedIds.Count != 1)
return null;
int selectedId = selectedIds[0];
foreach (KeyValuePair<MergeChangeInfo, int> item
in mTreeViewItemIds.GetInfoItems())
{
if (selectedId == item.Value)
return item.Key;
}
return null;
}
internal List<MergeChangeInfo> GetSelectedMergeChanges()
{
List<MergeChangeInfo> result = new List<MergeChangeInfo>();
IList<int> selectedIds = GetSelection();
if (selectedIds.Count == 0)
return result;
foreach (KeyValuePair<MergeChangeInfo, int> item
in mTreeViewItemIds.GetInfoItems())
{
if (!selectedIds.Contains(item.Value))
continue;
result.Add(item.Key);
}
return result;
}
internal List<MergeChangeInfo> GetSelectedFileConflicts()
{
List<MergeChangeInfo> result = new List<MergeChangeInfo>();
IList<int> selectedIds = GetSelection();
if (selectedIds.Count == 0)
return result;
foreach (KeyValuePair<MergeChangeInfo, int> item
in mTreeViewItemIds.GetInfoItems())
{
if (!selectedIds.Contains(item.Value))
continue;
if (item.Key.CategoryType !=
MergeChangesCategory.Type.FileConflicts)
continue;
result.Add(item.Key);
}
return result;
}
void DelayedSearchChanged()
{
Refilter();
Sort();
Reload();
TableViewOperations.ScrollToSelection(this);
}
void SortingChanged(MultiColumnHeader multiColumnHeader)
{
Sort();
Reload();
}
static void RegenerateRows(
UnityMergeTree mergeTree,
TreeViewItemIds<MergeChangesCategory, MergeChangeInfo> treeViewItemIds,
MergeTreeView treeView,
TreeViewItem rootItem,
List<TreeViewItem> rows,
bool expandCategories)
{
if (mergeTree == null)
return;
ClearRows(rootItem, rows);
List<MergeChangesCategory> categories = mergeTree.GetNodes();
if (categories == null)
return;
List<int> categoriesToExpand = new List<int>();
foreach (MergeChangesCategory category in categories)
{
int categoryId;
if (!treeViewItemIds.TryGetCategoryItemId(category, out categoryId))
categoryId = treeViewItemIds.AddCategoryItem(category);
ChangeCategoryTreeViewItem categoryTreeViewItem =
new ChangeCategoryTreeViewItem(categoryId, category);
rootItem.AddChild(categoryTreeViewItem);
rows.Add(categoryTreeViewItem);
if (!ShouldExpandCategory(
treeView,
categoryTreeViewItem,
expandCategories,
categories.Count))
continue;
categoriesToExpand.Add(categoryTreeViewItem.id);
foreach (MergeChangeInfo changeInfo in category.GetChanges())
{
int differenceId;
if (!treeViewItemIds.TryGetInfoItemId(changeInfo, out differenceId))
differenceId = treeViewItemIds.AddInfoItem(changeInfo);
TreeViewItem changeTreeViewItem =
new ChangeTreeViewItem(differenceId, changeInfo);
categoryTreeViewItem.AddChild(changeTreeViewItem);
rows.Add(changeTreeViewItem);
}
}
treeView.state.expandedIDs = categoriesToExpand;
}
static void ClearRows(
TreeViewItem rootItem,
List<TreeViewItem> rows)
{
if (rootItem.hasChildren)
rootItem.children.Clear();
rows.Clear();
}
static void CategoryTreeViewItemGUI(
Rect rowRect,
ChangeCategoryTreeViewItem item,
int solvedChildrenCount,
bool isSelected,
bool isFocused)
{
string label = item.Category.GetCategoryName();
string infoLabel = item.Category.GetChildrenCountText();
DefaultStyles.label = GetCategoryStyle(
item.Category,
solvedChildrenCount,
isSelected);
DrawTreeViewItem.ForCategoryItem(
rowRect,
item.depth,
label,
infoLabel,
isSelected,
isFocused);
DefaultStyles.label = UnityStyles.Tree.Label;
}
static void MergeTreeViewItemGUI(
string wkPath,
UnityMergeTree mergeTree,
MergeTreeView treeView,
ChangeTreeViewItem item,
RowGUIArgs args,
bool isCurrentConflict,
bool isSolvedConflict)
{
for (int visibleColumnIdx = 0; visibleColumnIdx < args.GetNumVisibleColumns(); visibleColumnIdx++)
{
Rect cellRect = args.GetCellRect(visibleColumnIdx);
MergeTreeColumn column =
(MergeTreeColumn)args.GetColumn(visibleColumnIdx);
MergeTreeViewItemCellGUI(
wkPath,
cellRect,
treeView.rowHeight,
mergeTree,
treeView,
item,
column,
args.selected,
args.focused,
isCurrentConflict,
isSolvedConflict);
}
}
static void MergeTreeViewItemCellGUI(
string wkPath,
Rect rect,
float rowHeight,
UnityMergeTree mergeTree,
MergeTreeView treeView,
ChangeTreeViewItem item,
MergeTreeColumn column,
bool isSelected,
bool isFocused,
bool isCurrentConflict,
bool isSolvedConflict)
{
MergeChangeInfo mergeChange = item.ChangeInfo;
string label = mergeChange.GetColumnText(
MergeTreeHeaderState.GetColumnName(column));
if (column == MergeTreeColumn.Path)
{
if (mergeTree.HasMeta(item.ChangeInfo))
label = string.Concat(label, UnityConstants.TREEVIEW_META_LABEL);
Texture icon = GetIcon(wkPath, mergeChange);
Texture overlayIcon =
GetChangesOverlayIcon.ForPlasticMergeChange(
mergeChange, isSolvedConflict);
DrawTreeViewItem.ForItemCell(
rect,
rowHeight,
item.depth,
icon,
overlayIcon,
label,
isSelected,
isFocused,
isCurrentConflict,
false);
return;
}
if (column == MergeTreeColumn.Size)
{
// If there is a meta file, add the meta file to the file size so that it is consistent
// with the Merge overview
if (mergeTree.HasMeta(item.ChangeInfo))
{
MergeChangeInfo metaFileInfo = mergeTree.GetMetaChange(mergeChange);
long metaFileSize = metaFileInfo.GetSize();
long fileSize = mergeChange.GetSize();
label = SizeConverter.ConvertToSizeString(fileSize + metaFileSize);
}
DrawTreeViewItem.ForSecondaryLabelRightAligned(
rect, label, isSelected, isFocused, isCurrentConflict);
return;
}
DrawTreeViewItem.ForSecondaryLabel(
rect, label, isSelected, isFocused, isCurrentConflict);
}
static Texture GetIcon(
string wkPath,
MergeChangeInfo mergeChange)
{
RevisionInfo revInfo = mergeChange.GetRevision();
bool isDirectory = revInfo.
Type == EnumRevisionType.enDirectory;
if (isDirectory || mergeChange.IsXLink())
return Images.GetDirectoryIcon();
string fullPath = WorkspacePath.GetWorkspacePathFromCmPath(
wkPath,
mergeChange.GetPath(),
Path.DirectorySeparatorChar);
return Images.GetFileIcon(fullPath);
}
static GUIStyle GetCategoryStyle(
MergeChangesCategory category,
int solvedChildrenCount,
bool isSelected)
{
if (isSelected)
return UnityStyles.Tree.Label;
if (category.CategoryType == MergeChangesCategory.Type.FileConflicts ||
category.CategoryType == MergeChangesCategory.Type.DirectoryConflicts)
{
return category.GetChildrenCount() > solvedChildrenCount ?
UnityStyles.Tree.RedLabel : UnityStyles.Tree.GreenLabel;
}
return UnityStyles.Tree.Label;
}
static bool ShouldExpandCategory(
MergeTreeView treeView,
ChangeCategoryTreeViewItem categoryTreeViewItem,
bool expandCategories,
int categoriesCount)
{
if (expandCategories)
{
if (categoriesCount == 1)
return true;
if (categoryTreeViewItem.Category.CategoryType ==
MergeChangesCategory.Type.FileConflicts)
return true;
if (categoryTreeViewItem.Category.GetChildrenCount() >
NODES_TO_EXPAND_CATEGORY)
return false;
return true;
}
return treeView.IsExpanded(categoryTreeViewItem.id);
}
static int GetSolvedChildrenCount(
MergeChangesCategory category,
MergeSolvedFileConflicts solvedFileConflicts)
{
int solvedDirConflicts = 0;
if (category.CategoryType == MergeChangesCategory.Type.DirectoryConflicts)
{
foreach (MergeChangeInfo change in category.GetChanges())
{
if (change.DirectoryConflict.IsResolved())
solvedDirConflicts++;
}
return solvedDirConflicts;
}
return (solvedFileConflicts == null) ? 0 :
solvedFileConflicts.GetCount();
}
bool mExpandCategories;
TreeViewItemIds<MergeChangesCategory, MergeChangeInfo> mTreeViewItemIds =
new TreeViewItemIds<MergeChangesCategory, MergeChangeInfo>();
List<TreeViewItem> mRows = new List<TreeViewItem>();
MergeSolvedFileConflicts mSolvedFileConflicts;
UnityMergeTree mMergeTree;
CooldownWindowDelayer mCooldownFilterAction;
readonly MergeViewMenu mMenu;
readonly List<string> mColumnNames;
readonly WorkspaceInfo mWkInfo;
const int NODES_TO_EXPAND_CATEGORY = 10;
}
}