Commit 1c847220 authored by jang dong hyeok's avatar jang dong hyeok
Browse files

.

parent 076f0c68
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Help
{
internal class FormattedHelpLink
{
internal HelpLink Source;
internal int Position;
internal int Length;
}
internal static class BuildFormattedHelp
{
internal static void ForData(
string plainText,
HelpFormat[] formattedBlocks,
HelpLink[] links,
out string formattedHelpText,
out List<FormattedHelpLink> formattedLinks)
{
formattedHelpText = string.Empty;
formattedLinks = new List<FormattedHelpLink>();
List<object> segments = new List<object>();
segments.AddRange(formattedBlocks);
segments.AddRange(links);
var sortedSegments = segments.OrderBy(
n => n is HelpFormat ?
((HelpFormat)n).Position :
((HelpLink)n).Position);
StringBuilder sb = new StringBuilder();
int lastIndex = 0;
foreach (var segment in sortedSegments)
{
Segment.Data segmentData = GetSegmentData(segment);
if (segmentData.Begin > lastIndex)
sb.Append(plainText.Substring(lastIndex, segmentData.Begin - lastIndex));
string plainSegment = plainText.Substring(
segmentData.Begin, segmentData.Length);
if (segment is HelpLink)
{
formattedLinks.Add(new FormattedHelpLink()
{
Source = (HelpLink)segment,
Position = sb.Length,
Length = segmentData.Prefix.Length +
plainSegment.Length +
segmentData.Suffix.Length
});
}
sb.Append(segmentData.Prefix);
sb.Append(plainSegment);
sb.Append(segmentData.Suffix);
lastIndex = segmentData.Begin + segmentData.Length;
}
sb.Append(plainText.Substring(lastIndex));
formattedHelpText = sb.ToString();
}
internal static bool IsLinkMetaChar(
FormattedHelpLink formattedLink,
int charIndex)
{
int prefixEndIndex =
formattedLink.Position +
Segment.LINK_PREFIX.Length - 1;
if (formattedLink.Position <= charIndex &&
charIndex <= prefixEndIndex)
return true;
int suffixStartIndex =
formattedLink.Position +
formattedLink.Length - Segment.LINK_SUFFIX.Length;
if (suffixStartIndex <= charIndex &&
charIndex <= (formattedLink.Position + formattedLink.Length - 1))
return true;
return false;
}
static Segment.Data GetSegmentData(object segment)
{
if (segment is HelpLink)
{
HelpLink link = (HelpLink)segment;
return Segment.BuildForLink(link);
}
HelpFormat format = (HelpFormat)segment;
return Segment.BuildForFormat(format);
}
static class Segment
{
internal class Data
{
internal int Begin;
internal int Length;
internal string Prefix;
internal string Suffix;
}
internal static Data BuildForLink(HelpLink link)
{
return new Data()
{
Begin = link.Position,
Length = link.Length,
Prefix = LINK_PREFIX,
Suffix = LINK_SUFFIX
};
}
internal static Data BuildForFormat(HelpFormat format)
{
switch (format.Type)
{
case HelpFormat.FormatType.Title:
return new Data()
{
Begin = format.Position,
Length = format.Length,
Prefix = TITLE_PREFIX,
Suffix = TITLE_SUFFIX
};
case HelpFormat.FormatType.Bold:
return new Data()
{
Begin = format.Position,
Length = format.Length,
Prefix = BOLD_PREFIX,
Suffix = BOLD_SUFFIX
};
case HelpFormat.FormatType.Underline:
// NOTE(rafa): No support yet for underline, we use italic instead
return new Data()
{
Begin = format.Position,
Length = format.Length,
Prefix = ITALIC_PREFIX,
Suffix = ITALIC_SUFFIX
};
default:
return null;
}
}
internal const string LINK_PREFIX = "<color=\"" + UnityStyles.HexColors.LINK_COLOR + "\">";
internal const string LINK_SUFFIX = "</color>";
const string TITLE_PREFIX = "<size=16>";
const string TITLE_SUFFIX = "</size>";
const string BOLD_PREFIX = "<b>";
const string BOLD_SUFFIX = "</b>";
const string ITALIC_PREFIX = "<i>";
const string ITALIC_SUFFIX = "</i>";
}
}
}
using System.Diagnostics;
using UnityEditor;
using UnityEngine;
using Codice.Client.Common;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Help
{
internal static class DrawHelpPanel
{
internal static void For(
HelpPanel helpPanel)
{
if (!helpPanel.Visible)
return;
DoHelpPanelToolbar(helpPanel);
GUILayout.Space(10);
DoHelpPanelContent(helpPanel);
}
static void DoHelpPanelToolbar(
HelpPanel helpPanel)
{
Rect rect = GUILayoutUtility.GetLastRect();
rect.y = rect.yMax;
rect.height = 22;
GUILayout.Space(1);
GUIStyle expandableToolbar = new GUIStyle(EditorStyles.toolbar);
expandableToolbar.fixedHeight = 0;
GUI.Label(rect, GUIContent.none, expandableToolbar);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("<", EditorStyles.miniButtonLeft))
{
// TODO(codice): On Left Clicked
}
if (GUILayout.Button(">", EditorStyles.miniButtonRight))
{
// TODO(codice): On Right Clicked
}
GUILayout.FlexibleSpace();
// TODO(codice): The bool used here must be loaded and persisted by some means
helpPanel.Data.ShouldShowAgain = EditorGUILayout.ToggleLeft(
PlasticLocalization.GetString(PlasticLocalization.Name.DontShowItAgain),
helpPanel.Data.ShouldShowAgain, UnityStyles.MiniToggle);
bool okWasPressed = GUILayout.Button(
PlasticLocalization.GetString(PlasticLocalization.Name.OkButton),
EditorStyles.miniButton);
if (okWasPressed)
{
helpPanel.Hide();
// TODO(codice): Do on helppanel dismiss actions
return;
}
}
}
static void DoHelpPanelContent(
HelpPanel helpPanel)
{
using (new EditorGUILayout.HorizontalScope())
{
Texture image = Images.GetHelpImage(helpPanel.Image);
var imgRect = GUILayoutUtility.GetRect(
image.width, image.width, image.height, image.height);
GUI.DrawTexture(imgRect, image, ScaleMode.ScaleToFit);
using (new EditorGUILayout.VerticalScope())
{
GUIStyle helpParagraph = UnityStyles.Paragraph;
helpPanel.TextScroll = GUILayout.BeginScrollView(helpPanel.TextScroll);
GUILayout.Label(helpPanel.GUIContent, helpParagraph);
if (Event.current.type != EventType.Layout)
DoHelpPanelLinks(helpPanel, helpParagraph);
GUILayout.EndScrollView();
Rect scrollRect = GUILayoutUtility.GetLastRect();
if (Mouse.IsRightMouseButtonPressed(Event.current) &&
scrollRect.Contains(Event.current.mousePosition))
{
GenericMenu contextMenu = BuildHelpPanelMenu(helpPanel.Data.CleanText);
contextMenu.ShowAsContext();
}
}
}
}
static void DoHelpPanelLinks(
HelpPanel helpPanel,
GUIStyle helpParagraph)
{
var lastRect = GUILayoutUtility.GetLastRect();
bool linkWasClicked = false;
GUIContent charContent = new GUIContent();
for (int charIdx = 0; charIdx < helpPanel.GUIContent.text.Length; charIdx++)
{
HelpLink link;
if (!helpPanel.TryGetLinkAtChar(charIdx, out link))
continue;
charContent.text = helpPanel.GUIContent.text[charIdx].ToString();
var pos = helpParagraph.GetCursorPixelPosition(
lastRect, helpPanel.GUIContent, charIdx);
float charWidth = helpParagraph.CalcSize(charContent).x;
Rect charRect = new Rect(pos, new Vector2(
charWidth - 4, helpParagraph.lineHeight));
if (!linkWasClicked &&
Mouse.IsLeftMouseButtonPressed(Event.current) &&
charRect.Contains(Event.current.mousePosition))
{
linkWasClicked = true;
OnHelpLinkClicked(helpPanel, link);
}
// Underline for links
charRect.y = charRect.yMax - 1;
charRect.height = 1;
GUI.DrawTexture(charRect, Images.GetLinkUnderlineImage());
}
}
static void OnHelpLinkClicked(
HelpPanel helpPanel,
HelpLink helpLink)
{
HelpLink.LinkType linkType;
string content;
if (!HelpLinkData.TryGet(helpLink.Link, out linkType, out content))
return;
switch (linkType)
{
case HelpLink.LinkType.Action:
GuiMessage.ShowInformation(
"An ACTION link has been clicked:\n" + content);
break;
case HelpLink.LinkType.Help:
helpPanel.Show(
PlasticGui.Help.HelpImage.GenericBuho,
content == "sample1" ?
TestingHelpData.GetSample1() :
TestingHelpData.GetSample2());
break;
case HelpLink.LinkType.Link:
Process.Start(content);
break;
}
}
static void CopyToClipboard(string data)
{
EditorGUIUtility.systemCopyBuffer = data;
}
static GenericMenu BuildHelpPanelMenu(string cleanText)
{
GenericMenu result = new GenericMenu();
result.AddItem(
new GUIContent(PlasticLocalization.GetString(PlasticLocalization.Name.Copy)),
false,
() => CopyToClipboard(cleanText)
);
return result;
}
}
}
using System.Collections.Generic;
namespace Unity.PlasticSCM.Editor.Help
{
internal class HelpData
{
internal List<HelpFormat> FormattedBlocks = new List<HelpFormat>();
internal List<HelpLink> Links = new List<HelpLink>();
internal string CleanText;
internal bool ShouldShowAgain;
}
}
\ No newline at end of file
namespace Unity.PlasticSCM.Editor.Help
{
internal class HelpFormat
{
internal enum FormatType
{
Title,
Bold,
Underline
}
internal int Position;
internal int Length;
internal FormatType Type;
}
}
\ No newline at end of file
namespace Unity.PlasticSCM.Editor.Help
{
internal class HelpLink
{
internal enum LinkType
{
Action,
Help,
Link,
}
internal int Position;
internal int Length;
internal string Link;
internal LinkType Type = LinkType.Action;
}
}
\ No newline at end of file
using System;
using Codice.LogWrapper;
namespace Unity.PlasticSCM.Editor.Help
{
internal static class HelpLinkData
{
internal static bool TryGet(
string link, out HelpLink.LinkType type, out string content)
{
type = HelpLink.LinkType.Link;
content = string.Empty;
int separatorIdx = link.IndexOf(':');
if (separatorIdx == -1)
return false;
string key = link.Substring(0, separatorIdx);
try
{
type = (HelpLink.LinkType)Enum.Parse(
typeof(HelpLink.LinkType), key, true);
}
catch (Exception ex)
{
mLog.ErrorFormat("Unable to get help link data: '{0}': {1}",
key, ex.Message);
mLog.DebugFormat("StackTrace: {0}", ex.StackTrace);
return false;
}
content = link.Substring(separatorIdx + 1);
return true;
}
static readonly ILog mLog = LogManager.GetLogger("HelpLinkData");
}
}
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Help
{
internal class HelpPanel
{
internal Vector2 TextScroll;
internal bool Visible { get; private set; }
internal PlasticGui.Help.HelpImage Image
{
get { return mHelpImage; }
}
internal HelpData Data
{
get { return mHelpData; }
}
internal GUIContent GUIContent
{
get { return mHelpGUIContent; }
}
internal HelpPanel(EditorWindow window)
{
mWindow = window;
}
internal void Show(PlasticGui.Help.HelpImage helpImage, HelpData helpData)
{
ClearData();
UpdateData(helpImage, helpData);
Visible = true;
mWindow.Repaint();
}
internal void Hide()
{
ClearData();
Visible = false;
mWindow.Repaint();
}
internal bool TryGetLinkAtChar(
int charIndex,
out HelpLink link)
{
link = null;
FormattedHelpLink formattedLink = GetFormattedLinkAtChar(
mFormattedLinks, charIndex);
if (formattedLink == null)
return false;
link = formattedLink.Source;
return !BuildFormattedHelp.IsLinkMetaChar(formattedLink, charIndex);
}
void ClearData()
{
mHelpImage = PlasticGui.Help.HelpImage.GenericBuho;
mHelpData = null;
mHelpGUIContent = null;
mFormattedLinks = null;
}
void UpdateData(PlasticGui.Help.HelpImage helpImage, HelpData helpData)
{
mHelpImage = helpImage;
mHelpData = helpData;
string formattedHelpText;
BuildFormattedHelp.ForData(
mHelpData.CleanText,
mHelpData.FormattedBlocks.ToArray(),
mHelpData.Links.ToArray(),
out formattedHelpText,
out mFormattedLinks);
mHelpGUIContent = new GUIContent(formattedHelpText);
}
static FormattedHelpLink GetFormattedLinkAtChar(
List<FormattedHelpLink> formattedLinks, int charIndex)
{
for(int i = 0; i < formattedLinks.Count; i++)
{
FormattedHelpLink link = formattedLinks[i];
if (link.Position <= charIndex &&
charIndex < link.Position + link.Length)
return link;
if (charIndex <= link.Position + link.Length)
return null;
}
return null;
}
PlasticGui.Help.HelpImage mHelpImage;
HelpData mHelpData;
GUIContent mHelpGUIContent;
List<FormattedHelpLink> mFormattedLinks;
EditorWindow mWindow;
}
}
using System.Collections.Generic;
namespace Unity.PlasticSCM.Editor.Help
{
internal static class TestingHelpData
{
internal static HelpData GetSample1()
{
HelpData result = new HelpData();
result.CleanText = "There are some .private files" + System.Environment.NewLine + System.Environment.NewLine +
"Do not panic, these are copies Plastic creates to preserve files it can't overwrite." + System.Environment.NewLine + System.Environment.NewLine +
"Suppose you have a private file \"src / foo.c\", then switch your workspace to a branch where someone added \"src / foo.c\". Plastic downloads the new file because it is under source control and yours is not. But, it can't delete yours, so it renames it as .private.0." + System.Environment.NewLine + System.Environment.NewLine +
"Makes sense?" + System.Environment.NewLine + System.Environment.NewLine +
"Learn more:" + System.Environment.NewLine +
"* You have some files ready to be added to version control" + System.Environment.NewLine +
"* Are you missing any changes?" + System.Environment.NewLine +
"* Tips to work with Visual Studio projects." + System.Environment.NewLine + System.Environment.NewLine +
"This is just text after links (like this help link -> content2) to verify that the format is preserved." + System.Environment.NewLine + System.Environment.NewLine +
"And then that another link at the end works, with some bold text at the end, final!!";
// IMPORTANT! We need single EOL chars to calculate the positions,
// otherwise positions are wrong calculated
result.CleanText = result.CleanText.Replace("\r\n", "\n");
result.FormattedBlocks = new List<HelpFormat>();
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Title,
Position = 0,
Length = 29
});
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Bold,
Position = result.CleanText.IndexOf("not panic"),
Length = "not panic".Length
});
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Underline,
Position = result.CleanText.IndexOf("overwrite"),
Length = "overwrite".Length
});
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Bold,
Position = result.CleanText.IndexOf("Makes sense?"),
Length = "Makes sense?".Length
});
result.Links = new List<HelpLink>();
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("You have some files ready to be added to version control"),
Length = "You have some files ready to be added to version control".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Action, "plasticscm-pendingchanges-filestoadd")
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("Are you missing any changes?"),
Length = "Are you missing any changes?".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Action, "plasticscm-pendingchanges-missingchanges")
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("Tips to work with Visual Studio projects."),
Length = "Tips to work with Visual Studio projects.".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Action, "plasticscm-pendingchanges-visualstudio")
});
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Bold,
Position = result.CleanText.IndexOf("verify that the format is preserved"),
Length = "verify that the format is preserved".Length
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("this help link"),
Length = "this help link".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Help, "sample2")
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("another link at the end"),
Length = "another link at the end".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Link, "https://www.google.com")
});
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Bold,
Position = result.CleanText.IndexOf("bold text at the end"),
Length = "bold text at the end".Length
});
return result;
}
internal static HelpData GetSample2()
{
HelpData result = new HelpData();
result.CleanText = "Alternative title to confirm that all is working" + System.Environment.NewLine + System.Environment.NewLine +
"This is just another help example to ensure that the panel replaces the helps dynamically." + System.Environment.NewLine + System.Environment.NewLine +
"If you're reading this text, means that the help changed its content dynamically, so we can navigate between help tips by clicking hyperlinks" + System.Environment.NewLine + System.Environment.NewLine +
"Makes sense?" + System.Environment.NewLine + System.Environment.NewLine +
"Learn more:" + System.Environment.NewLine +
"* You have some files ready to be added to version control" + System.Environment.NewLine +
"* Are you missing any changes?" + System.Environment.NewLine +
"* Tips to work with Visual Studio projects." + System.Environment.NewLine + System.Environment.NewLine +
"This is just text after links (like this help link -> content1) to verify that the format is preserved.";
// IMPORTANT! We need single EOL chars to calculate the positions,
// otherwise positions are wrong calculated
result.CleanText = result.CleanText.Replace("\r\n", "\n");
result.FormattedBlocks = new List<HelpFormat>();
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Title,
Position = 0,
Length = "Alternative title to confirm that all is working".Length
});
result.FormattedBlocks.Add(new HelpFormat()
{
Type = HelpFormat.FormatType.Bold,
Position = result.CleanText.IndexOf("replaces the helps dynamically"),
Length = "replaces the helps dynamically".Length
});
result.Links = new List<HelpLink>();
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("You have some files ready to be added to version control"),
Length = "You have some files ready to be added to version control".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Action, "plasticscm-pendingchanges-filestoadd")
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("Are you missing any changes?"),
Length = "Are you missing any changes?".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Action, "plasticscm-pendingchanges-missingchanges")
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("Tips to work with Visual Studio projects."),
Length = "Tips to work with Visual Studio projects.".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Action, "plasticscm-pendingchanges-visualstudio")
});
result.Links.Add(new HelpLink()
{
Position = result.CleanText.IndexOf("this help link"),
Length = "this help link".Length,
Link = HelpLinkData.AsString(HelpLink.LinkType.Help, "sample1")
});
return result;
}
class HelpLinkData
{
internal static string AsString(HelpLink.LinkType linkType, string linkContent)
{
string linkTypeString = string.Empty;
switch (linkType)
{
case HelpLink.LinkType.Action:
linkTypeString = ACTION;
break;
case HelpLink.LinkType.Help:
linkTypeString = HELP;
break;
case HelpLink.LinkType.Link:
linkTypeString = LINK;
break;
}
return string.Concat(linkTypeString, SEPARATOR, linkContent);
}
const string ACTION = "action";
const string HELP = "help";
const string LINK = "link";
const string SEPARATOR = ":";
}
}
}
\ No newline at end of file
using PlasticGui;
using System;
using System.IO;
using Unity.PlasticSCM.Editor.AssetMenu;
using Unity.PlasticSCM.Editor.AssetsOverlays;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.UI;
using UnityEditor;
using UnityEditor.VersionControl;
using UnityEngine;
namespace Unity.PlasticSCM.Editor.Inspector
{
static class DrawInspectorOperations
{
internal static void Enable(
IAssetMenuOperations operations,
IAssetStatusCache statusCache,
AssetOperations.IAssetSelection assetsSelection)
{
mOperations = operations;
mStatusCache = statusCache;
mAssetsSelection = assetsSelection;
mIsEnabled = true;
UnityEditor.Editor.finishedDefaultHeaderGUI +=
Editor_finishedDefaultHeaderGUI;
RefreshAsset.RepaintInspectors();
}
internal static void Disable()
{
mIsEnabled = false;
UnityEditor.Editor.finishedDefaultHeaderGUI -=
Editor_finishedDefaultHeaderGUI;
RefreshAsset.RepaintInspectors();
}
static void Editor_finishedDefaultHeaderGUI(UnityEditor.Editor obj)
{
if (!mIsEnabled)
return;
AssetList assetList = mAssetsSelection.GetSelectedAssets();
if (mOperations == null ||
assetList.Count == 0 ||
string.IsNullOrEmpty(assetList[0].path))
return;
string selectionFullPath = Path.GetFullPath(assetList[0].path);
AssetsOverlays.AssetStatus assetStatus = (assetList.Count > 1) ?
AssetsOverlays.AssetStatus.None :
mStatusCache.GetStatusForPath(selectionFullPath);
LockStatusData lockStatusData = mStatusCache.GetLockStatusDataForPath(
selectionFullPath);
SelectedAssetGroupInfo selectedGroupInfo = SelectedAssetGroupInfo.
BuildFromAssetList(assetList, mStatusCache);
AssetMenuOperations assetOperations =
AssetMenuUpdater.GetAvailableMenuOperations(selectedGroupInfo);
bool guiEnabledBck = GUI.enabled;
GUI.enabled = true;
try
{
DrawBackRectangle(guiEnabledBck);
GUILayout.BeginHorizontal();
DrawStatusLabels(assetStatus, lockStatusData);
GUILayout.FlexibleSpace();
DrawButtons(assetList, assetOperations);
GUILayout.EndHorizontal();
}
finally
{
GUI.enabled = guiEnabledBck;
}
}
static void DrawBackRectangle(bool isEnabled)
{
// when the inspector is disabled, there is a separator line
// that breaks the visual style. Draw an empty rectangle
// matching the background color to cover it
GUILayout.Space(
UnityConstants.INSPECTOR_ACTIONS_BACK_RECTANGLE_TOP_MARGIN);
GUIStyle targetStyle = (isEnabled) ?
UnityStyles.Inspector.HeaderBackgroundStyle :
UnityStyles.Inspector.DisabledHeaderBackgroundStyle;
Rect rect = GUILayoutUtility.GetRect(
GUIContent.none, targetStyle);
// extra space to cover the inspector full width
rect.x -= 20;
rect.width += 80;
GUI.Box(rect, GUIContent.none, targetStyle);
// now reset the space used by the rectangle
GUILayout.Space(
-UnityConstants.INSPECTOR_ACTIONS_HEADER_BACK_RECTANGLE_HEIGHT
- UnityConstants.INSPECTOR_ACTIONS_BACK_RECTANGLE_TOP_MARGIN);
}
static void DrawButtons(
AssetList assetList,
AssetMenuOperations selectedGroupInfo)
{
if (selectedGroupInfo.HasFlag(AssetMenuOperations.Add))
DoAddButton();
if (selectedGroupInfo.HasFlag(AssetMenuOperations.Checkout))
DoCheckoutButton();
if (selectedGroupInfo.HasFlag(AssetMenuOperations.Checkin))
DoCheckinButton();
if (selectedGroupInfo.HasFlag(AssetMenuOperations.Undo))
DoUndoButton();
}
static void DrawStatusLabels(
AssetsOverlays.AssetStatus assetStatus,
LockStatusData lockStatusData)
{
AssetsOverlays.AssetStatus statusesToDraw = DrawAssetOverlay.GetStatusesToDraw(assetStatus);
foreach (AssetsOverlays.AssetStatus status in Enum.GetValues(typeof(AssetsOverlays.AssetStatus)))
{
if (status == AssetsOverlays.AssetStatus.None)
continue;
if (!statusesToDraw.HasFlag(status))
continue;
string label = string.Format("{0}",
DrawAssetOverlay.GetStatusString(status));
Texture icon = DrawAssetOverlay.DrawOverlayIcon.GetOverlayIcon(
status);
string tooltipText = DrawAssetOverlay.GetTooltipText(
status, lockStatusData);
GUILayout.Label(new GUIContent(
label, icon, tooltipText), GUILayout.Height(18));
}
}
static void DoAddButton()
{
string buttonText = PlasticLocalization.GetString(PlasticLocalization.Name.AddButton);
if (GUILayout.Button(string.Format("{0}", buttonText), EditorStyles.miniButton))
{
mOperations.Add();
}
}
static void DoCheckoutButton()
{
string buttonText = PlasticLocalization.GetString(PlasticLocalization.Name.CheckoutButton);
if (GUILayout.Button(string.Format("{0}", buttonText), EditorStyles.miniButton))
{
mOperations.Checkout();
}
}
static void DoCheckinButton()
{
string buttonText = PlasticLocalization.GetString(PlasticLocalization.Name.CheckinButton);
if (GUILayout.Button(string.Format("{0}", buttonText), EditorStyles.miniButton))
{
mOperations.Checkin();
EditorGUIUtility.ExitGUI();
}
}
static void DoUndoButton()
{
string buttonText = PlasticLocalization.GetString(PlasticLocalization.Name.UndoButton);
if (GUILayout.Button(string.Format("{0}", buttonText), EditorStyles.miniButton))
{
mOperations.Undo();
EditorGUIUtility.ExitGUI();
}
}
static IAssetMenuOperations mOperations;
static IAssetStatusCache mStatusCache;
static AssetOperations.IAssetSelection mAssetsSelection;
static bool mIsEnabled;
}
}
using Unity.PlasticSCM.Editor.AssetMenu;
using Unity.PlasticSCM.Editor.AssetUtils;
using UnityEditor.VersionControl;
namespace Unity.PlasticSCM.Editor.Inspector
{
internal class InspectorAssetSelection : AssetOperations.IAssetSelection
{
AssetList AssetOperations.IAssetSelection.GetSelectedAssets()
{
AssetList result = new AssetList();
foreach (UnityEngine.Object obj in UnityEditor.Selection.objects)
{
result.Add(new Asset(AssetsPath.GetFullPath(obj)));
}
return result;
}
}
}
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor
{
internal static class MetaPath
{
internal const string META_EXTENSION = ".meta";
internal static bool IsMetaPath(string path)
{
return path.EndsWith(META_EXTENSION);
}
internal static string GetMetaPath(string path)
{
return string.Concat(
path,
META_EXTENSION);
}
internal static string GetPathFromMetaPath(string path)
{
return path.Substring(
0,
path.Length - META_EXTENSION.Length);
}
}
}
using System;
using Codice.Client.Common;
using Codice.CM.Common;
using PlasticGui.WorkspaceWindow;
using Unity.PlasticSCM.Editor.UI;
using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater;
using GluonCheckIncomingChanges = PlasticGui.Gluon.WorkspaceWindow.CheckIncomingChanges;
namespace Unity.PlasticSCM.Editor
{
internal static class NewIncomingChanges
{
internal static NewIncomingChangesUpdater BuildUpdaterForDeveloper(
WorkspaceInfo wkInfo,
CheckIncomingChanges.IAutoRefreshIncomingChangesView autoRefreshIncomingChangesView,
CheckIncomingChanges.IUpdateIncomingChanges updateIncomingChanges)
{
if (!ClientConfig.Get().GetClientConfigData().IsIncomingChangesEnabled())
return null;
NewIncomingChangesUpdater updater = new NewIncomingChangesUpdater(
new UnityPlasticTimerBuilder(), updateIncomingChanges);
updater.SetAutoRefreshIncomingChangesView(
autoRefreshIncomingChangesView);
updater.SetWorkspace(wkInfo);
updater.Start();
return updater;
}
internal static GluonNewIncomingChangesUpdater BuildUpdaterForGluon(
WorkspaceInfo wkInfo,
GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView autoRefreshIncomingChangesView,
GluonCheckIncomingChanges.IUpdateIncomingChanges updateIncomingChanges,
GluonCheckIncomingChanges.ICalculateIncomingChanges calculateIncomingChanges)
{
if (!ClientConfig.Get().GetClientConfigData().IsGluonIncomingChangesEnabled())
return null;
GluonNewIncomingChangesUpdater updater = new GluonNewIncomingChangesUpdater(
wkInfo,
new UnityPlasticTimerBuilder(),
updateIncomingChanges,
autoRefreshIncomingChangesView,
calculateIncomingChanges);
updater.Start();
return updater;
}
internal static void LaunchUpdater(
NewIncomingChangesUpdater developerNewIncomingChangesUpdater,
GluonNewIncomingChangesUpdater gluonNewIncomingChangesUpdater)
{
if (developerNewIncomingChangesUpdater != null)
{
developerNewIncomingChangesUpdater.Start();
developerNewIncomingChangesUpdater.Update();
}
if (gluonNewIncomingChangesUpdater != null)
{
gluonNewIncomingChangesUpdater.Start();
gluonNewIncomingChangesUpdater.Update(DateTime.Now);
}
}
internal static void StopUpdater(
NewIncomingChangesUpdater developerNewIncomingChangesUpdater,
GluonNewIncomingChangesUpdater gluonNewIncomingChangesUpdater)
{
if (developerNewIncomingChangesUpdater != null)
developerNewIncomingChangesUpdater.Stop();
if (gluonNewIncomingChangesUpdater != null)
gluonNewIncomingChangesUpdater.Stop();
}
internal static void DisposeUpdater(
NewIncomingChangesUpdater developerNewIncomingChangesUpdater,
GluonNewIncomingChangesUpdater gluonNewIncomingChangesUpdater)
{
if (developerNewIncomingChangesUpdater != null)
developerNewIncomingChangesUpdater.Dispose();
if (gluonNewIncomingChangesUpdater != null)
gluonNewIncomingChangesUpdater.Dispose();
}
}
}
using System;
using System.IO;
using System.Linq;
using UnityEngine;
using Codice.Client.BaseCommands;
using Codice.Client.Common;
using Codice.Client.Common.FsNodeReaders;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.CM.ConfigureHelper;
using Codice.LogWrapper;
using Codice.Utils;
using PlasticGui;
using PlasticPipe.Certificates;
using Unity.PlasticSCM.Editor.Configuration;
using Unity.PlasticSCM.Editor.UI;
using MacUI;
namespace Unity.PlasticSCM.Editor
{
internal static class PlasticApp
{
internal static void InitializeIfNeeded()
{
if (mIsInitialized)
return;
ConfigureLogging();
RegisterExceptionHandlers();
InitLocalization();
ThreadWaiter.Initialize(new UnityThreadWaiterBuilder());
ServicePointConfigurator.ConfigureServicePoint();
CertificateUi.RegisterHandler(new ChannelCertificateUiImpl());
SetupFsWatcher();
EditionManager.Get().DisableCapability(
EnumEditionCapabilities.Extensions);
ClientHandlers.Register();
PlasticGuiConfig.SetConfigFile(
PlasticGuiConfig.UNITY_GUI_CONFIG_FILE);
mIsInitialized = true;
}
internal static void Dispose()
{
UnRegisterExceptionHandlers();
}
static void InitLocalization()
{
string language = null;
try
{
language = ClientConfig.Get().GetLanguage();
}
catch
{
language = string.Empty;
}
Localization.Init(language);
PlasticLocalization.SetLanguage(language);
}
static void ConfigureLogging()
{
try
{
string log4netpath = ToolConfig.GetUnityPlasticLogConfigFile();
if (!File.Exists(log4netpath))
WriteLogConfiguration.For(log4netpath);
XmlConfigurator.Configure(new FileInfo(log4netpath));
}
catch
{
//it failed configuring the logging info; nothing to do.
}
}
static void RegisterExceptionHandlers()
{
AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
Application.logMessageReceivedThreaded += HandleLog;
}
static void UnRegisterExceptionHandlers()
{
AppDomain.CurrentDomain.UnhandledException -= HandleUnhandledException;
Application.logMessageReceivedThreaded -= HandleLog;
}
static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception ex = (Exception)args.ExceptionObject;
if (IsExitGUIException(ex) ||
!IsPlasticStackTrace(ex.StackTrace))
return;
GUIActionRunner.RunGUIAction(delegate {
ExceptionsHandler.HandleException("HandleUnhandledException", ex);
});
}
static void HandleLog(string logString, string stackTrace, LogType type)
{
if (type != LogType.Exception)
return;
if (!IsPlasticStackTrace(stackTrace))
return;
GUIActionRunner.RunGUIAction(delegate {
mLog.ErrorFormat("[HandleLog] Unexpected error: {0}", logString);
mLog.DebugFormat("Stack trace: {0}", stackTrace);
string message = logString;
if (ExceptionsHandler.DumpStackTrace())
message += Environment.NewLine + stackTrace;
GuiMessage.ShowError(message);
});
}
static void SetupFsWatcher()
{
if (!PlatformIdentifier.IsMac())
return;
WorkspaceWatcherFsNodeReadersCache.Get().SetMacFsWatcherBuilder(
new MacFsWatcherBuilder());
}
static bool IsPlasticStackTrace(string stackTrace)
{
if (stackTrace == null)
return false;
string[] namespaces = new[] {
"Codice.",
"GluonGui.",
"PlasticGui."
};
return namespaces.Any(stackTrace.Contains);
}
static bool IsExitGUIException(Exception ex)
{
return ex is ExitGUIException;
}
static bool mIsInitialized;
static readonly ILog mLog = LogManager.GetLogger("PlasticApp");
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using Codice.Client.BaseCommands;
using Codice.Client.Commands;
using Codice.Client.Commands.CheckIn;
using Codice.Client.Common;
using Codice.Client.Common.FsNodeReaders;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.CM.Common.Merge;
using Codice.CM.Common.Replication;
using GluonGui;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using PlasticGui.WorkspaceWindow.PendingChanges;
using PlasticGui.WorkspaceWindow.Replication;
using PlasticGui.WorkspaceWindow.Update;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.Configuration;
using Unity.PlasticSCM.Editor.Developer.UpdateReport;
using Unity.PlasticSCM.Editor.UI.Progress;
using Unity.PlasticSCM.Editor.Views.PendingChanges;
using Unity.PlasticSCM.Editor.Views.PendingChanges.Dialogs;
using Unity.PlasticSCM.Editor.Views.PendingChanges.PendingMergeLinks;
using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater;
namespace Unity.PlasticSCM.Editor
{
internal partial class PlasticGUIClient :
IPendingChangesView, IWorkspaceWindow, IUpdateReport
{
internal void SetUpdateNotifierForTesting(UpdateNotifier updateNotifier)
{
mUpdateNotifierForTesting = updateNotifier;
}
internal void SetMergeLinksForTesting(
IDictionary<MountPoint, IList<PendingMergeLink>> mergeLinks)
{
mPendingMergeLinks = mergeLinks;
UpdateMergeLinksList();
}
internal OperationProgressData Progress { get { return mOperationProgressData; } }
internal string HeaderTitle { get; private set; }
internal string CommentText { get; set; }
internal bool KeepItemsLocked { get; set; }
internal bool ForceToShowComment { get; set; }
internal bool IsCommentWarningNeeded { get; set; }
internal string GluonWarningMessage { get; private set; }
internal Gluon.ProgressOperationHandler GluonProgressOperationHandler
{
get { return mGluonProgressOperationHandler; }
}
internal PlasticGUIClient(
WorkspaceInfo wkInfo,
ViewSwitcher switcher,
IMergeViewLauncher mergeViewLauncher,
ViewHost viewHost,
PlasticGui.WorkspaceWindow.PendingChanges.PendingChanges pendingChanges,
NewIncomingChangesUpdater developerNewIncomingChangesUpdater,
GluonNewIncomingChangesUpdater gluonNewIncomingChangesUpdater,
EditorWindow parentWindow,
GuiMessage.IGuiMessage guiMessage)
{
mWkInfo = wkInfo;
mSwitcher = switcher;
mMergeViewLauncher = mergeViewLauncher;
mViewHost = viewHost;
mPendingChanges = pendingChanges;
mDeveloperNewIncomingChangesUpdater = developerNewIncomingChangesUpdater;
mGluonNewIncomingChangesUpdater = gluonNewIncomingChangesUpdater;
mPlasticWindow = parentWindow;
mGuiMessage = guiMessage;
((IWorkspaceWindow)this).UpdateTitle();
mCheckedStateManager = new CheckedStateManager();
mDeveloperProgressOperationHandler = new Developer.ProgressOperationHandler(mWkInfo, this);
mGluonProgressOperationHandler = new Gluon.ProgressOperationHandler(this);
}
internal void RegisterPendingChangesGuiControls(
ProgressControlsForViews progressControls,
PendingChangesTreeView changesTreeView,
MergeLinksListView mergeLinksListView)
{
mProgressControls = progressControls;
mChangesTreeView = changesTreeView;
mMergeLinksListView = mergeLinksListView;
mPendingChangesOperations = new PendingChangesOperations(
mWkInfo, this, mSwitcher, mMergeViewLauncher,
this, mProgressControls, this, null, null, null);
}
internal bool HasPendingMergeLinks()
{
if (mPendingMergeLinks == null)
return false;
return mPendingMergeLinks.Count > 0;
}
internal void UpdateIsCommentWarningNeeded(string comment)
{
IsCommentWarningNeeded = string.IsNullOrEmpty(comment)
&& mPendingChanges.HasPendingChanges();
}
internal bool IsOperationInProgress()
{
return mDeveloperProgressOperationHandler.IsOperationInProgress()
|| mGluonProgressOperationHandler.IsOperationInProgress();
}
internal bool IsRefreshing()
{
return mIsRefreshing;
}
internal void CancelCurrentOperation()
{
if (mDeveloperProgressOperationHandler.IsOperationInProgress())
{
mDeveloperProgressOperationHandler.CancelCheckinProgress();
return;
}
if (mGluonProgressOperationHandler.IsOperationInProgress())
{
mGluonProgressOperationHandler.CancelUpdateProgress();
return;
}
}
internal void Checkin()
{
List<ChangeInfo> changesToCheckin;
List<ChangeInfo> dependenciesCandidates;
mChangesTreeView.GetCheckedChanges(
false, out changesToCheckin, out dependenciesCandidates);
if (CheckEmptyOperation(changesToCheckin, HasPendingMergeLinks()))
{
mProgressControls.ShowWarning(
PlasticLocalization.GetString(PlasticLocalization.Name.NoItemsAreSelected));
return;
}
bool isCancelled;
SaveAssets.ForChangesWithConfirmation(changesToCheckin, out isCancelled);
if (isCancelled)
return;
mPendingChangesOperations.Checkin(
changesToCheckin,
dependenciesCandidates,
CommentText,
null,
RefreshAsset.UnityAssetDatabase);
}
internal void Undo()
{
List<ChangeInfo> changesToUndo;
List<ChangeInfo> dependenciesCandidates;
mChangesTreeView.GetCheckedChanges(
true, out changesToUndo, out dependenciesCandidates);
UndoChanges(changesToUndo, dependenciesCandidates);
}
internal void UndoChanges(
List<ChangeInfo> changesToUndo,
List<ChangeInfo> dependenciesCandidates)
{
if (CheckEmptyOperation(changesToUndo, HasPendingMergeLinks()))
{
mProgressControls.ShowWarning(
PlasticLocalization.GetString(PlasticLocalization.Name.NoItemsToUndo));
return;
}
SaveAssets.ForChangesWithoutConfirmation(changesToUndo);
mPendingChangesOperations.Undo(
changesToUndo,
dependenciesCandidates,
mPendingMergeLinks.Count,
RefreshAsset.UnityAssetDatabase);
}
internal void UpdateWorkspace()
{
UpdateWorkspaceOperation update = new UpdateWorkspaceOperation(
mWkInfo, this, mSwitcher, mMergeViewLauncher, this,
mDeveloperNewIncomingChangesUpdater,
null);
update.Run(
UpdateWorkspaceOperation.UpdateType.UpdateToLatest,
RefreshAsset.UnityAssetDatabase);
}
internal void GetPendingChanges(INewChangesInWk newChangesInWk)
{
if (mDeveloperNewIncomingChangesUpdater != null)
mDeveloperNewIncomingChangesUpdater.Update();
if (mGluonNewIncomingChangesUpdater != null)
mGluonNewIncomingChangesUpdater.Update(DateTime.Now);
FillPendingChanges(newChangesInWk);
}
internal void OnParentUpdated(double elapsedSeconds)
{
if (IsOperationInProgress() || mRequestedRepaint)
{
if (mDeveloperProgressOperationHandler.IsOperationInProgress())
mDeveloperProgressOperationHandler.Update(elapsedSeconds);
mPlasticWindow.Repaint();
mRequestedRepaint = false;
}
}
void FillPendingChanges(INewChangesInWk newChangesInWk)
{
if (mIsRefreshing)
return;
mIsRefreshing = true;
List<ChangeInfo> changesToSelect =
PendingChangesSelection.GetChangesToFocus(mChangesTreeView);
mProgressControls.ShowProgress(PlasticLocalization.GetString(
PlasticLocalization.Name.LoadingPendingChanges));
IDictionary<MountPoint, IList<PendingMergeLink>> mergeLinks = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter();
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
FilterManager.Get().Reload();
WorkspaceStatusOptions options = WorkspaceStatusOptions.None;
options |= WorkspaceStatusOptions.FindAdded;
options |= WorkspaceStatusOptions.FindDeleted;
options |= WorkspaceStatusOptions.FindMoved;
options |= WorkspaceStatusOptions.SplitModifiedMoved;
options |= PendingChangesOptions.GetWorkspaceStatusOptions();
if (newChangesInWk != null)
newChangesInWk.Detected();
mPendingChanges.Calculate(
options, PendingChangesOptions.GetMovedMatchingOptions());
mergeLinks = Plastic.API.GetPendingMergeLinks(mWkInfo);
},
/*afterOperationDelegate*/ delegate
{
mPendingMergeLinks = mergeLinks;
try
{
if (waiter.Exception != null)
{
ExceptionsHandler.DisplayException(waiter.Exception);
return;
}
UpdateChangesTree();
UpdateMergeLinksList();
PendingChangesSelection.SelectChanges(
mChangesTreeView, changesToSelect);
}
finally
{
mProgressControls.HideProgress();
UpdateIsCommentWarningNeeded(CommentText);
UpdateNotificationPanel();
mIsRefreshing = false;
}
});
}
void UpdateChangesTree()
{
mChangesTreeView.BuildModel(mPendingChanges, mCheckedStateManager);
mChangesTreeView.Refilter();
mChangesTreeView.Sort();
mChangesTreeView.Reload();
}
void UpdateMergeLinksList()
{
mMergeLinksListView.BuildModel(mPendingMergeLinks);
mMergeLinksListView.Reload();
}
void UpdateNotificationPanel()
{
if (Plastic.API.IsFsReaderWatchLimitReached(mWkInfo))
{
mProgressControls.ShowWarning(PlasticLocalization.GetString(
PlasticLocalization.Name.NotifyLinuxWatchLimitWarning));
return;
}
}
void IUpdateReport.Show(WorkspaceInfo wkInfo, IList reportLines)
{
UpdateReportDialog.ShowReportDialog(
wkInfo,
reportLines,
mPlasticWindow);
}
void IWorkspaceWindow.RefreshView(ViewType viewType)
{
mSwitcher.RefreshView(viewType);
}
void IWorkspaceWindow.UpdateTitle()
{
string title = string.Empty;
IThreadWaiter waiter = ThreadWaiter.GetWaiter();
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
title = GetTitle(mWkInfo);
},
/*afterOperationDelegate*/ delegate
{
if (waiter.Exception != null)
return;
HeaderTitle = title;
RequestRepaint();
});
}
bool IWorkspaceWindow.CheckOperationInProgress()
{
return mDeveloperProgressOperationHandler.CheckOperationInProgress();
}
void IWorkspaceWindow.ShowUpdateProgress(string title, UpdateNotifier notifier)
{
mDeveloperProgressOperationHandler.ShowUpdateProgress(title, mUpdateNotifierForTesting ?? notifier);
}
void IWorkspaceWindow.EndUpdateProgress()
{
mDeveloperProgressOperationHandler.EndUpdateProgress();
}
void IWorkspaceWindow.ShowCheckinProgress()
{
mDeveloperProgressOperationHandler.ShowCheckinProgress();
}
void IWorkspaceWindow.EndCheckinProgress()
{
mDeveloperProgressOperationHandler.EndCheckinProgress();
}
void IWorkspaceWindow.RefreshCheckinProgress(
CheckinStatus checkinStatus,
BuildProgressSpeedAndRemainingTime.ProgressData progressData)
{
mDeveloperProgressOperationHandler.
RefreshCheckinProgress(checkinStatus, progressData);
}
bool IWorkspaceWindow.HasCheckinCancelled()
{
return mDeveloperProgressOperationHandler.HasCheckinCancelled();
}
void IWorkspaceWindow.ShowReplicationProgress(IReplicationOperation replicationOperation)
{
throw new NotImplementedException();
}
void IWorkspaceWindow.RefreshReplicationProgress(BranchReplicationData replicationData, ReplicationStatus replicationStatus, int current, int total)
{
throw new NotImplementedException();
}
void IWorkspaceWindow.EndReplicationProgress(ReplicationStatus replicationStatus)
{
throw new NotImplementedException();
}
void IWorkspaceWindow.ShowProgress()
{
mDeveloperProgressOperationHandler.ShowProgress();
}
void IWorkspaceWindow.ShowProgress(IProgressOperation progressOperation)
{
throw new NotImplementedException();
}
void IWorkspaceWindow.RefreshProgress(ProgressData progressData)
{
mDeveloperProgressOperationHandler.RefreshProgress(progressData);
}
void IWorkspaceWindow.EndProgress()
{
mDeveloperProgressOperationHandler.EndProgress();
}
EncryptionConfigurationDialogData IWorkspaceWindow.RequestEncryptionPassword(string server)
{
return EncryptionConfigurationDialog.RequestEncryptionPassword(server, mPlasticWindow);
}
void IPendingChangesView.ClearChangesToCheck(List<string> changes)
{
mCheckedStateManager.ClearChangesToCheck(changes);
RequestRepaint();
}
void IPendingChangesView.CleanCheckedElements(List<ChangeInfo> checkedChanges)
{
mCheckedStateManager.Clean(checkedChanges);
RequestRepaint();
}
void IPendingChangesView.CheckChanges(List<string> changesToCheck)
{
mCheckedStateManager.SetChangesToCheck(changesToCheck);
RequestRepaint();
}
bool IPendingChangesView.IncludeDependencies(
IList<ChangeDependencies<ChangeInfo>> changesDependencies,
string operation)
{
return DependenciesDialog.IncludeDependencies(
mWkInfo, changesDependencies, operation, mPlasticWindow);
}
CheckinMergeNeededData IPendingChangesView.CheckinMergeNeeded()
{
return CheckinMergeNeededDialog.Merge(mWkInfo, mPlasticWindow);
}
void IPendingChangesView.ClearComments()
{
ClearComments();
}
SearchMatchesData IPendingChangesView.AskForMatches(string changePath)
{
throw new NotImplementedException();
}
void IPendingChangesView.CleanLinkedTasks()
{
}
internal void RequestRepaint()
{
mRequestedRepaint = true;
}
void ClearComments()
{
CommentText = string.Empty;
ForceToShowComment = true;
RequestRepaint();
}
static string GetTitle(WorkspaceInfo wkInfo)
{
WorkspaceStatusString.Data wkStatusData =
WorkspaceStatusString.GetSelectorData(wkInfo);
return string.Format("{0} {1} @ {2} @ {3}",
wkStatusData.ObjectName,
wkStatusData.ObjectSpec,
wkStatusData.RepositoryName,
wkStatusData.Server);
}
static bool CheckEmptyOperation(List<ChangeInfo> elements, bool bHasPendingMergeLinks)
{
if (bHasPendingMergeLinks)
return false;
if (elements != null && elements.Count > 0)
return false;
return true;
}
bool mIsRefreshing;
bool mRequestedRepaint;
UpdateNotifier mUpdateNotifierForTesting;
OperationProgressData mOperationProgressData = new OperationProgressData();
IProgressControls mProgressControls;
IDictionary<MountPoint, IList<PendingMergeLink>> mPendingMergeLinks;
PendingChangesTreeView mChangesTreeView;
MergeLinksListView mMergeLinksListView;
PendingChangesOperations mPendingChangesOperations;
readonly GluonNewIncomingChangesUpdater mGluonNewIncomingChangesUpdater;
readonly NewIncomingChangesUpdater mDeveloperNewIncomingChangesUpdater;
readonly PlasticGui.WorkspaceWindow.PendingChanges.PendingChanges mPendingChanges;
readonly Developer.ProgressOperationHandler mDeveloperProgressOperationHandler;
readonly CheckedStateManager mCheckedStateManager;
readonly Gluon.ProgressOperationHandler mGluonProgressOperationHandler;
readonly GuiMessage.IGuiMessage mGuiMessage;
readonly EditorWindow mPlasticWindow;
readonly ViewSwitcher mSwitcher;
readonly IMergeViewLauncher mMergeViewLauncher;
readonly ViewHost mViewHost;
readonly WorkspaceInfo mWkInfo;
}
}
using System;
using System.Collections.Generic;
using Codice.Client.BaseCommands;
using Codice.Client.Common;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using GluonGui;
using GluonGui.WorkspaceWindow.Views;
using GluonGui.WorkspaceWindow.Views.Checkin.Operations;
using GluonGui.WorkspaceWindow.Views.WorkspaceExplorer.Explorer;
using PlasticGui;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.Gluon.UpdateReport;
using Unity.PlasticSCM.Editor.Views.PendingChanges.Dialogs;
using IGluonUpdateReport = PlasticGui.Gluon.IUpdateReport;
namespace Unity.PlasticSCM.Editor
{
internal partial class PlasticGUIClient :
CheckinUIOperation.ICheckinView, IGluonUpdateReport
{
internal void PartialCheckin(bool keepItemsLocked)
{
List<ChangeInfo> changesToCheckin;
List<ChangeInfo> dependenciesCandidates;
mChangesTreeView.GetCheckedChanges(
false, out changesToCheckin, out dependenciesCandidates);
if (CheckEmptyOperation(changesToCheckin))
{
mProgressControls.ShowWarning(
PlasticLocalization.GetString(PlasticLocalization.Name.NoItemsAreSelected));
return;
}
bool isCancelled;
SaveAssets.ForChangesWithConfirmation(changesToCheckin, out isCancelled);
if (isCancelled)
return;
CheckinUIOperation ciOperation = new CheckinUIOperation(
mWkInfo, mViewHost, mProgressControls, mGuiMessage,
new LaunchCheckinConflictsDialog(mPlasticWindow),
new LaunchDependenciesDialog(
PlasticLocalization.GetString(PlasticLocalization.Name.CheckinButton),
mPlasticWindow),
this, mGluonProgressOperationHandler);
ciOperation.Checkin(
changesToCheckin,
dependenciesCandidates,
CommentText,
keepItemsLocked,
RefreshAsset.UnityAssetDatabase);
}
internal void PartialUndo()
{
List<ChangeInfo> changesToUndo;
List<ChangeInfo> dependenciesCandidates;
mChangesTreeView.GetCheckedChanges(
true, out changesToUndo, out dependenciesCandidates);
PartialUndoChanges(changesToUndo, dependenciesCandidates);
}
internal void PartialUndoChanges(
List<ChangeInfo> changesToUndo,
List<ChangeInfo> dependenciesCandidates)
{
if (CheckEmptyOperation(changesToUndo))
{
mProgressControls.ShowWarning(
PlasticLocalization.GetString(PlasticLocalization.Name.NoItemsToUndo));
return;
}
SaveAssets.ForChangesWithoutConfirmation(changesToUndo);
UndoUIOperation undoOperation = new UndoUIOperation(
mWkInfo, mViewHost,
new LaunchDependenciesDialog(
PlasticLocalization.GetString(PlasticLocalization.Name.UndoButton),
mPlasticWindow),
mProgressControls, mGuiMessage);
undoOperation.Undo(
changesToUndo,
dependenciesCandidates,
RefreshAsset.UnityAssetDatabase);
}
internal void PartialUpdateWorkspace()
{
mProgressControls.ShowProgress(PlasticLocalization.GetString(
PlasticLocalization.Name.UpdatingWorkspace));
((IUpdateProgress)mGluonProgressOperationHandler).ShowCancelableProgress();
OutOfDateUpdater outOfDateUpdater = new OutOfDateUpdater(mWkInfo);
BuildProgressSpeedAndRemainingTime.ProgressData progressData =
new BuildProgressSpeedAndRemainingTime.ProgressData(DateTime.Now);
IThreadWaiter waiter = ThreadWaiter.GetWaiter();
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
outOfDateUpdater.Execute();
},
/*afterOperationDelegate*/ delegate
{
mProgressControls.HideProgress();
((IUpdateProgress)mGluonProgressOperationHandler).EndProgress();
mViewHost.RefreshView(ViewType.CheckinView);
mViewHost.RefreshView(ViewType.IncomingChangesView);
RefreshAsset.UnityAssetDatabase();
if (waiter.Exception != null)
{
ExceptionsHandler.DisplayException(waiter.Exception);
return;
}
ShowUpdateReportDialog(
mWkInfo, mViewHost, outOfDateUpdater.Progress, mProgressControls,
mGuiMessage, mGluonProgressOperationHandler, this);
},
/*timerTickDelegate*/ delegate
{
UpdateProgress progress = outOfDateUpdater.Progress;
if (progress == null)
return;
if (progress.IsCanceled)
{
mProgressControls.ShowNotification(
PlasticLocalization.GetString(PlasticLocalization.Name.Canceling));
}
((IUpdateProgress)mGluonProgressOperationHandler).RefreshProgress(
progress,
UpdateProgressDataCalculator.CalculateProgressForWorkspaceUpdate(
mWkInfo.ClientPath, progress, progressData));
});
}
static void ShowUpdateReportDialog(
WorkspaceInfo wkInfo,
ViewHost viewHost,
UpdateProgress progress,
IProgressControls progressControls,
GuiMessage.IGuiMessage guiMessage,
IUpdateProgress updateProgress,
IGluonUpdateReport updateReport)
{
if (progress.ErrorMessages.Count == 0)
return;
UpdateReportResult updateReportResult =
updateReport.ShowUpdateReport(wkInfo, progress.ErrorMessages);
if (!updateReportResult.IsUpdateForcedRequested())
return;
UpdateForcedOperation updateForced = new UpdateForcedOperation(
wkInfo, viewHost, progress, progressControls,
guiMessage, updateProgress, updateReport);
updateForced.UpdateForced(
updateReportResult.UpdateForcedPaths,
updateReportResult.UnaffectedErrors);
}
void CheckinUIOperation.ICheckinView.ClearComments()
{
ClearComments();
}
void CheckinUIOperation.ICheckinView.CollapseWarningMessagePanel()
{
GluonWarningMessage = string.Empty;
RequestRepaint();
}
void CheckinUIOperation.ICheckinView.ExpandWarningMessagePanel(string text)
{
GluonWarningMessage = text;
RequestRepaint();
}
static bool CheckEmptyOperation(List<ChangeInfo> elements)
{
return elements == null || elements.Count == 0;
}
UpdateReportResult IGluonUpdateReport.ShowUpdateReport(
WorkspaceInfo wkInfo, List<ErrorMessage> errors)
{
return UpdateReportDialog.ShowUpdateReport(
wkInfo, errors, mPlasticWindow);
}
void IGluonUpdateReport.AppendReport(string updateReport)
{
throw new NotImplementedException();
}
}
}
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor
{
internal static class PlasticMenuItem
{
internal static void Add()
{
HandleMenuItem.AddMenuItem(
MENU_ITEM_NAME, MENU_ITEM_PRIORITY,
ShowPanel, ValidateMenu);
HandleMenuItem.UpdateAllMenus();
}
static bool ValidateMenu()
{
return !CollabPlugin.IsEnabled();
}
static void ShowPanel()
{
ShowWindow.Plastic();
}
const string MENU_ITEM_NAME = "Window/" + UnityConstants.PLASTIC_WINDOW_TITLE;
const int MENU_ITEM_PRIORITY = 1000;
}
}
using System;
using UnityEditor;
using UnityEngine;
using Codice.Client.BaseCommands.EventTracking;
using Codice.Client.Common;
using Codice.Client.Common.Encryption;
using Codice.Client.Common.EventTracking;
using Codice.Client.Common.FsNodeReaders;
using Codice.Client.Common.FsNodeReaders.Watcher;
using Codice.Client.Common.Threading;
using Codice.Client.Common.WebApi;
using Codice.CM.Common;
using Codice.LogWrapper;
using CodiceApp.EventTracking;
using GluonGui;
using PlasticGui;
using PlasticGui.Gluon;
using PlasticGui.WebApi;
using Unity.PlasticSCM.Editor.AssetMenu;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetsOverlays;
using Unity.PlasticSCM.Editor.AssetUtils.Processor;
using Unity.PlasticSCM.Editor.Configuration;
using Unity.PlasticSCM.Editor.Inspector;
using Unity.PlasticSCM.Editor.Tool;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.Avatar;
using Unity.PlasticSCM.Editor.UI.Progress;
using Unity.PlasticSCM.Editor.Views.CreateWorkspace;
using Unity.PlasticSCM.Editor.Views.Welcome;
using GluonCheckIncomingChanges = PlasticGui.Gluon.WorkspaceWindow.CheckIncomingChanges;
using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater;
using EventTracking = PlasticGui.EventTracking.EventTracking;
using Codice.Client.Common.Connection;
namespace Unity.PlasticSCM.Editor
{
internal class PlasticWindow : EditorWindow,
PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView,
GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView,
CreateWorkspaceView.ICreateWorkspaceListener
{
internal PlasticGUIClient PlasticClientForTesting { get { return mPlasticClient; } }
internal ViewSwitcher ViewSwitcherForTesting { get { return mViewSwitcher; } }
internal IPlasticAPI PlasticApiForTesting { get { return mPlasticAPI; } }
internal IPlasticWebRestApi PlasticWebRestApiForTesting { get { return mPlasticWebRestApi; } }
internal void SetupWindowTitle()
{
titleContent = new GUIContent(
UnityConstants.PLASTIC_WINDOW_TITLE,
Images.GetImage(Images.Name.IconPlasticView));
}
internal void DisableCollabIfEnabledWhenLoaded()
{
mDisableCollabIfEnabledWhenLoaded = true;
}
void PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible()
{
mViewSwitcher.AutoRefreshIncomingChangesView();
}
void GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible()
{
mViewSwitcher.AutoRefreshIncomingChangesView();
}
void CreateWorkspaceView.ICreateWorkspaceListener.OnWorkspaceCreated(
WorkspaceInfo wkInfo, bool isGluonMode)
{
mWkInfo = wkInfo;
mIsGluonMode = isGluonMode;
mWelcomeView = null;
if (mIsGluonMode)
ConfigurePartialWorkspace.AsFullyChecked(mWkInfo);
InitializePlastic();
Repaint();
}
void OnEnable()
{
wantsMouseMove = true;
if (mException != null)
return;
SetupWindowTitle();
GuiMessage.Initialize(new UnityPlasticGuiMessage(this));
PlasticApp.InitializeIfNeeded();
RegisterApplicationFocusHandlers(this);
PlasticMethodExceptionHandling.InitializeAskCredentialsUi(
new CredentialsUiImpl(this));
ClientEncryptionServiceProvider.SetEncryptionPasswordProvider(
new MissingEncryptionPasswordPromptHandler(this));
mPlasticAPI = new PlasticAPI();
mPlasticWebRestApi = new PlasticWebRestApi();
mEventSenderScheduler = EventTracking.Configure(
mPlasticWebRestApi,
ApplicationIdentifier.UnityPackage,
IdentifyEventPlatform.Get());
if (mEventSenderScheduler != null)
{
mPingEventLoop = new PingEventLoop();
mPingEventLoop.Start();
}
InitializePlastic();
}
void OnDisable()
{
AssetsProcessors.Disable();
if (mWkInfo != null)
{
MonoFileSystemWatcher.IsEnabled = false;
WorkspaceFsNodeReaderCachesCleaner.CleanWorkspaceFsNodeReader(mWkInfo);
}
if (mException != null)
return;
if (mWkInfo == null)
{
ClosePlasticWindow(this);
return;
}
mViewSwitcher.OnDisable();
ClosePlasticWindow(this);
}
void OnDestroy()
{
if (mException != null)
return;
if (mWkInfo == null)
return;
if (!mPlasticClient.IsOperationInProgress())
return;
bool bCloseWindow = GuiMessage.ShowQuestion(
PlasticLocalization.GetString(PlasticLocalization.Name.OperationRunning),
PlasticLocalization.GetString(PlasticLocalization.Name.ConfirmClosingRunningOperation),
PlasticLocalization.GetString(PlasticLocalization.Name.YesButton));
if (bCloseWindow)
return;
mForceToOpen = true;
ShowPlasticWindow(this);
}
void OnFocus()
{
if (mException != null)
return;
if (mWkInfo == null)
return;
mViewSwitcher.AutoRefreshPendingChangesView();
mViewSwitcher.AutoRefreshIncomingChangesView();
}
void OnGUI()
{
if (mException != null)
{
DoExceptionErrorArea();
return;
}
try
{
// IMPORTANT: disable collab (if needed)
// must be executed before the next if statement
// where we check if collab is enabled
if (mDisableCollabIfEnabledWhenLoaded)
{
mDisableCollabIfEnabledWhenLoaded = false;
DisableCollabIfEnabled(ProjectPath.FromApplicationDataPath(
Application.dataPath));
}
if (CollabPlugin.IsEnabled())
{
// execute Close() once after all inspectors update
// to avoid our window to be drawn in back color
EditorApplication.delayCall = Close;
return;
}
bool isPlasticExeAvailable = IsExeAvailable.ForMode(mIsGluonMode);
bool clientNeedsConfiguration = UnityConfigurationChecker.NeedsConfiguration();
if (NeedsToDisplayWelcomeView(
isPlasticExeAvailable,
clientNeedsConfiguration,
mWkInfo))
{
GetWelcomeView().OnGUI(
isPlasticExeAvailable,
clientNeedsConfiguration,
mIsGluonMode);
return;
}
DoHeader(
mWkInfo,
mPlasticClient,
mViewSwitcher,
mViewSwitcher,
mIsGluonMode,
mIncomingChangesNotificationPanel);
DoTabToolbar(
mWkInfo,
mPlasticClient,
mViewSwitcher,
mIsGluonMode);
mViewSwitcher.TabViewGUI();
if (mPlasticClient.IsOperationInProgress())
DrawProgressForOperations.For(
mPlasticClient, mPlasticClient.Progress,
position.width);
}
catch (Exception ex)
{
if (IsExitGUIException(ex))
throw;
GUI.enabled = true;
if (IsIMGUIPaintException(ex))
{
ExceptionsHandler.LogException("PlasticWindow", ex);
return;
}
mException = ex;
DoExceptionErrorArea();
ExceptionsHandler.HandleException("OnGUI", ex);
}
}
void Update()
{
if (mException != null)
return;
if (mWkInfo == null)
return;
try
{
double currentUpdateTime = EditorApplication.timeSinceStartup;
double elapsedSeconds = currentUpdateTime - mLastUpdateTime;
mViewSwitcher.Update();
mPlasticClient.OnParentUpdated(elapsedSeconds);
if (mWelcomeView != null)
mWelcomeView.Update();
mLastUpdateTime = currentUpdateTime;
}
catch (Exception ex)
{
mException = ex;
ExceptionsHandler.HandleException("Update", ex);
}
}
void InitializePlastic()
{
if (mForceToOpen)
{
mForceToOpen = false;
return;
}
try
{
if (UnityConfigurationChecker.NeedsConfiguration())
return;
mWkInfo = FindWorkspace.InfoForApplicationPath(
Application.dataPath, mPlasticAPI);
if (mWkInfo == null)
{
AssetMenuItems.Disable();
return;
}
MonoFileSystemWatcher.IsEnabled = true;
SetupCloudProjectIdIfNeeded(mWkInfo, mPlasticAPI);
DisableVCSIfEnabled(mWkInfo.ClientPath);
mIsGluonMode = mPlasticAPI.IsGluonWorkspace(mWkInfo);
IAssetStatusCache assetStatusCache =
new AssetStatusCache(
mWkInfo,
mIsGluonMode,
RepaintProjectWindow);
AssetsProcessors.Enable(
mPlasticAPI,
assetStatusCache);
if (mEventSenderScheduler != null)
{
mPingEventLoop.SetWorkspace(mWkInfo);
((IPlasticWebRestApi)mPlasticWebRestApi).SetToken(
CmConnection.Get().BuildWebApiTokenForCloudEditionDefaultUser());
}
InitializeNewIncomingChanges(mWkInfo, mIsGluonMode);
ViewHost viewHost = new ViewHost();
PlasticGui.WorkspaceWindow.PendingChanges.PendingChanges pendingChanges =
new PlasticGui.WorkspaceWindow.PendingChanges.PendingChanges(mWkInfo);
mViewSwitcher = new ViewSwitcher(
mWkInfo,
viewHost,
mIsGluonMode,
pendingChanges,
mDeveloperNewIncomingChangesUpdater,
mGluonNewIncomingChangesUpdater,
mIncomingChangesNotificationPanel,
assetStatusCache,
this);
mCooldownAutoRefreshPendingChangesAction = new CooldownWindowDelayer(
mViewSwitcher.AutoRefreshPendingChangesView,
UnityConstants.AUTO_REFRESH_PENDING_CHANGES_DELAYED_INTERVAL);
mPlasticClient = new PlasticGUIClient(
mWkInfo,
mViewSwitcher,
mViewSwitcher,
viewHost,
pendingChanges,
mDeveloperNewIncomingChangesUpdater,
mGluonNewIncomingChangesUpdater,
this,
new UnityPlasticGuiMessage(this));
mViewSwitcher.SetPlasticGUIClient(mPlasticClient);
mViewSwitcher.ShowInitialView();
UnityStyles.Initialize(Repaint);
AssetOperations.IAssetSelection inspectorAssetSelection =
new InspectorAssetSelection();
AssetOperations.IAssetSelection projectViewAssetSelection =
new ProjectViewAssetSelection();
AssetOperations inspectorAssetOperations =
new AssetOperations(
mWkInfo,
mPlasticClient,
mViewSwitcher,
mViewSwitcher,
viewHost,
mDeveloperNewIncomingChangesUpdater,
assetStatusCache,
mViewSwitcher,
mViewSwitcher,
this,
inspectorAssetSelection,
mIsGluonMode);
AssetOperations projectViewAssetOperations =
new AssetOperations(
mWkInfo,
mPlasticClient,
mViewSwitcher,
mViewSwitcher,
viewHost,
mDeveloperNewIncomingChangesUpdater,
assetStatusCache,
mViewSwitcher,
mViewSwitcher,
this,
projectViewAssetSelection,
mIsGluonMode);
AssetMenuItems.Enable(
projectViewAssetOperations,
assetStatusCache,
projectViewAssetSelection);
DrawInspectorOperations.Enable(
inspectorAssetOperations,
assetStatusCache,
inspectorAssetSelection);
DrawAssetOverlay.Initialize(
assetStatusCache,
RepaintProjectWindow);
mLastUpdateTime = EditorApplication.timeSinceStartup;
}
catch (Exception ex)
{
mException = ex;
ExceptionsHandler.HandleException("InitializePlastic", ex);
}
}
void InitializeNewIncomingChanges(
WorkspaceInfo wkInfo,
bool bIsGluonMode)
{
if (bIsGluonMode)
{
Gluon.IncomingChangesNotificationPanel gluonPanel =
new Gluon.IncomingChangesNotificationPanel(this);
mGluonNewIncomingChangesUpdater =
NewIncomingChanges.BuildUpdaterForGluon(
wkInfo,
this,
gluonPanel,
new GluonCheckIncomingChanges.CalculateIncomingChanges());
mIncomingChangesNotificationPanel = gluonPanel;
return;
}
Developer.IncomingChangesNotificationPanel developerPanel =
new Developer.IncomingChangesNotificationPanel(this);
mDeveloperNewIncomingChangesUpdater =
NewIncomingChanges.BuildUpdaterForDeveloper(
wkInfo, this, developerPanel);
mIncomingChangesNotificationPanel = developerPanel;
}
void OnApplicationActivated()
{
if (mException != null)
return;
Reload.IfWorkspaceConfigChanged(
mPlasticAPI, mWkInfo, mIsGluonMode,
ExecuteFullReload);
if (mWkInfo == null)
return;
((IWorkspaceWindow)mPlasticClient).UpdateTitle();
NewIncomingChanges.LaunchUpdater(
mDeveloperNewIncomingChangesUpdater,
mGluonNewIncomingChangesUpdater);
// When Unity Editor window is activated it writes some files to its Temp folder.
// This causes the fswatcher to process those events.
// We need to wait until the fswatcher finishes processing the events,
// otherwise the NewChangesInWk method will return TRUE, causing
// the pending changes view to unwanted auto-refresh.
// So, we need to delay the auto-refresh call in order
// to give the fswatcher enough time to process the events.
// Note that the OnFocus event is not affected by this issue.
mCooldownAutoRefreshPendingChangesAction.Ping();
mViewSwitcher.AutoRefreshIncomingChangesView();
}
void OnApplicationDeactivated()
{
if (mException != null)
return;
if (mWkInfo == null)
return;
NewIncomingChanges.StopUpdater(
mDeveloperNewIncomingChangesUpdater,
mGluonNewIncomingChangesUpdater);
}
void ExecuteFullReload()
{
mException = null;
DisposeNewIncomingChanges(this);
InitializePlastic();
}
void DoExceptionErrorArea()
{
string labelText = PlasticLocalization.GetString(
PlasticLocalization.Name.UnexpectedError);
string buttonText = PlasticLocalization.GetString(
PlasticLocalization.Name.ReloadButton);
DrawActionHelpBox.For(
Images.GetErrorDialogIcon(), labelText, buttonText,
ExecuteFullReload);
}
WelcomeView GetWelcomeView()
{
if (mWelcomeView != null)
return mWelcomeView;
mWelcomeView = new WelcomeView(
this,
this,
mPlasticAPI,
mPlasticWebRestApi);
return mWelcomeView;
}
static void DoHeader(
WorkspaceInfo workspaceInfo,
PlasticGUIClient plasticClient,
IMergeViewLauncher mergeViewLauncher,
IGluonViewSwitcher gluonSwitcher,
bool isGluonMode,
IIncomingChangesNotificationPanel incomingChangesNotificationPanel)
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
GUILayout.Label(
plasticClient.HeaderTitle,
UnityStyles.PlasticWindow.HeaderTitleLabel);
GUILayout.FlexibleSpace();
DrawIncomingChangesNotificationPanel.ForMode(
workspaceInfo, plasticClient,
mergeViewLauncher, gluonSwitcher, isGluonMode,
incomingChangesNotificationPanel.IsVisible,
incomingChangesNotificationPanel.Data);
//TODO: Codice - beta: hide the switcher until the update dialog is implemented
//DrawGuiModeSwitcher.ForMode(
// isGluonMode, plasticClient, changesTreeView, editorWindow);
EditorGUILayout.EndHorizontal();
}
static void DoTabToolbar(
WorkspaceInfo workspaceInfo,
PlasticGUIClient plasticClient,
ViewSwitcher viewSwitcher,
bool isGluonMode)
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
viewSwitcher.TabButtonsGUI();
GUILayout.FlexibleSpace();
DoLaunchButtons(workspaceInfo, isGluonMode);
EditorGUILayout.EndHorizontal();
}
static void DoLaunchButtons(
WorkspaceInfo wkInfo,
bool isGluonMode)
{
//TODO: Codice - beta: hide the diff button until the behavior is implemented
/*GUILayout.Button(PlasticLocalization.GetString(
PlasticLocalization.Name.DiffWindowMenuItemDiff),
EditorStyles.toolbarButton,
GUILayout.Width(UnityConstants.REGULAR_BUTTON_WIDTH));*/
if (isGluonMode)
{
var label = PlasticLocalization.GetString(PlasticLocalization.Name.ConfigureGluon);
if (DrawActionButton.For(label))
LaunchTool.OpenWorkspaceConfiguration(wkInfo);
}
else
{
var label = PlasticLocalization.GetString(PlasticLocalization.Name.LaunchBranchExplorer);
if (DrawActionButton.For(label))
LaunchTool.OpenBranchExplorer(wkInfo);
}
string openToolText = isGluonMode ?
PlasticLocalization.GetString(PlasticLocalization.Name.LaunchGluonButton) :
PlasticLocalization.GetString(PlasticLocalization.Name.LaunchPlasticButton);
if (DrawActionButton.For(openToolText))
LaunchTool.OpenGUIForMode(wkInfo, isGluonMode);
}
static void SetupCloudProjectIdIfNeeded(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi)
{
if (SetupCloudProjectId.HasCloudProjectId())
return;
SetupCloudProjectId.ForWorkspace(wkInfo, plasticApi);
mLog.DebugFormat("Setup CloudProjectId on Project: {0}",
wkInfo.ClientPath);
}
static void DisableVCSIfEnabled(string projectPath)
{
if (!VCSPlugin.IsEnabled())
return;
VCSPlugin.Disable();
mLog.DebugFormat("Disabled VCS Plugin on Project: {0}",
projectPath);
}
static void DisposeNewIncomingChanges(PlasticWindow window)
{
NewIncomingChanges.DisposeUpdater(
window.mDeveloperNewIncomingChangesUpdater,
window.mGluonNewIncomingChangesUpdater);
window.mDeveloperNewIncomingChangesUpdater = null;
window.mGluonNewIncomingChangesUpdater = null;
}
static void RegisterApplicationFocusHandlers(PlasticWindow window)
{
EditorWindowFocus.OnApplicationActivated += window.OnApplicationActivated;
EditorWindowFocus.OnApplicationDeactivated += window.OnApplicationDeactivated;
}
static void UnRegisterApplicationFocusHandlers(PlasticWindow window)
{
EditorWindowFocus.OnApplicationActivated -= window.OnApplicationActivated;
EditorWindowFocus.OnApplicationDeactivated -= window.OnApplicationDeactivated;
}
static bool IsExitGUIException(Exception ex)
{
return ex is ExitGUIException;
}
static bool IsIMGUIPaintException(Exception ex)
{
if (!(ex is ArgumentException))
return false;
return ex.Message.StartsWith("Getting control") &&
ex.Message.Contains("controls when doing repaint");
}
static void ClosePlasticWindow(PlasticWindow window)
{
UnRegisterApplicationFocusHandlers(window);
PlasticApp.Dispose();
AssetMenuItems.Disable();
DrawInspectorOperations.Disable();
DrawAssetOverlay.Dispose();
if (window.mEventSenderScheduler != null)
{
window.mPingEventLoop.Stop();
window.mEventSenderScheduler.End();
}
DisposeNewIncomingChanges(window);
AvatarImages.Dispose();
}
static void ShowPlasticWindow(PlasticWindow window)
{
EditorWindow dockWindow = FindEditorWindow.ToDock<PlasticWindow>();
PlasticWindow newPlasticWindow = InstantiateFrom(window);
if (DockEditorWindow.IsAvailable())
DockEditorWindow.To(dockWindow, newPlasticWindow);
newPlasticWindow.Show();
newPlasticWindow.Focus();
}
static bool NeedsToDisplayWelcomeView(
bool isPlasticExeAvailable,
bool clientNeedsConfiguration,
WorkspaceInfo wkInfo)
{
if (!isPlasticExeAvailable)
return true;
if (clientNeedsConfiguration)
return true;
if (wkInfo == null)
return true;
return false;
}
static void RepaintProjectWindow()
{
EditorWindow projectWindow = FindEditorWindow.ProjectWindow();
if (projectWindow == null)
return;
projectWindow.Repaint();
}
static void DisableCollabIfEnabled(string projectPath)
{
if (!CollabPlugin.IsEnabled())
return;
CollabPlugin.Disable();
mLog.DebugFormat("Disabled Collab Plugin on Project: {0}",
projectPath);
}
static PlasticWindow InstantiateFrom(PlasticWindow window)
{
PlasticWindow result = Instantiate(window);
result.mWkInfo = window.mWkInfo;
result.mPlasticClient = window.mPlasticClient;
result.mViewSwitcher = window.mViewSwitcher;
result.mCooldownAutoRefreshPendingChangesAction = window.mCooldownAutoRefreshPendingChangesAction;
result.mDeveloperNewIncomingChangesUpdater = window.mDeveloperNewIncomingChangesUpdater;
result.mGluonNewIncomingChangesUpdater = window.mGluonNewIncomingChangesUpdater;
result.mException = window.mException;
result.mLastUpdateTime = window.mLastUpdateTime;
result.mIsGluonMode = window.mIsGluonMode;
result.mIncomingChangesNotificationPanel = window.mIncomingChangesNotificationPanel;
result.mWelcomeView = window.mWelcomeView;
result.mPlasticAPI = window.mPlasticAPI;
result.mEventSenderScheduler = window.mEventSenderScheduler;
result.mPingEventLoop = window.mPingEventLoop;
return result;
}
static class Reload
{
internal static void IfWorkspaceConfigChanged(
IPlasticAPI plasticApi,
WorkspaceInfo lastWkInfo,
bool lastIsGluonMode,
Action reloadAction)
{
string applicationPath = Application.dataPath;
bool isGluonMode = false;
WorkspaceInfo wkInfo = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
wkInfo = FindWorkspace.
InfoForApplicationPath(applicationPath, plasticApi);
if (wkInfo != null)
isGluonMode = plasticApi.IsGluonWorkspace(wkInfo);
},
/*afterOperationDelegate*/ delegate
{
if (waiter.Exception != null)
return;
if (!IsWorkspaceConfigChanged(
lastWkInfo, wkInfo,
lastIsGluonMode, isGluonMode))
return;
reloadAction();
});
}
static bool IsWorkspaceConfigChanged(
WorkspaceInfo lastWkInfo,
WorkspaceInfo currentWkInfo,
bool lastIsGluonMode,
bool currentIsGluonMode)
{
if (lastIsGluonMode != currentIsGluonMode)
return true;
if (lastWkInfo == null || currentWkInfo == null)
return true;
return !lastWkInfo.Equals(currentWkInfo);
}
}
[SerializeField]
bool mForceToOpen;
[NonSerialized]
WorkspaceInfo mWkInfo;
Exception mException;
IIncomingChangesNotificationPanel mIncomingChangesNotificationPanel;
double mLastUpdateTime = 0f;
CooldownWindowDelayer mCooldownAutoRefreshPendingChangesAction;
ViewSwitcher mViewSwitcher;
WelcomeView mWelcomeView;
PlasticGui.WorkspaceWindow.NewIncomingChangesUpdater mDeveloperNewIncomingChangesUpdater;
GluonNewIncomingChangesUpdater mGluonNewIncomingChangesUpdater;
PlasticGUIClient mPlasticClient;
bool mIsGluonMode;
bool mDisableCollabIfEnabledWhenLoaded;
PlasticAPI mPlasticAPI;
static PlasticWebRestApi mPlasticWebRestApi;
EventSenderScheduler mEventSenderScheduler;
PingEventLoop mPingEventLoop;
static readonly ILog mLog = LogManager.GetLogger("PlasticWindow");
}
}
\ No newline at end of file
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticGui;
namespace Unity.PlasticSCM.Editor
{
static class SetupCloudProjectId
{
internal static bool HasCloudProjectId()
{
//disable Warning CS0618 'PlayerSettings.cloudProjectId' is obsolete: 'cloudProjectId is deprecated
#pragma warning disable 0618
return !string.IsNullOrEmpty(PlayerSettings.cloudProjectId);
}
internal static void ForWorkspace(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi)
{
RepositoryInfo repInfo = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
RepositorySpec repSpec = plasticApi.GetRepositorySpec(wkInfo);
repInfo = plasticApi.GetRepositoryInfo(repSpec);
},
/*afterOperationDelegate*/ delegate
{
if (waiter.Exception != null)
{
ExceptionsHandler.LogException(
"SetupCloudProjectId",
waiter.Exception);
return;
}
SetupCloudProjectId.ForRepository(repInfo);
});
}
internal static void ForRepository(RepositoryInfo repInfo)
{
string projectId = repInfo.GUID.ToString();
// Invokes PlayerSettings.SetCloudProjectId(projectId)
SetCloudProjectId(projectId);
AssetDatabase.SaveAssets();
}
static void SetCloudProjectId(string projectId)
{
MethodInfo InternalSetCloudProjectId = PlayerSettingsType.GetMethod(
"SetCloudProjectId",
BindingFlags.NonPublic | BindingFlags.Static);
if (InternalSetCloudProjectId == null)
{
Debug.LogWarning(PlasticLocalization.GetString(
PlasticLocalization.Name.CannotWriteCloudProjectId));
return;
}
InternalSetCloudProjectId.Invoke(
null, new object[] { projectId });
}
static readonly Type PlayerSettingsType =
typeof(UnityEditor.PlayerSettings);
static readonly ILog mLog = LogManager.GetLogger("SetupCloudProjectId");
}
}
using UnityEditor;
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor
{
internal class SwitchModeConfirmationDialog : PlasticDialog
{
protected override Rect DefaultRect
{
get
{
var baseRect = base.DefaultRect;
return new Rect(baseRect.x, baseRect.y, 560, 180);
}
}
internal static bool SwitchMode(
bool isGluonMode,
EditorWindow parentWindow)
{
SwitchModeConfirmationDialog dialog = Create(isGluonMode);
return dialog.RunModal(parentWindow) == ResponseType.Ok;
}
protected override void OnModalGUI()
{
Title(PlasticLocalization.GetString(
PlasticLocalization.Name.SwitchModeConfirmationDialogTitle));
DoExplanationArea(mIsGluonMode);
GUILayout.Space(20);
DoButtonsArea();
}
protected override string GetTitle()
{
return PlasticLocalization.GetString(
PlasticLocalization.Name.SwitchModeConfirmationDialogTitle);
}
void DoExplanationArea(bool isGluonMode)
{
PlasticLocalization.Name currentMode = isGluonMode ?
PlasticLocalization.Name.GluonMode :
PlasticLocalization.Name.DeveloperMode;
PlasticLocalization.Name selectedMode = isGluonMode ?
PlasticLocalization.Name.DeveloperMode :
PlasticLocalization.Name.GluonMode;
string formattedExplanation = PlasticLocalization.GetString(
PlasticLocalization.Name.SwitchModeConfirmationDialogExplanation,
PlasticLocalization.GetString(currentMode),
PlasticLocalization.GetString(selectedMode),
"{0}");
TextBlockWithEndLink(
GLUON_HELP_URL, formattedExplanation, UnityStyles.Paragraph);
}
void DoButtonsArea()
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (Application.platform == RuntimePlatform.WindowsEditor)
{
DoSwitchButton();
DoCancelButton();
return;
}
DoCancelButton();
DoSwitchButton();
}
}
void DoSwitchButton()
{
if (!AcceptButton(PlasticLocalization.GetString(
PlasticLocalization.Name.SwitchButton)))
return;
OkButtonAction();
}
void DoCancelButton()
{
if (!NormalButton(PlasticLocalization.GetString(
PlasticLocalization.Name.CancelButton)))
return;
CancelButtonAction();
}
static SwitchModeConfirmationDialog Create(
bool isGluonMode)
{
var instance = CreateInstance<SwitchModeConfirmationDialog>();
instance.mIsGluonMode = isGluonMode;
instance.mEnterKeyAction = instance.OkButtonAction;
instance.mEscapeKeyAction = instance.CancelButtonAction;
return instance;
}
bool mIsGluonMode;
const string GLUON_HELP_URL = "https://www.plasticscm.com/gluon";
}
}
using System;
using System.Runtime.InteropServices;
namespace Unity.PlasticSCM.Editor.Tool
{
internal static class BringWindowToFront
{
internal static void ForWindowsProcess(int processId)
{
IntPtr handle = FindMainWindowForProcess(processId);
if (IsIconic(handle))
ShowWindow(handle, SW_RESTORE);
SetForegroundWindow(handle);
}
static IntPtr FindMainWindowForProcess(int processId)
{
IntPtr result = IntPtr.Zero;
EnumWindows(delegate (IntPtr wnd, IntPtr param)
{
uint windowProcessId = 0;
GetWindowThreadProcessId(wnd, out windowProcessId);
if (windowProcessId == processId &&
IsMainWindow(wnd))
{
result = wnd;
return false;
}
return true;
}, IntPtr.Zero);
return result;
}
static bool IsMainWindow(IntPtr handle)
{
return GetWindow(new HandleRef(null, handle), GW_OWNER) == IntPtr.Zero
&& IsWindowVisible(new HandleRef(null, handle));
}
// Delegate to filter which windows to include
delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
static extern IntPtr GetWindow(HandleRef hWnd, int uCmd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern bool IsWindowVisible(HandleRef hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr handle);
[DllImport("user32.dll")]
static extern bool IsIconic(IntPtr handle);
const int GW_OWNER = 4;
const int SW_RESTORE = 9;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment