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<ChangeListEntry> //{ // 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<Changelist> _changes; private static Dictionary<int, ChangeInfo> _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<ChangeListsWindow>(_windowName); _pInstance.titleContent = new GUIContent(_windowName); _pInstance.minSize = new UnityEngine.Vector2(350.0f, 130.0f); } // Where is our scroll view? private static Vector2 _scrollVector; /// <summary> /// Utility class used to keep GUI state between uses. /// Kept in a dictionary by change_id /// </summary> 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; /// <summary> /// Quick Method called from OnGUI to make sure that skin initialization occurs at the right time /// </summary> static void CheckInit() { if (!_styleInitialized) { Skin.InitializeSkin(); _styleInitialized = true; } } public void OnEnable() { if (_changeInfo == null) _changeInfo = new Dictionary<int, ChangeInfo>(); 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<LineContents>(); // 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; /// <summary> /// Called during layout event /// Computes location and size of scroll view within the data. /// </summary> 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; } /// <summary> /// /// </summary> 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(); } /// <summary> /// Display a header line (made of buttons for future use) /// </summary> 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<PendingAssetAndMeta> newSelection = new HashSet<PendingAssetAndMeta>(); // //foreach (var change in _PendingChanges) // //{ // // if (!_CurrentSelectedChanges.Contains(change)) // // { // // newSelection.Add(change); // // } // //} // //_CurrentSelectedChanges = newSelection; // evt.Use(); // Repaint(); // } // } // } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 20581 | Norman Morse |
Add P4Connect.Skin Fixed issues in ChangeManager Renamed ChangeLists to ChangeListsWindow. |
||
//guest/perforce_software/p4connect/main/src/P4Connect/P4Connect/P4Connect.ChangeLists.cs | |||||
#3 | 20275 | Norman Morse |
Update source to match 2016.2 patch 2 release Much thrashing of source during refactor. Proper caching of asset statuses, reducing fstats issued. Some bug fixes by Liz Lam Cleanup of Pending changes, rework of initialization and play/stop play transitions |
||
#2 | 19279 | Norman Morse |
Update workshop from internal changes. These Changes are the basis of the 2016.2 release - Dropped support for Unity 4 - Built in Unity 5 - Fixed assembly misidentifications. - Fixed problem where configuration dialog would pop up between runs |
||
#1 | 16209 | Norman Morse | Move entire source tree into "main" branch so workshop code will act correctly. | ||
//guest/perforce_software/p4connect/src/P4Connect/P4Connect/P4Connect.ChangeLists.cs | |||||
#4 | 14193 | Norman Morse |
GA.7 release Refactor Pending Changes Resolve Submit issues. Fixed Menu entries. Handle mismatched file and meta states. |
||
#3 | 12568 | Norman Morse | Fixed some error handling during Perforce Configuration | ||
#2 | 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 |
||
#1 | 12512 | Norman Morse | Integrate from Dev branch, preparing for Beta3 release | ||
//guest/norman_morse/dev/p4connect/src/P4Connect/P4Connect/P4Connect.ChangeLists.cs | |||||
#3 | 12501 | Norman Morse |
Rewrote Configuration Window. Provided buttons to read values and to save configurations. Removed P4Config settings, replaced with P4Config button and reports to Debug.Log() Removed SaveConfigurationAsset Setting, replaced with "Save as Asset" button. Made Connection Configuration read only while connected. Made dialogs disappear if they become disconnected during OnGui() Bumped Beta Value. |
||
#2 | 12480 | Norman Morse |
Fixed crash in logging. Worked on UI issues. Cleaned up some connection usage. Still looking for the problem with pending changes. |
||
#1 | 12445 | Norman Morse |
Integrated log4net and nunit into P4Connect. Still need cleanup and debugging, good enough for dev tree Also added ChangeManager and ChangeLists Classes for future use with multiple changes. |