using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using log4net; using Perforce.P4; namespace P4Connect { //#region ChangeListEntry //public class ChangeListEntry : IComparable //{ // public Changelist change; // public ChangeListEntry(Changelist c) // { // change = c; // show_children = true; // } // public void Refresh(Connection con) // { // change.initialize(con); // } // public int CompareTo(ChangeListEntry entry) // { // return this.change.Id.CompareTo(entry.change.Id); // } // private bool show_children; // public bool ShowChildren // { // get { return show_children; } // set { show_children = value; } // } // public static string ChangeIdToString(int id) // { // if (id <= 0) // return "default"; // return id.ToString(); // } //} //#endregion public class ChangeListsWindow : EditorWindow { private static bool _styleInitialized; private static readonly ILog log = LogManager.GetLogger(typeof(ChangeListsWindow)); const float SpaceBeforeIcon = 8.0f; const float IconSize = 20.0f; const float ColWidthChange = 60.0f; const float ColWidthDesc = 250f; const float ColWidthFiles = 50f; const float ColWidthShelves = 50f; const float ColWidthUser = 100f; const float ColWidthWorkspace = 100f; const double DoubleClickTime = 500; // ms private static ChangeListsWindow _pInstance; private static IList _changes; private static Dictionary _changeInfo; private static GUIContent _refreshIcon; private static Texture _otherFile; private static string _windowName = "Changes"; [MenuItem("Window/Perforce Changes", false, 1000)] public static void ShowWindow() { // Get existing open window or if none, make a new one: _pInstance = EditorWindow.GetWindow(_windowName); _pInstance.titleContent = new GUIContent(_windowName); _pInstance.minSize = new UnityEngine.Vector2(350.0f, 130.0f); } // Where is our scroll view? private static Vector2 _scrollVector; /// /// Utility class used to keep GUI state between uses. /// Kept in a dictionary by change_id /// private class ChangeInfo { public bool Opened { get; set; } public GUIContent Content { get; set; } public ChangeInfo(bool open, GUIContent content) { Opened = open; Content = content; } } private class LineContents { public Changelist Change; public FileMetaData Fmd; public LineContents(Changelist c, FileMetaData f) { Change = c; Fmd = f; } public override string ToString() { if (Change != null) return ("Change: " + Change.Id); if (Fmd != null) return ("File: " + Fmd.LocalPath); return (""); } } private static LineContents[] _lines; /// /// Quick Method called from OnGUI to make sure that skin initialization occurs at the right time /// static void CheckInit() { if (!_styleInitialized) { Skin.InitializeSkin(); _styleInitialized = true; } } public void OnEnable() { if (_changeInfo == null) _changeInfo = new Dictionary(); if (_refreshIcon == null) _refreshIcon = new GUIContent(Icons.GetIcon("rotate-cw.png")); if (_otherFile == null) _otherFile = Icons.GetIcon("other-file.png"); Reload(true); // Force reload } void Reload(bool force=false) { _changes = ChangeManager.Changelists; ChangeManager.PrepareChange(ChangeManager.DEFAULT_CHANGE, force); var lineList = new List(); // Build changeInfo entries for each change ID in the list. foreach (var change in _changes) { if (!_changeInfo.ContainsKey(change.Id)) { _changeInfo.Add(change.Id, new ChangeInfo(false, new GUIContent() { text = changeIdString(change.Id), //image = Icons.GetChangelistIcon(change), tooltip = "Open/Close Change" })); } // Create the Lines Array reflecting current state of "open" / "closed" for each change. lineList.Add(new LineContents(change,null)); if (_changeInfo[change.Id].Opened) { foreach (var f in change.Files) { lineList.Add(new LineContents(null, f)); } } } _lines = lineList.ToArray(); //log.Debug("Reload Complete " + _lines.Length + " lines"); Repaint(); } void OnInspectorUpdate() { Repaint(); } void OnSelectionChange() { //Repaint(); } public void OnDestroy() { _pInstance = null; Clear(); } void Clear() { _scrollVector = Vector2.zero; } void Update() { if (!Config.ValidConfiguration) { this.Close(); Debug.Log("Closed ChangeListsWindow because Connection is invalid"); } } private int FileCnt(Changelist change) { if (change.Files != null) return (change.Files.Count); return 0; } private int ShelveCount(Changelist change) { if (change.ShelvedFiles != null) return (change.ShelvedFiles.Count); return 0; } private string changeIdString(int changeId) { if (changeId < 0) return "Default change"; return "Change " + changeId; } private const int CItemHeight = 20; // Should Match IconSize private Vector2 _scrollPosition; private Rect _lastRect; private int _itemCount; private int _itemsAbove, _itemsToRender, _itemsBelow; /// /// Called during layout event /// Computes location and size of scroll view within the data. /// private void CalculateWhatItemsToRender() { _itemsAbove = (int)(_scrollPosition.y / CItemHeight); _itemsToRender = (int)(_lastRect.height / CItemHeight); if (_itemsAbove + _itemsToRender > _itemCount - 2) { _itemsToRender += 1; } else { _itemsToRender += 2; } _itemsBelow = _itemCount - _itemsAbove - _itemsToRender; if (_itemsBelow < 0) _itemsBelow = 0; } /// /// /// void OnGuiToolbar() { // Toolbar Buttons GUILayout.BeginHorizontal(Skin.ToolBarStyle, GUILayout.Height(IconSize)); // GUILayout.Label("Pending Changelists ", Skin.ToolBarLabelStyle, GUILayout.Width(200.0f)); GUILayout.Label(" "); if (GUILayout.Button("Outgoing", Skin.ToolBarButtonStyle)) { // Do outgoing stuff } if (GUILayout.Button("Incoming", Skin.ToolBarButtonStyle)) { // Do incoming stuff } GUILayout.FlexibleSpace(); if (GUILayout.Button("Settings...", Skin.ToolBarButtonStyle)) { ConfigWindow.ShowWindow(); } //if (GUILayout.Button(_refreshIcon, GUILayout.Width(IconSize), GUILayout.Height(IconSize))) if (GUILayout.Button("Refresh", Skin.ToolBarButtonStyle)) { Reload(true); } if (GUILayout.Button("Help", Skin.ToolBarButtonStyle)) { System.Diagnostics.Process.Start( "http://www.perforce.com/perforce/doc.current/manuals/p4connectguide/index.html"); } GUILayout.EndHorizontal(); } /// /// Display a header line (made of buttons for future use) /// void OnGuiHeader() { GUILayout.BeginHorizontal(Skin.HeaderStyle); { if (GUILayout.Button("", Skin.HeaderButton, GUILayout.Width(SpaceBeforeIcon))) { } if (GUILayout.Button("", Skin.HeaderButton, GUILayout.Width(IconSize))) { } if (GUILayout.Button("ChangeId", Skin.HeaderButton, GUILayout.Width(ColWidthChange))) { } if (GUILayout.Button("Description", Skin.HeaderButton, GUILayout.Width(ColWidthDesc))) { } GUILayout.FlexibleSpace(); if (GUILayout.Button("Files", Skin.HeaderButton, GUILayout.Width(ColWidthFiles))) { } if (GUILayout.Button("Shelves", Skin.HeaderButton, GUILayout.Width(ColWidthShelves))) { } if (GUILayout.Button("User", Skin.HeaderButton, GUILayout.Width(ColWidthUser))) { } if (GUILayout.Button("Workspace", Skin.HeaderButton, GUILayout.Width(ColWidthWorkspace))) { } GUILayout.Space(32.0f); } GUILayout.EndHorizontal(); } void OnGuiChangeSummary(Changelist change) { GUILayout.BeginHorizontal(Skin.NormalStyle); bool oldValue = _changeInfo[change.Id].Opened; bool bValue = oldValue; if (GUILayout.Button(Icons.GetChangelistIcon(change), GUI.skin.GetStyle("miniLabel"), GUILayout.Height(IconSize), GUILayout.Width(IconSize))) { bValue = !oldValue; } Rect pos = GUILayoutUtility.GetRect(_changeInfo[change.Id].Content, Skin.FoldOutStyle); var fValue = EditorGUI.Foldout(pos, oldValue, _changeInfo[change.Id].Content, true, Skin.FoldOutStyle); if (fValue != oldValue || bValue != oldValue) { //log.Debug(oldValue ? "Closed Foldout" : "Opened Foldout"); _changeInfo[change.Id].Opened = ! oldValue; Reload(); return; } GUILayout.FlexibleSpace(); //int fcnt = fileCnt(change); //int scnt = shelveCount(change); //GUILayout.Label(fcnt.ToString(), GUILayout.Width(ColWidthFiles)); //GUILayout.Label(scnt.ToString(), GUILayout.Width(ColWidthShelves)); //GUILayout.Label(change.OwnerName, GUILayout.Width(ColWidthUser)); //GUILayout.Label(change.ClientId, GUILayout.Width(ColWidthWorkspace)); GUILayout.EndHorizontal(); } void OnGuiChangeContents(Changelist change) { foreach (FileMetaData fmd in change.Files) { log.Debug("show file: " + fmd.ToAssetPath()); OnGuiFileLine(fmd); //var assetPath = Utils.DepotPathToAssetPath(fd.DepotPath.Path); //var icon = Utils.IsMetaFile(assetPath) ? Icons.GetIcon("other-file.png") : AssetDatabase.GetCachedIcon(assetPath); //GUILayout.BeginHorizontal(Skin.NormalStyle); //GUILayout.Space(SpaceBeforeIcon); //GUILayout.Label(icon, GUILayout.Width(IconSize), GUILayout.Height(IconSize)); //Rect pos = GUILayoutUtility.GetLastRect(); //Icons.DrawItemIcons(AssetStatusCache.GetCachedAssetStatus(assetPath),false,pos,true); //GUILayout.Label(assetPath); //GUILayout.FlexibleSpace(); ////GUILayout.Label(fd.Action.ToString()); //GUILayout.EndHorizontal(); } if (change.Shelved && change.ShelvedFiles != null) { GUILayout.Label("Shelves:"); foreach (ShelvedFile sf in change.ShelvedFiles) { GUILayout.BeginHorizontal(Skin.NormalStyle); GUILayout.Space(SpaceBeforeIcon); GUILayout.Label(sf.Path.ToString()); GUILayout.FlexibleSpace(); //GUILayout.Label(sf.Action.ToString()); GUILayout.EndHorizontal(); } } } private void OnGuiFileLine(FileMetaData fmd) { // Get a style for this line (if selected or not) var assetPath = Utils.DepotPathToAssetPath(fmd.DepotPath.Path); var icon = Utils.IsMetaFile(assetPath) ? _otherFile : AssetDatabase.GetCachedIcon(assetPath); GUILayout.BeginHorizontal(Skin.FoldOutEntryStyle); GUILayout.Space(IconSize); GUILayout.Label(icon, GUILayout.Width(IconSize), GUILayout.Height(IconSize)); Rect pos = GUILayoutUtility.GetLastRect(); Icons.DrawItemIcons(AssetStatusCache.GetCachedAssetStatus(assetPath), false, pos, true); GUILayout.Label(assetPath,Skin.FoldOutEntryStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } void OnGUI() { CheckInit(); if (Event.current == null || !Config.IsEditing()) { GUIUtility.ExitGUI(); } OnGuiToolbar(); var newScroll = GUILayout.BeginScrollView(_scrollPosition, false, false, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, GUI.skin.box); if (newScroll != _scrollPosition) { _scrollPosition = newScroll; Repaint(); } if (_lines.Length == 0) { GUILayout.BeginHorizontal(Skin.NormalStyle); GUILayout.Label("no changelists", GUILayout.Width(400.0f)); GUILayout.EndHorizontal(); } else { if (Event.current.type == EventType.Layout && _lastRect.height > 0) { _itemCount = _lines.Length; //log.Debug("LastRect: " + _lastRect.ToStringNullSafe()); //log.Debug("ItemCount: " + _itemCount); CalculateWhatItemsToRender(); //log.Debug("ItemsAbove: " + _itemsAbove); //log.Debug("ItemsToRender: " + _itemsToRender); //log.Debug("itemsBelow: " + _itemsBelow); } GUILayout.Space(_itemsAbove * CItemHeight); // Items Above for (int j = 0, i = _itemsAbove; j < _itemsToRender; j++, i++) { if (i >= _lines.Length) break; if (_lines[i].Change != null) { OnGuiChangeSummary(_lines[i].Change); } if (_lines[i].Fmd != null) { OnGuiFileLine(_lines[i].Fmd); } } GUILayout.Space(_itemsBelow * CItemHeight); // items below } GUILayout.EndScrollView(); if (Event.current.type == EventType.Repaint) { _lastRect = GUILayoutUtility.GetLastRect(); // save the rect for the scrolling area. } // 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) // { // //reach (var change in _CurrentSelectedChanges) // // // // Utils.LaunchDiffAgainstHaveRev(change.EffectiveFilePath); // // // evt.Use(); // Repaint(); // } // else if (evt.keyCode == KeyCode.I) // { // //HashSet newSelection = new HashSet(); // //foreach (var change in _PendingChanges) // //{ // // if (!_CurrentSelectedChanges.Contains(change)) // // { // // newSelection.Add(change); // // } // //} // //_CurrentSelectedChanges = newSelection; // evt.Use(); // Repaint(); // } // } // } } } }