Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Commit 3df7f67

Browse files
Merge pull request #475 from github-for-unity/enhancements/changes-tree-view
ChangesView Tree Implementation
2 parents 023d813 + 62a0f82 commit 3df7f67

File tree

7 files changed

+340
-124
lines changed

7 files changed

+340
-124
lines changed

src/GitHub.Api/Git/TreeData.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,24 @@ public GitBranchTreeData(GitBranch gitBranch)
2323
public string Path => GitBranch.Name;
2424
public bool IsActive => GitBranch.IsActive;
2525
}
26+
27+
[Serializable]
28+
public struct GitStatusEntryTreeData : ITreeData
29+
{
30+
public static GitStatusEntryTreeData Default = new GitStatusEntryTreeData(GitStatusEntry.Default);
31+
32+
public GitStatusEntry gitStatusEntry;
33+
34+
public GitStatusEntryTreeData(GitStatusEntry gitStatusEntry)
35+
{
36+
this.gitStatusEntry = gitStatusEntry;
37+
}
38+
39+
public string Path => gitStatusEntry.Path;
40+
public string ProjectPath => gitStatusEntry.ProjectPath;
41+
public bool IsActive => false;
42+
public GitStatusEntry GitStatusEntry => gitStatusEntry;
43+
44+
public GitFileStatus FileStatus => gitStatusEntry.Status;
45+
}
2646
}

src/GitHub.Api/UI/TreeBase.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,28 @@ public void Load(IEnumerable<TData> treeDatas)
102102
}
103103
}
104104

105+
public void SetCheckStateOnAll(bool isChecked)
106+
{
107+
var nodeCheckState = isChecked ? CheckState.Checked : CheckState.Empty;
108+
foreach (var node in Nodes)
109+
{
110+
var wasChecked = node.CheckState == CheckState.Checked;
111+
node.CheckState = nodeCheckState;
112+
113+
if (!node.IsFolder)
114+
{
115+
if (isChecked && !wasChecked)
116+
{
117+
AddCheckedNode(node);
118+
}
119+
else if (!isChecked && wasChecked)
120+
{
121+
RemoveCheckedNode(node);
122+
}
123+
}
124+
}
125+
}
126+
105127
protected abstract IEnumerable<string> GetCollapsedFolders();
106128

107129
protected void AddNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden,

src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
<Compile Include="EntryPoint.cs" />
8888
<Compile Include="Misc\Installer.cs" />
8989
<Compile Include="UI\BaseWindow.cs" />
90+
<Compile Include="UI\ChangesTreeControl.cs" />
9091
<Compile Include="UI\PopupWindow.cs" />
9192
<Compile Include="UI\ProjectWindowInterface.cs" />
9293
<Compile Include="Misc\Styles.cs" />

src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs

Lines changed: 54 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -182,23 +182,6 @@ private void UpdateTreeIcons()
182182
}
183183
}
184184

185-
private void UpdateTreeStyles()
186-
{
187-
if (treeLocals != null && treeLocals.FolderStyle == null)
188-
{
189-
treeLocals.FolderStyle = Styles.Foldout;
190-
treeLocals.TreeNodeStyle = Styles.TreeNode;
191-
treeLocals.ActiveTreeNodeStyle = Styles.TreeNodeActive;
192-
}
193-
194-
if (treeRemotes != null && treeRemotes.FolderStyle == null)
195-
{
196-
treeRemotes.FolderStyle = Styles.Foldout;
197-
treeRemotes.TreeNodeStyle = Styles.TreeNode;
198-
treeRemotes.ActiveTreeNodeStyle = Styles.TreeNodeActive;
199-
}
200-
}
201-
202185
private void OnButtonBarGUI()
203186
{
204187
if (mode == BranchesMode.Default)
@@ -313,67 +296,75 @@ private void OnButtonBarGUI()
313296

314297
private void OnTreeGUI(Rect rect)
315298
{
316-
UpdateTreeStyles();
317-
318299
var initialRect = rect;
319-
var treeHadFocus = treeLocals.SelectedNode != null;
300+
if (treeLocals != null && treeRemotes != null)
301+
{
302+
treeLocals.FolderStyle = Styles.Foldout;
303+
treeLocals.TreeNodeStyle = Styles.TreeNode;
304+
treeLocals.ActiveTreeNodeStyle = Styles.TreeNodeActive;
320305

321-
rect = treeLocals.Render(initialRect, rect, scroll,
322-
node =>{ },
323-
node => {
324-
if (node.IsFolder)
325-
return;
306+
treeRemotes.FolderStyle = Styles.Foldout;
307+
treeRemotes.TreeNodeStyle = Styles.TreeNode;
308+
treeRemotes.ActiveTreeNodeStyle = Styles.TreeNodeActive;
326309

327-
if(node.IsActive)
328-
return;
310+
var treeHadFocus = treeLocals.SelectedNode != null;
329311

330-
SwitchBranch(node.Path);
331-
},
332-
node => {
333-
if (node.IsFolder)
334-
return;
312+
rect = treeLocals.Render(initialRect, rect, scroll,
313+
node => { },
314+
node => {
315+
if (node.IsFolder)
316+
return;
335317

336-
var menu = CreateContextMenuForLocalBranchNode(node);
337-
menu.ShowAsContext();
338-
});
318+
if (node.IsActive)
319+
return;
339320

340-
if (treeHadFocus && treeLocals.SelectedNode == null)
341-
treeRemotes.Focus();
342-
else if (!treeHadFocus && treeLocals.SelectedNode != null)
343-
treeRemotes.Blur();
321+
SwitchBranch(node.Path);
322+
},
323+
node => {
324+
if (node.IsFolder)
325+
return;
344326

345-
if (treeLocals.RequiresRepaint)
346-
Redraw();
327+
var menu = CreateContextMenuForLocalBranchNode(node);
328+
menu.ShowAsContext();
329+
});
347330

348-
treeHadFocus = treeRemotes.SelectedNode != null;
331+
if (treeHadFocus && treeLocals.SelectedNode == null)
332+
treeRemotes.Focus();
333+
else if (!treeHadFocus && treeLocals.SelectedNode != null)
334+
treeRemotes.Blur();
349335

350-
rect.y += Styles.TreePadding;
336+
if (treeLocals.RequiresRepaint)
337+
Redraw();
351338

352-
rect = treeRemotes.Render(initialRect, rect, scroll,
353-
node => { },
354-
node => {
355-
if (node.IsFolder)
356-
return;
339+
treeHadFocus = treeRemotes.SelectedNode != null;
357340

358-
CheckoutRemoteBranch(node.Path);
359-
},
360-
node => {
361-
if (node.IsFolder)
362-
return;
341+
rect.y += Styles.TreePadding;
363342

364-
var menu = CreateContextMenuForRemoteBranchNode(node);
365-
menu.ShowAsContext();
366-
});
343+
rect = treeRemotes.Render(initialRect, rect, scroll,
344+
node => { },
345+
node => {
346+
if (node.IsFolder)
347+
return;
367348

368-
if (treeHadFocus && treeRemotes.SelectedNode == null)
369-
treeLocals.Focus();
370-
else if (!treeHadFocus && treeRemotes.SelectedNode != null)
371-
treeLocals.Blur();
349+
CheckoutRemoteBranch(node.Path);
350+
},
351+
node => {
352+
if (node.IsFolder)
353+
return;
372354

373-
if (treeRemotes.RequiresRepaint)
374-
Redraw();
355+
var menu = CreateContextMenuForRemoteBranchNode(node);
356+
menu.ShowAsContext();
357+
});
358+
359+
if (treeHadFocus && treeRemotes.SelectedNode == null)
360+
treeLocals.Focus();
361+
else if (!treeHadFocus && treeRemotes.SelectedNode != null)
362+
treeLocals.Blur();
363+
364+
if (treeRemotes.RequiresRepaint)
365+
Redraw();
366+
}
375367

376-
//Debug.LogFormat("reserving: {0} {1} {2}", rect.y - initialRect.y, rect.y, initialRect.y);
377368
GUILayout.Space(rect.y - initialRect.y);
378369
}
379370

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using UnityEditor;
5+
using UnityEngine;
6+
7+
namespace GitHub.Unity
8+
{
9+
[Serializable]
10+
public class ChangesTreeNodeDictionary : SerializableDictionary<string, ChangesTreeNode> { }
11+
12+
[Serializable]
13+
public class ChangesTreeNode : TreeNode
14+
{
15+
public string projectPath;
16+
public GitFileStatus gitFileStatus;
17+
18+
public string ProjectPath
19+
{
20+
get { return projectPath; }
21+
set { projectPath = value; }
22+
}
23+
24+
public GitFileStatus GitFileStatus
25+
{
26+
get { return gitFileStatus; }
27+
set { gitFileStatus = value; }
28+
}
29+
}
30+
31+
[Serializable]
32+
public class ChangesTree : Tree<ChangesTreeNode, GitStatusEntryTreeData>
33+
{
34+
[SerializeField] public ChangesTreeNodeDictionary folders = new ChangesTreeNodeDictionary();
35+
[SerializeField] public ChangesTreeNodeDictionary checkedFileNodes = new ChangesTreeNodeDictionary();
36+
37+
[NonSerialized] public Texture2D FolderIcon;
38+
39+
public void UpdateIcons(Texture2D folderIcon)
40+
{
41+
var needsLoad = FolderIcon == null;
42+
if (needsLoad)
43+
{
44+
FolderIcon = folderIcon;
45+
46+
LoadNodeIcons();
47+
}
48+
}
49+
50+
protected override void SetNodeIcon(ChangesTreeNode node)
51+
{
52+
node.Icon = GetNodeIcon(node);
53+
node.IconBadge = GetNodeIconBadge(node);
54+
node.Load();
55+
}
56+
57+
protected Texture GetNodeIcon(ChangesTreeNode node)
58+
{
59+
Texture nodeIcon = null;
60+
if (node.IsFolder)
61+
{
62+
nodeIcon = FolderIcon;
63+
}
64+
else
65+
{
66+
if (!string.IsNullOrEmpty(node.ProjectPath))
67+
{
68+
nodeIcon = AssetDatabase.GetCachedIcon(node.ProjectPath);
69+
}
70+
71+
if (nodeIcon != null)
72+
{
73+
nodeIcon.hideFlags = HideFlags.HideAndDontSave;
74+
}
75+
else
76+
{
77+
nodeIcon = Styles.DefaultAssetIcon;
78+
}
79+
}
80+
81+
return nodeIcon;
82+
}
83+
84+
protected Texture GetNodeIconBadge(ChangesTreeNode node)
85+
{
86+
if (node.IsFolder)
87+
{
88+
return null;
89+
}
90+
91+
var gitFileStatus = node.GitFileStatus;
92+
return Styles.GetFileStatusIcon(gitFileStatus, false);
93+
}
94+
95+
protected override ChangesTreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, GitStatusEntryTreeData? treeData)
96+
{
97+
var node = new ChangesTreeNode
98+
{
99+
Path = path,
100+
Label = label,
101+
Level = level,
102+
IsFolder = isFolder,
103+
IsActive = isActive,
104+
IsHidden = isHidden,
105+
IsCollapsed = isCollapsed,
106+
TreeIsCheckable = IsCheckable,
107+
GitFileStatus = treeData.HasValue ? treeData.Value.FileStatus : GitFileStatus.None,
108+
ProjectPath = treeData.HasValue ? treeData.Value.ProjectPath : null
109+
};
110+
111+
if (isFolder)
112+
{
113+
folders.Add(node.Path, node);
114+
}
115+
116+
return node;
117+
}
118+
119+
protected override void OnClear()
120+
{
121+
folders.Clear();
122+
checkedFileNodes.Clear();
123+
}
124+
125+
protected override IEnumerable<string> GetCollapsedFolders()
126+
{
127+
return folders.Where(pair => pair.Value.IsCollapsed).Select(pair => pair.Key);
128+
}
129+
130+
public override IEnumerable<string> GetCheckedFiles()
131+
{
132+
return checkedFileNodes.Where(pair => pair.Value.CheckState == CheckState.Checked).Select(pair => pair.Key);
133+
}
134+
135+
protected override void RemoveCheckedNode(ChangesTreeNode node)
136+
{
137+
checkedFileNodes.Remove(((ITreeNode)node).Path);
138+
}
139+
140+
protected override void AddCheckedNode(ChangesTreeNode node)
141+
{
142+
checkedFileNodes.Add(((ITreeNode)node).Path, node);
143+
}
144+
}
145+
}

0 commit comments

Comments
 (0)