using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Perforce.P4;
using log4net;
namespace P4Connect
{
class PendingAssetAndMeta
{
public string AssetPath;
public string MetaPath;
public FileAndMetaType Type;
public AssetStatusCache.AssetStatus State;
public string EffectiveFilePath
{
get
{
switch (Type)
{
case FileAndMetaType.None:
return "";
case FileAndMetaType.FileOnly:
return AssetPath;
case FileAndMetaType.MetaOnly:
return MetaPath;
case FileAndMetaType.FileAndMeta:
return AssetPath;
default:
throw new System.Exception("Unhandled case");
}
}
}
public string TypeString
{
get
{
switch (Type)
{
case FileAndMetaType.None:
return "";
case FileAndMetaType.FileOnly:
return "Asset";
case FileAndMetaType.MetaOnly:
return "Meta";
case FileAndMetaType.FileAndMeta:
return "Asset+Meta";
default:
throw new System.Exception("Unhandled case");
}
}
}
public PendingAssetAndMeta()
{
AssetPath = "";
MetaPath = "";
Type = FileAndMetaType.None;
State = new AssetStatusCache.AssetStatus();
}
}
public class PendingChanges
: EditorWindow
{
private static readonly ILog log = LogManager.GetLogger(typeof(PendingChanges));
const float iconSize = 20.0f;
const float spaceBeforeIcon = 8.0f;
const double DoubleClickTime = 500; // ms
static PendingChanges _CurrentInstance;
// Add menu named "Perforce" to the Window menu
[MenuItem("Window/Perforce", false, 1000)]
public static void ShowWindow()
{
// Get existing open window or if none, make a new one:
PendingChanges window = EditorWindow.GetWindow(typeof(PendingChanges), false, "Perforce") as PendingChanges;
window.title = "Perforce";
window.name = "Perforce";
}
public static void UpdateDisplay()
{
if (_CurrentInstance != null)
{
if (Config.ValidConfiguration)
{
using (PerforceConnection con = new PerforceConnection())
{
_CurrentInstance.UpdateList(con);
}
}
else
{
_CurrentInstance.Clear();
}
_CurrentInstance.Repaint();
}
}
public IEnumerable<string> SelectedAssets
{
get
{
return _CurrentSelectedChanges.Select(ch => ch.EffectiveFilePath);
}
}
List<PendingAssetAndMeta> _PendingChanges;
Dictionary<string, bool> _CheckedFiles;
Vector2 _ScrollVector;
string _ChangeListDescription;
Texture2D _HighlightedBackground;
Texture2D _SelectedBackground;
// User selection
PendingAssetAndMeta _LastSelectedChange;
DateTime _LastSelectedChangeTime;
HashSet<PendingAssetAndMeta> _CurrentSelectedChanges;
// Sorting algorithms
System.Func<PendingAssetAndMeta, string> _CurrentSortingFunc;
bool _CurrentSortingAscending;
public PendingChanges()
{
Init();
}
void Init()
{
_LastSelectedChange = null;
_CurrentSelectedChanges = new HashSet<PendingAssetAndMeta>();
_PendingChanges = new List<PendingAssetAndMeta>();
_CheckedFiles = new Dictionary<string, bool>();
if (!Config.ValidConfiguration)
return;
ChangeManager.Refresh(ChangeManager.DEFAULT_CHANGE);
using (PerforceConnection con = new PerforceConnection())
{
UpdateList(con);
}
AssetStatusCache.OnAssetStatusChanged -= OnOperationPerformed;
AssetStatusCache.OnAssetStatusChanged += OnOperationPerformed;
_HighlightedBackground = new Texture2D(1, 1);
_HighlightedBackground.SetPixel(0, 0, new Color(61.0f / 255.0f, 96.0f / 255.0f, 145.0f / 255.0f));
_HighlightedBackground.Apply();
_SelectedBackground = new Texture2D(1, 1);
_SelectedBackground.SetPixel(0, 0, new Color(72.0f / 255.0f, 72.0f / 255.0f, 72.0f / 255.0f));
_SelectedBackground.Apply();
_CurrentSortingFunc = FilenameSortingFunc;
_CurrentSortingAscending = true;
_CurrentInstance = this;
}
void CheckInit()
{
if (_HighlightedBackground == null)
{
Init();
}
}
public void OnDestroy()
{
_CurrentInstance = null;
Clear();
AssetStatusCache.OnAssetStatusChanged -= OnOperationPerformed;
}
void Clear()
{
if (_HighlightedBackground == null)
return;
_PendingChanges.Clear();
_CheckedFiles.Clear();
_ScrollVector = Vector2.zero;
// User selection
_LastSelectedChange = null;
_CurrentSelectedChanges.Clear();
}
void OnOperationPerformed(PerforceConnection con)
{
UpdateList(con);
Repaint();
}
void Update()
{
if (!Config.ValidConfiguration)
{
this.Close(); // If the perforce connection is broken, close the pending changes window
Debug.Log("Closed PendingChanges window because Connection is invalid");
}
}
void UpdateList(PerforceConnection con)
{
Profiler.BeginSample("UpdateList");
//log.Debug("UpdateList");
_PendingChanges.Clear();
if (Config.ValidConfiguration)
{
List<string> openedFiles = new List<string>(ChangeManager.LocalOpenedFiles);
//log.DebugFormat("openedFiles: {0}", Logger.StringArrayToString(openedFiles.ToArray()));
if (openedFiles != null)
{
// Parse the list, seeing if files have metas and such
while (openedFiles.Count > 0)
{
Profiler.BeginSample("UpdateList - count" + openedFiles.Count);
//log.DebugFormat("Main.Rootpath: {0} ", Main.RootPath);
//if (openedFiles[0].StartsWith(Main.RootPath, !Utils.IsCaseSensitive(), null))
//{
string filePath = Utils.UnescapeFilename(openedFiles[0]);
// log.DebugFormat("filePath: {0}", filePath);
PendingAssetAndMeta assetAndMeta = new PendingAssetAndMeta();
if (filePath.EndsWith(".meta"))
{
// It's a meta file, is there an asset in the list as well?
assetAndMeta.MetaPath = filePath;
assetAndMeta.AssetPath = Utils.AssetFromMeta(filePath);
int assetIndex = openedFiles.IndexOf(assetAndMeta.AssetPath);
if (assetIndex != -1)
{
// Yes, there is an asset file
assetAndMeta.Type = FileAndMetaType.FileAndMeta;
// Remove both entries
openedFiles.RemoveAt(assetIndex);
}
else
{
// No, this is a meta only
assetAndMeta.Type = FileAndMetaType.MetaOnly;
}
}
else
{
// It's not a meta file, is there a meta as well?
assetAndMeta.AssetPath = filePath;
assetAndMeta.MetaPath = Utils.MetaFromAsset(filePath);
int metaIndex = openedFiles.IndexOf(Utils.EscapeFilename(assetAndMeta.MetaPath));
if (metaIndex != -1)
{
// Yes, there is a meta file
assetAndMeta.Type = FileAndMetaType.FileAndMeta;
// Remove both entries
openedFiles.RemoveAt(metaIndex);
}
else
{
// No, this is a file only
assetAndMeta.Type = FileAndMetaType.FileOnly;
}
}
// Check whether we knew about this file and wanted it selected
if (!_CheckedFiles.ContainsKey(assetAndMeta.EffectiveFilePath))
{
// If we don't know the file, say that it's selected
_CheckedFiles.Add(assetAndMeta.EffectiveFilePath, true);
}
// Finally, add the asset and meta to the list
//log.DebugFormat(" Adding to Pending Changes: {0}", assetAndMeta.EffectiveFilePath);
_PendingChanges.Add(assetAndMeta);
//}
// No matter what, remove the file
openedFiles.RemoveAt(0);
Profiler.EndSample();
}
// Fetch the state of the file
List<string> paths = new List<string>(_PendingChanges.Select(pc => pc.EffectiveFilePath));
List<AssetStatusCache.AssetStatus> statuses = new List<AssetStatusCache.AssetStatus>();
AssetStatusCache.GetAssetData(con, paths, statuses);
for (int i = 0; i < paths.Count; ++i)
{
_PendingChanges[i].State = statuses[i];
}
// Sort the changes
SortPendingChanges();
}
}
Profiler.EndSample();
}
void OnGUI()
{
CheckInit();
Event evt = Event.current;
// Header
GUIStyle changelistStyle = new GUIStyle(EditorStyles.toolbarButton);
changelistStyle.normal.textColor = Color.grey;
changelistStyle.alignment = TextAnchor.MiddleLeft;
// Buttons
GUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUI.BeginDisabledGroup(!Config.ValidConfiguration);
GUILayout.Label("Default Changelist: " + _PendingChanges.Count + " assets", changelistStyle, GUILayout.Width(200.0f));
if (GUILayout.Button("Refresh", EditorStyles.toolbarButton))
{
using (PerforceConnection con = new PerforceConnection())
{
ChangeManager.Refresh(-1);
UpdateList(con);
}
}
if (GUILayout.Button("Revert All Unchanged", EditorStyles.toolbarButton))
{
RevertUnchanged();
}
if (GUILayout.Button("Get Latest Assets", EditorStyles.toolbarButton))
{
if (EditorUtility.DisplayDialog("Get Latest Assets?", "Are you sure you want to update all assets to the latest revision?", "Ok", "Cancel"))
{
if (Engine.GetLatestAsset("", false).Count == 0)
{
Debug.Log("P4Connect - Get Latest Revision - No Change");
}
}
}
EditorGUI.EndDisabledGroup();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Help", EditorStyles.toolbarButton))
{
System.Diagnostics.Process.Start("http://www.perforce.com/perforce/doc.current/manuals/p4connectguide/index.html");
}
if (GUILayout.Button("Settings...", EditorStyles.toolbarButton))
{
Config.ShowWindow();
}
GUILayout.EndHorizontal();
EditorGUI.BeginDisabledGroup(!Config.ValidConfiguration);
GUILayout.BeginHorizontal();
_ScrollVector = GUILayout.BeginScrollView(_ScrollVector);
// Header
GUIStyle HeaderStyle = new GUIStyle(EditorStyles.miniButtonMid);
HeaderStyle.normal.textColor = Color.white;
HeaderStyle.padding = new RectOffset(0, 0, 0, 0);
HeaderStyle.margin = new RectOffset(0, 0, 0, 0);
HeaderStyle.overflow = new RectOffset(0, 0, 0, 0);
GUIStyle HeaderButtons = new GUIStyle(EditorStyles.miniButtonMid);
HeaderButtons.alignment = TextAnchor.MiddleLeft;
HeaderStyle.padding = new RectOffset(0, 0, 0, 2);
HeaderButtons.margin = new RectOffset(0, 0, 0, 0);
HeaderButtons.overflow = new RectOffset(0, 0, 0, 2);
GUIStyle ToggleStyle = new GUIStyle(EditorStyles.toggle);
RectOffset margin = ToggleStyle.margin;
margin.top = 0; margin.bottom = 0;
ToggleStyle.margin = margin;
GUIStyle normalStyle = new GUIStyle(GUIStyle.none);
normalStyle.padding = new RectOffset(0, 0, 0, 0);
normalStyle.margin = new RectOffset(0, 0, 0, 0);
normalStyle.border = new RectOffset(0, 0, 0, 0);
GUIStyle highlightedStyle = new GUIStyle(GUIStyle.none);
highlightedStyle.normal.background = _HighlightedBackground;
highlightedStyle.padding = new RectOffset(0, 0, 0, 0);
highlightedStyle.margin = new RectOffset(0, 0, 0, 0);
highlightedStyle.border = new RectOffset(0, 0, 0, 0);
GUIStyle selectedStyle = new GUIStyle(GUIStyle.none);
selectedStyle.normal.background = _SelectedBackground;
selectedStyle.padding = new RectOffset(0, 0, 0, 0);
selectedStyle.margin = new RectOffset(0, 0, 0, 0);
selectedStyle.border = new RectOffset(0, 0, 0, 0);
GUILayout.BeginHorizontal(HeaderStyle);
{
bool allSelected = _PendingChanges.Count(pc => _CheckedFiles[pc.EffectiveFilePath]) == _PendingChanges.Count;
bool newAllSelected = GUILayout.Toggle(allSelected, "", ToggleStyle, GUILayout.Width(10.0f));
if (newAllSelected != allSelected)
{
foreach (var pc in _PendingChanges)
{
_CheckedFiles[pc.EffectiveFilePath] = newAllSelected;
}
}
if (GUILayout.Button("", HeaderButtons, GUILayout.Width(spaceBeforeIcon)))
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
// Sort the files according to their extension
if (_CurrentSortingFunc == SelectedSortingFunc)
{
// Reverse the order if the sorting was already according to whether they are selected
_CurrentSortingAscending = !_CurrentSortingAscending;
}
else
{
// Make sorting according to the selection and reset the direction
_CurrentSortingFunc = SelectedSortingFunc;
_CurrentSortingAscending = true;
}
SortPendingChanges();
}
if (GUILayout.Button("", HeaderButtons, GUILayout.Width(iconSize)))
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
// Sort the files according to their extension
if (_CurrentSortingFunc == ExtensionSortingFunc)
{
// Reverse the order if the sorting was already according to the extension
_CurrentSortingAscending = !_CurrentSortingAscending;
}
else
{
// Make sorting according to the extension and reset the direction
_CurrentSortingFunc = ExtensionSortingFunc;
_CurrentSortingAscending = true;
}
SortPendingChanges();
}
if (GUILayout.Button("Filename", HeaderButtons, GUILayout.Width(250.0f)))
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
// Sort the files according to their name
if (_CurrentSortingFunc == FilenameSortingFunc)
{
// Reverse the order if the sorting was already according to the name
_CurrentSortingAscending = !_CurrentSortingAscending;
}
else
{
// Make sorting according to the name and reset the direction
_CurrentSortingFunc = FilenameSortingFunc;
_CurrentSortingAscending = true;
}
SortPendingChanges();
}
if (GUILayout.Button("in Directory", HeaderButtons, GUILayout.MinWidth(250.0f)))
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
if (_CurrentSortingFunc == DirectorySortingFunc)
{
_CurrentSortingAscending = !_CurrentSortingAscending;
}
else
{
_CurrentSortingFunc = DirectorySortingFunc;
_CurrentSortingAscending = true;
}
SortPendingChanges();
}
//GUILayout.FlexibleSpace();
if (GUILayout.Button("Type", HeaderButtons, GUILayout.Width(80.0f)))
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
if (_CurrentSortingFunc == TypeSortingFunc)
{
_CurrentSortingAscending = !_CurrentSortingAscending;
}
else
{
_CurrentSortingFunc = TypeSortingFunc;
_CurrentSortingAscending = true;
}
SortPendingChanges();
}
if (GUILayout.Button("Change", HeaderButtons, GUILayout.Width(80.0f)))
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
if (_CurrentSortingFunc == StateSortingFunc)
{
_CurrentSortingAscending = !_CurrentSortingAscending;
}
else
{
_CurrentSortingFunc = StateSortingFunc;
_CurrentSortingAscending = true;
}
SortPendingChanges();
}
GUILayout.Space(32.0f);
}
GUILayout.EndHorizontal();
// Add all the items
foreach (var change in _PendingChanges)
{
if (_LastSelectedChange == change && focusedWindow == this)
{
if (_CurrentSelectedChanges.Contains(_LastSelectedChange))
{
GUILayout.BeginHorizontal(highlightedStyle);
}
else
{
GUILayout.BeginHorizontal(normalStyle);
}
}
else if (_CurrentSelectedChanges.Contains(change))
{
GUILayout.BeginHorizontal(selectedStyle);
}
else
{
GUILayout.BeginHorizontal(normalStyle);
}
// Draw a selection box
bool itemChecked = _CheckedFiles[change.EffectiveFilePath];
bool newItemChecked = GUILayout.Toggle(itemChecked, "", EditorStyles.toggle, GUILayout.Width(10.0f));
if (newItemChecked != itemChecked)
{
if (_CurrentSelectedChanges.Contains(change))
{
foreach (var ch in _CurrentSelectedChanges)
{
_CheckedFiles[ch.EffectiveFilePath] = newItemChecked;
}
}
else
{
_CheckedFiles[change.EffectiveFilePath] = newItemChecked;
}
}
GUILayout.Space(spaceBeforeIcon);
// Fetch the asset's icon and draw it
Texture assetTexture = Icons.GetAssetIcon(change.AssetPath);
GUILayout.Label(assetTexture, GUILayout.Width(iconSize), GUILayout.Height(iconSize));
// Then decorate it with status icons
Rect iconRect = GUILayoutUtility.GetLastRect();
iconRect.yMin -= 1.0f;
iconRect.xMax -= 0.5f;
iconRect.yMax += 16.0f;
Icons.DrawItemIcons(change.EffectiveFilePath, iconRect, false);
// And the name of the asset
GUILayout.Label(System.IO.Path.GetFileName(change.AssetPath), GUILayout.Width(250.0f));
GUILayout.Label(System.IO.Path.GetDirectoryName(change.AssetPath), GUILayout.MinWidth(250.0f));
GUILayout.FlexibleSpace();
// Now indicate if we have the file and/or the meta
GUILayout.Label(Utils.GetStorageTypeString(change.State.StorageType), GUILayout.Width(80.0f));
GUILayout.Label(Utils.GetFileStateString(change.State.LocalState), GUILayout.Width(80.0f));
GUILayout.Label(Icons.GetFileAndMetaTypeIcon(change.Type), GUILayout.Width(iconSize), GUILayout.Height(iconSize));
GUILayout.EndHorizontal();
Rect lastRect = GUILayoutUtility.GetLastRect();
if (_LastSelectedChange == change && focusedWindow == this && !_CurrentSelectedChanges.Contains(_LastSelectedChange))
{
Rect topLine = lastRect; topLine.yMax = topLine.yMin + 1;
Rect bottomLine = lastRect; bottomLine.yMin = bottomLine.yMax - 1;
Rect leftLine = lastRect; leftLine.xMin += 1; leftLine.xMax = leftLine.xMin + 1;
Rect rightLine = lastRect; rightLine.xMin = rightLine.xMax - 1;
GUI.Box(topLine, GUIContent.none, highlightedStyle);
GUI.Box(bottomLine, GUIContent.none, highlightedStyle);
GUI.Box(leftLine, GUIContent.none, highlightedStyle);
GUI.Box(rightLine, GUIContent.none, highlightedStyle);
}
if (lastRect.Contains(evt.mousePosition))
{
// Handle events here
if (evt.isMouse)
{
if (evt.type == EventType.MouseDown)
{
if (GUI.GetNameOfFocusedControl() == "DescriptionBox")
{
GUI.FocusControl("");
}
if (evt.button == 0)
{
if ((evt.modifiers & EventModifiers.Control) != 0)
{
// Ctrl means Add/remove from selection
if (_CurrentSelectedChanges.Contains(change))
{
_CurrentSelectedChanges.Remove(change);
}
else
{
_CurrentSelectedChanges.Add(change);
}
}
else if ((evt.modifiers & EventModifiers.Shift) != 0)
{
// Shift means select all between this and previous selected
foreach (var ch in GetChangesBetweenChanges(_LastSelectedChange, change))
{
_CurrentSelectedChanges.Add(ch);
}
}
else
{
if (change == _LastSelectedChange)
{
// Is this a double click?
if ((DateTime.Now - _LastSelectedChangeTime).TotalMilliseconds < DoubleClickTime)
{
// Yes, open the asset
if (_LastSelectedChange.AssetPath != null || _LastSelectedChange.AssetPath != "")
{
UnityEngine.Object asset = AssetDatabase.LoadMainAssetAtPath(_LastSelectedChange.AssetPath);
AssetDatabase.OpenAsset(asset);
}
}
}
else
{
// Clear selection and set it to new element
_CurrentSelectedChanges.Clear();
_CurrentSelectedChanges.Add(change);
}
}
// In all cases, we remember the last selected change
_LastSelectedChange = change;
_LastSelectedChangeTime = DateTime.Now;
evt.Use();
Repaint();
}
else if (evt.button == 1)
{
// In all cases, we remember the last selected change
_LastSelectedChange = change;
evt.Use();
Repaint();
}
}
else if (evt.type == EventType.MouseUp)
{
if (evt.button == 1)
{
if (!_CurrentSelectedChanges.Contains(change) && (evt.modifiers & EventModifiers.Control) == 0)
{
// Anything other than Ctrl Deselects
_CurrentSelectedChanges.Clear();
_CurrentSelectedChanges.Add(change);
}
// Display contextual menu
Rect menuRect = lastRect;
menuRect.xMin = evt.mousePosition.x;
menuRect.yMin = evt.mousePosition.y;
EditorUtility.DisplayPopupMenu(menuRect, "CONTEXT/Perforce/", new MenuCommand(this));
evt.Use();
}
}
}
}
}
GUILayout.EndScrollView();
GUILayout.EndHorizontal();
EditorGUI.EndDisabledGroup();
if (!Config.PerforceEnabled)
{
EditorGUILayout.HelpBox("Perforce integration is disabled", MessageType.Info);
}
else if (!Config.ValidConfiguration)
{
EditorGUILayout.HelpBox("Pending Changes are unavailable because your settings are invalid.\nPlease go to Edit->Perforce Settings to update them.", MessageType.Warning);
}
EditorGUI.BeginDisabledGroup(!Config.ValidConfiguration);
GUILayout.Label("Description", EditorStyles.boldLabel);
GUI.SetNextControlName("DescriptionBox");
_ChangeListDescription = EditorGUILayout.TextArea(_ChangeListDescription, GUILayout.MinHeight(50.0f));
GUILayout.BeginHorizontal();
int unresolvedCount = _PendingChanges.Count(ch => _CheckedFiles[ch.EffectiveFilePath] && ch.State.ResolvedState == ResolvedState.NeedsResolve);
int outOfDateCount = _PendingChanges.Count(ch => _CheckedFiles[ch.EffectiveFilePath] && ch.State.RevisionState == RevisionState.OutOfDate);
if (unresolvedCount > 0)
{
Color prevColor = GUI.color;
GUI.color = Color.yellow;
GUILayout.Label(unresolvedCount.ToString() + " unresolved assets selected!");
GUI.color = prevColor;
}
else if (outOfDateCount > 0)
{
Color prevColor = GUI.color;
GUI.color = Color.yellow;
GUILayout.Label(outOfDateCount.ToString() + " out of date assets selected!");
GUI.color = prevColor;
}
GUILayout.FlexibleSpace();
int assetCount = 0;
int fileCount = 0;
GetSelectedCounts(out assetCount, out fileCount);
GUILayout.Label(assetCount.ToString() + " assets selected (" + fileCount.ToString() + " files)");
EditorGUI.BeginDisabledGroup(_ChangeListDescription == null || _ChangeListDescription.Length == 0 || unresolvedCount > 0 || outOfDateCount > 0);
if (GUILayout.Button("Submit Selected"))
{
SubmitFiles();
}
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
EditorGUI.EndDisabledGroup();
// Handle key events
if (evt.isKey)
{
if (evt.type == EventType.KeyDown)
{
if (evt.keyCode == KeyCode.Return)
{
// Toggle all selected changes to the new state of the selected item
bool itemChecked = _CheckedFiles[_LastSelectedChange.EffectiveFilePath];
foreach (var ch in _CurrentSelectedChanges)
{
_CheckedFiles[ch.EffectiveFilePath] = !itemChecked;
}
evt.Use();
Repaint();
}
else if (evt.keyCode == KeyCode.DownArrow)
{
// Update highlight
_LastSelectedChange = GetNextPendingChange(_LastSelectedChange);
// Handle shift selection
if ((evt.modifiers & EventModifiers.Shift) == 0 && (evt.modifiers & EventModifiers.Control) == 0)
{
_CurrentSelectedChanges.Clear();
}
_CurrentSelectedChanges.Add(_LastSelectedChange);
evt.Use();
Repaint();
}
else if (evt.keyCode == KeyCode.UpArrow)
{
_LastSelectedChange = GetPrevPendingChange(_LastSelectedChange);
if ((evt.modifiers & EventModifiers.Shift) == 0 && (evt.modifiers & EventModifiers.Control) == 0)
{
_CurrentSelectedChanges.Clear();
}
_CurrentSelectedChanges.Add(_LastSelectedChange);
evt.Use();
Repaint();
}
else if (evt.keyCode == KeyCode.A)
{
_CurrentSelectedChanges.Clear();
foreach (var change in _PendingChanges)
{
_CurrentSelectedChanges.Add(change);
}
evt.Use();
Repaint();
}
else if (evt.keyCode == KeyCode.D)
{
foreach (var change in _CurrentSelectedChanges)
{
Utils.LaunchDiffAgainstHaveRev(change.EffectiveFilePath);
}
evt.Use();
Repaint();
}
else if (evt.keyCode == KeyCode.I)
{
HashSet<PendingAssetAndMeta> newSelection = new HashSet<PendingAssetAndMeta>();
foreach (var change in _PendingChanges)
{
if (!_CurrentSelectedChanges.Contains(change))
{
newSelection.Add(change);
}
}
_CurrentSelectedChanges = newSelection;
evt.Use();
Repaint();
}
}
}
}
void GetSelectedCounts(out int aOutAssetCount, out int aOutFileCount)
{
int assetCount = 0;
int fileCount = 0;
for (int i = 0; i < _PendingChanges.Count; i++)
{
var change = _PendingChanges[i];
if (_CheckedFiles[change.EffectiveFilePath])
{
assetCount += 1;
switch (change.Type)
{
case FileAndMetaType.FileOnly:
fileCount += 1;
break;
case FileAndMetaType.MetaOnly:
fileCount += 1;
break;
case FileAndMetaType.FileAndMeta:
fileCount += 2;
break;
}
}
}
aOutAssetCount = assetCount;
aOutFileCount = fileCount;
}
void SubmitFiles()
{
List<FileSpec> specsToSubmit = new List<FileSpec>();
// Build a string of the names
StringBuilder builder = new StringBuilder();
builder.AppendLine("Are you sure you want to submit the following files?");
builder.AppendLine();
int maxCount = 20;
int curCount = 0;
for (int i = 0; i < _PendingChanges.Count; i++)
{
var change = _PendingChanges[i];
if (_CheckedFiles[change.EffectiveFilePath])
{
switch (change.Type)
{
case FileAndMetaType.FileOnly:
{
string filepath = Utils.AssetPathToLocalPath(change.AssetPath);
specsToSubmit.Add(FileSpec.LocalSpec(filepath));
if (++curCount <= maxCount)
builder.AppendLine(change.AssetPath);
}
break;
case FileAndMetaType.MetaOnly:
{
string filepath = Utils.AssetPathToLocalPath(change.MetaPath);
specsToSubmit.Add(FileSpec.LocalSpec(filepath));
if (++curCount <= maxCount)
builder.AppendLine(change.MetaPath);
}
break;
case FileAndMetaType.FileAndMeta:
{
string filepath = Utils.AssetPathToLocalPath(change.AssetPath);
specsToSubmit.Add(FileSpec.LocalSpec(filepath));
if (++curCount <= maxCount)
builder.AppendLine(change.AssetPath);
}
{
string filepath = Utils.AssetPathToLocalPath(change.MetaPath);
specsToSubmit.Add(FileSpec.LocalSpec(filepath));
if (++curCount <= maxCount)
builder.AppendLine(change.MetaPath);
}
break;
}
}
}
if (curCount > maxCount)
{
builder.Append("...");
}
if (EditorUtility.DisplayDialog("Submit changes?", builder.ToString(), "Submit", "Cancel"))
{
Engine.PerformConnectionOperation(con => Engine.SubmitFiles(con, _ChangeListDescription, specsToSubmit));
_ChangeListDescription = "";
GUI.FocusControl("");
}
}
void RevertUnchanged()
{
List<string> filesToRevert = new List<string>();
for (int i = 0; i < _PendingChanges.Count; i++)
{
var change = _PendingChanges[i];
switch (change.Type)
{
case FileAndMetaType.FileOnly:
filesToRevert.Add(change.AssetPath);
break;
case FileAndMetaType.MetaOnly:
filesToRevert.Add(change.MetaPath);
break;
case FileAndMetaType.FileAndMeta:
filesToRevert.Add(change.AssetPath);
filesToRevert.Add(change.MetaPath);
break;
}
}
if (Engine.RevertAssets(filesToRevert.ToArray(), false).Count == 0)
{
Debug.Log("P4Connect - Revert if Unchanged - No Change");
}
}
string SelectedSortingFunc(PendingAssetAndMeta aAssetAndMeta)
{
return _CheckedFiles[aAssetAndMeta.EffectiveFilePath] ? "A" : "B";
}
static string ExtensionSortingFunc(PendingAssetAndMeta aAssetAndMeta)
{
return System.IO.Path.GetExtension(aAssetAndMeta.EffectiveFilePath);
}
static string FilenameSortingFunc(PendingAssetAndMeta aAssetAndMeta)
{
return System.IO.Path.GetFileName(aAssetAndMeta.EffectiveFilePath);
}
static string DirectorySortingFunc(PendingAssetAndMeta aAssetAndMeta)
{
return System.IO.Path.GetDirectoryName(aAssetAndMeta.EffectiveFilePath);
}
static string StateSortingFunc(PendingAssetAndMeta aAssetAndMeta)
{
return Utils.GetFileStateString(aAssetAndMeta.State.LocalState);
}
static string TypeSortingFunc(PendingAssetAndMeta aAssetAndMeta)
{
return Utils.GetStorageTypeString(aAssetAndMeta.State.StorageType);
}
void SortPendingChanges()
{
if (_CurrentSortingFunc != null)
{
List<PendingAssetAndMeta> newList = null;
if (_CurrentSortingAscending)
newList = new List<PendingAssetAndMeta>(_PendingChanges.OrderBy(_CurrentSortingFunc));
else
newList = new List<PendingAssetAndMeta>(_PendingChanges.OrderByDescending(_CurrentSortingFunc));
_PendingChanges = newList;
}
}
PendingAssetAndMeta GetPrevPendingChange(PendingAssetAndMeta aCurrent)
{
int index = _PendingChanges.IndexOf(aCurrent);
return _PendingChanges[Mathf.Clamp(index - 1, 0, _PendingChanges.Count)];
}
PendingAssetAndMeta GetNextPendingChange(PendingAssetAndMeta aCurrent)
{
int index = _PendingChanges.IndexOf(aCurrent);
return _PendingChanges[Mathf.Clamp(index + 1, 0, _PendingChanges.Count)];
}
IEnumerable<PendingAssetAndMeta> GetChangesBetweenChanges(PendingAssetAndMeta aStart, PendingAssetAndMeta aEndIncluded)
{
int indexStart = _PendingChanges.IndexOf(aStart);
int indexEnd = _PendingChanges.IndexOf(aEndIncluded);
for (int i = indexStart; i <= indexEnd; ++i)
{
yield return _PendingChanges[i];
}
}
public void SelectAssets(IEnumerable<string> aEffectiveFilePaths)
{
// Deselect all
List<string> files = new List<string>(_CheckedFiles.Keys);
foreach (var file in files)
{
_CheckedFiles[file] = false;
}
// Select files passed in
foreach (var file in aEffectiveFilePaths)
{
bool state = false;
if (_CheckedFiles.TryGetValue(file, out state))
{
_CheckedFiles[file] = true;
}
}
}
}
}
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 12954 | anis_sg |
Populate -o //guest/perforce_software/p4connect/... //guest/anis_sg/perforce_software/p4connect/.... |
||
| //guest/perforce_software/p4connect/src/P4Connect/P4Connect/P4Connect.PendingChanges.cs | |||||
| #7 | 12862 | Norman Morse |
Fixed problem with an empty default change list not refresshing. Fixed crash in is_ignored Removed a lot of log output |
||
| #6 | 12565 | Norman Morse |
Integrated from Dev Branch Made ChangeManager into Static Class. Improved close window behavior for when connection is invalid Fixed localOpenFiles not updating on submit |
||
| #5 | 12553 | Norman Morse |
integrate from internal main Build fixes for EC. Major changes to Configuration and re-initialization code. Bug fixes |
||
| #4 | 12512 | Norman Morse | Integrate from Dev branch, preparing for Beta3 release | ||
| #3 | 12362 | Norman Morse |
Added Debug Logging for p4log Fixed some path comparison issues. Created a CaseSensitivity test |
||
| #2 | 11223 | Norman Morse | Fixed typo in comment | ||
| #1 | 10940 | Norman Morse |
Inital Workshop release of P4Connect. Released under BSD-2 license |
||