390 lines
12 KiB
C#
390 lines
12 KiB
C#
|
using System.Collections.Generic;
|
|||
|
using System.IO;
|
|||
|
|
|||
|
using UnityEditor;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
using Codice.Client.Common;
|
|||
|
using Codice.Client.Common.EventTracking;
|
|||
|
|
|||
|
using Codice.CM.Common;
|
|||
|
using GluonGui;
|
|||
|
using PlasticGui;
|
|||
|
using PlasticGui.Gluon;
|
|||
|
|
|||
|
using Unity.PlasticSCM.Editor.AssetsOverlays;
|
|||
|
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
|
|||
|
using Unity.PlasticSCM.Editor.AssetUtils;
|
|||
|
using Unity.PlasticSCM.Editor.AssetUtils.Processor;
|
|||
|
using Unity.PlasticSCM.Editor.UI;
|
|||
|
using Unity.PlasticSCM.Editor.UI.Progress;
|
|||
|
using Unity.PlasticSCM.Editor.UI.Tree;
|
|||
|
|
|||
|
namespace Unity.PlasticSCM.Editor.AssetMenu.Dialogs
|
|||
|
{
|
|||
|
internal class CheckinDialog : PlasticDialog
|
|||
|
{
|
|||
|
protected override Rect DefaultRect
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
var baseRect = base.DefaultRect;
|
|||
|
return new Rect(baseRect.x, baseRect.y, 700, 450);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected override string GetTitle()
|
|||
|
{
|
|||
|
return PlasticLocalization.GetString(
|
|||
|
PlasticLocalization.Name.CheckinChanges);
|
|||
|
}
|
|||
|
|
|||
|
internal static bool CheckinPaths(
|
|||
|
WorkspaceInfo wkInfo,
|
|||
|
List<string> paths,
|
|||
|
IAssetStatusCache assetStatusCache,
|
|||
|
bool isGluonMode,
|
|||
|
IWorkspaceWindow workspaceWindow,
|
|||
|
ViewHost viewHost,
|
|||
|
WorkspaceOperationsMonitor workspaceOperationsMonitor,
|
|||
|
GuiMessage.IGuiMessage guiMessage,
|
|||
|
IMergeViewLauncher mergeViewLauncher,
|
|||
|
IGluonViewSwitcher gluonViewSwitcher)
|
|||
|
{
|
|||
|
MetaCache metaCache = new MetaCache();
|
|||
|
metaCache.Build(paths);
|
|||
|
|
|||
|
CheckinDialog dialog = Create(
|
|||
|
wkInfo,
|
|||
|
paths,
|
|||
|
assetStatusCache,
|
|||
|
metaCache,
|
|||
|
isGluonMode,
|
|||
|
new ProgressControlsForDialogs(),
|
|||
|
workspaceWindow,
|
|||
|
viewHost,
|
|||
|
workspaceOperationsMonitor,
|
|||
|
guiMessage,
|
|||
|
mergeViewLauncher,
|
|||
|
gluonViewSwitcher);
|
|||
|
|
|||
|
return dialog.RunModal(focusedWindow) == ResponseType.Ok;
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnModalGUI()
|
|||
|
{
|
|||
|
Title(PlasticLocalization.GetString(PlasticLocalization.Name.CheckinOnlyComment));
|
|||
|
|
|||
|
GUI.SetNextControlName(CHECKIN_TEXTAREA_NAME);
|
|||
|
|
|||
|
mComment = GUILayout.TextArea(
|
|||
|
mComment,
|
|||
|
EditorStyles.textArea,
|
|||
|
GUILayout.MinHeight(120));
|
|||
|
|
|||
|
if (!mTextAreaFocused)
|
|||
|
{
|
|||
|
EditorGUI.FocusTextInControl(CHECKIN_TEXTAREA_NAME);
|
|||
|
mTextAreaFocused = true;
|
|||
|
}
|
|||
|
|
|||
|
Title(PlasticLocalization.GetString(PlasticLocalization.Name.Files));
|
|||
|
|
|||
|
DoFileList(
|
|||
|
mWkInfo,
|
|||
|
mPaths,
|
|||
|
mAssetStatusCache,
|
|||
|
mMetaCache);
|
|||
|
|
|||
|
DrawProgressForDialogs.For(
|
|||
|
mProgressControls.ProgressData);
|
|||
|
|
|||
|
DoButtonsArea();
|
|||
|
|
|||
|
mProgressControls.ForcedUpdateProgress(this);
|
|||
|
}
|
|||
|
|
|||
|
void DoFileList(
|
|||
|
WorkspaceInfo wkInfo,
|
|||
|
List<string> paths,
|
|||
|
IAssetStatusCache assetStatusCache,
|
|||
|
MetaCache metaCache)
|
|||
|
{
|
|||
|
mFileListScrollPosition = GUILayout.BeginScrollView(
|
|||
|
mFileListScrollPosition,
|
|||
|
EditorStyles.helpBox,
|
|||
|
GUILayout.ExpandHeight(true));
|
|||
|
|
|||
|
foreach (string path in paths)
|
|||
|
{
|
|||
|
if (MetaPath.IsMetaPath(path))
|
|||
|
continue;
|
|||
|
|
|||
|
Texture fileIcon = Directory.Exists(path) ?
|
|||
|
Images.GetDirectoryIcon() :
|
|||
|
Images.GetFileIcon(path);
|
|||
|
|
|||
|
string label = WorkspacePath.GetWorkspaceRelativePath(
|
|||
|
wkInfo.ClientPath, path);
|
|||
|
|
|||
|
if (metaCache.HasMeta(path))
|
|||
|
label = string.Concat(label, UnityConstants.TREEVIEW_META_LABEL);
|
|||
|
|
|||
|
AssetsOverlays.AssetStatus assetStatus =
|
|||
|
assetStatusCache.GetStatus(path);
|
|||
|
|
|||
|
Rect selectionRect = EditorGUILayout.GetControlRect();
|
|||
|
|
|||
|
DoListViewItem(selectionRect, fileIcon, label, assetStatus);
|
|||
|
}
|
|||
|
|
|||
|
GUILayout.EndScrollView();
|
|||
|
}
|
|||
|
|
|||
|
void DoListViewItem(
|
|||
|
Rect itemRect,
|
|||
|
Texture fileIcon,
|
|||
|
string label,
|
|||
|
AssetsOverlays.AssetStatus statusToDraw)
|
|||
|
{
|
|||
|
Texture overlayIcon = DrawAssetOverlay.DrawOverlayIcon.
|
|||
|
GetOverlayIcon(statusToDraw);
|
|||
|
|
|||
|
itemRect = DrawTreeViewItem.DrawIconLeft(
|
|||
|
itemRect,
|
|||
|
UnityConstants.TREEVIEW_ROW_HEIGHT,
|
|||
|
fileIcon,
|
|||
|
overlayIcon);
|
|||
|
|
|||
|
GUI.Label(itemRect, label);
|
|||
|
}
|
|||
|
|
|||
|
void DoButtonsArea()
|
|||
|
{
|
|||
|
using (new EditorGUILayout.HorizontalScope())
|
|||
|
{
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
|
|||
|
if (Application.platform == RuntimePlatform.WindowsEditor)
|
|||
|
{
|
|||
|
DoCheckinButton();
|
|||
|
DoCancelButton();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
DoCancelButton();
|
|||
|
DoCheckinButton();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void DoCheckinButton()
|
|||
|
{
|
|||
|
GUI.enabled = !string.IsNullOrEmpty(mComment) && !mIsRunningCheckin;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
if (!AcceptButton(PlasticLocalization.GetString(
|
|||
|
PlasticLocalization.Name.CheckinButton)))
|
|||
|
return;
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
if (!mSentCheckinTrackEvent)
|
|||
|
{
|
|||
|
TrackFeatureUseEvent.For(
|
|||
|
PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
|
|||
|
TrackFeatureUseEvent.Features.ContextMenuCheckinDialogCheckin);
|
|||
|
|
|||
|
mSentCheckinTrackEvent = true;
|
|||
|
}
|
|||
|
|
|||
|
GUI.enabled = true;
|
|||
|
}
|
|||
|
|
|||
|
OkButtonWithCheckinAction();
|
|||
|
}
|
|||
|
|
|||
|
void DoCancelButton()
|
|||
|
{
|
|||
|
if (!NormalButton(PlasticLocalization.GetString(
|
|||
|
PlasticLocalization.Name.CancelButton)))
|
|||
|
return;
|
|||
|
|
|||
|
if (!mSentCancelTrackEvent)
|
|||
|
{
|
|||
|
TrackFeatureUseEvent.For(
|
|||
|
PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
|
|||
|
TrackFeatureUseEvent.Features.ContextMenuCheckinDialogCancel);
|
|||
|
|
|||
|
mSentCancelTrackEvent = true;
|
|||
|
}
|
|||
|
|
|||
|
CancelButtonAction();
|
|||
|
}
|
|||
|
|
|||
|
void OkButtonWithCheckinAction()
|
|||
|
{
|
|||
|
bool isCancelled;
|
|||
|
SaveAssets.ForPathsWithConfirmation(
|
|||
|
mPaths, mWorkspaceOperationsMonitor,
|
|||
|
out isCancelled);
|
|||
|
|
|||
|
if (isCancelled)
|
|||
|
return;
|
|||
|
|
|||
|
mIsRunningCheckin = true;
|
|||
|
|
|||
|
mPaths.AddRange(mMetaCache.GetExistingMeta(mPaths));
|
|||
|
|
|||
|
if (mIsGluonMode)
|
|||
|
{
|
|||
|
CheckinDialogOperations.CheckinPathsPartial(
|
|||
|
mWkInfo,
|
|||
|
mPaths,
|
|||
|
mComment,
|
|||
|
mViewHost,
|
|||
|
this,
|
|||
|
mGuiMessage,
|
|||
|
mProgressControls,
|
|||
|
mGluonViewSwitcher);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
CheckinDialogOperations.CheckinPaths(
|
|||
|
mWkInfo,
|
|||
|
mPaths,
|
|||
|
mComment,
|
|||
|
mWorkspaceWindow,
|
|||
|
this,
|
|||
|
mGuiMessage,
|
|||
|
mProgressControls,
|
|||
|
mMergeViewLauncher);
|
|||
|
}
|
|||
|
|
|||
|
static CheckinDialog Create(
|
|||
|
WorkspaceInfo wkInfo,
|
|||
|
List<string> paths,
|
|||
|
IAssetStatusCache assetStatusCache,
|
|||
|
MetaCache metaCache,
|
|||
|
bool isGluonMode,
|
|||
|
ProgressControlsForDialogs progressControls,
|
|||
|
IWorkspaceWindow workspaceWindow,
|
|||
|
ViewHost viewHost,
|
|||
|
WorkspaceOperationsMonitor workspaceOperationsMonitor,
|
|||
|
GuiMessage.IGuiMessage guiMessage,
|
|||
|
IMergeViewLauncher mergeViewLauncher,
|
|||
|
IGluonViewSwitcher gluonViewSwitcher)
|
|||
|
{
|
|||
|
var instance = CreateInstance<CheckinDialog>();
|
|||
|
instance.IsResizable = true;
|
|||
|
instance.minSize = new Vector2(520, 370);
|
|||
|
instance.mWkInfo = wkInfo;
|
|||
|
instance.mPaths = paths;
|
|||
|
instance.mAssetStatusCache = assetStatusCache;
|
|||
|
instance.mMetaCache = metaCache;
|
|||
|
instance.mIsGluonMode = isGluonMode;
|
|||
|
instance.mProgressControls = progressControls;
|
|||
|
instance.mWorkspaceWindow = workspaceWindow;
|
|||
|
instance.mViewHost = viewHost;
|
|||
|
instance.mWorkspaceOperationsMonitor = workspaceOperationsMonitor;
|
|||
|
instance.mGuiMessage = guiMessage;
|
|||
|
instance.mMergeViewLauncher = mergeViewLauncher;
|
|||
|
instance.mGluonViewSwitcher = gluonViewSwitcher;
|
|||
|
instance.mEscapeKeyAction = instance.CancelButtonAction;
|
|||
|
return instance;
|
|||
|
}
|
|||
|
|
|||
|
WorkspaceInfo mWkInfo;
|
|||
|
List<string> mPaths;
|
|||
|
IAssetStatusCache mAssetStatusCache;
|
|||
|
MetaCache mMetaCache;
|
|||
|
bool mIsGluonMode;
|
|||
|
bool mTextAreaFocused;
|
|||
|
string mComment;
|
|||
|
|
|||
|
bool mIsRunningCheckin;
|
|||
|
Vector2 mFileListScrollPosition;
|
|||
|
|
|||
|
// IMGUI evaluates every frame, need to make sure feature tracks get sent only once
|
|||
|
bool mSentCheckinTrackEvent = false;
|
|||
|
bool mSentCancelTrackEvent = false;
|
|||
|
|
|||
|
ProgressControlsForDialogs mProgressControls;
|
|||
|
|
|||
|
IWorkspaceWindow mWorkspaceWindow;
|
|||
|
WorkspaceOperationsMonitor mWorkspaceOperationsMonitor;
|
|||
|
ViewHost mViewHost;
|
|||
|
IMergeViewLauncher mMergeViewLauncher;
|
|||
|
IGluonViewSwitcher mGluonViewSwitcher;
|
|||
|
GuiMessage.IGuiMessage mGuiMessage;
|
|||
|
|
|||
|
const string CHECKIN_TEXTAREA_NAME = "checkin_textarea";
|
|||
|
|
|||
|
class MetaCache
|
|||
|
{
|
|||
|
internal bool HasMeta(string path)
|
|||
|
{
|
|||
|
return mCache.Contains(MetaPath.GetMetaPath(path));
|
|||
|
}
|
|||
|
|
|||
|
internal List<string> GetExistingMeta(List<string> paths)
|
|||
|
{
|
|||
|
List<string> result = new List<string>();
|
|||
|
|
|||
|
foreach (string path in paths)
|
|||
|
{
|
|||
|
string metaPath = MetaPath.GetMetaPath(path);
|
|||
|
|
|||
|
if (!mCache.Contains(metaPath))
|
|||
|
continue;
|
|||
|
|
|||
|
result.Add(metaPath);
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
internal void Build(List<string> paths)
|
|||
|
{
|
|||
|
HashSet<string> indexedKeys = BuildIndexedKeys(paths);
|
|||
|
|
|||
|
for (int i = paths.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
string currentPath = paths[i];
|
|||
|
|
|||
|
if (!MetaPath.IsMetaPath(currentPath))
|
|||
|
continue;
|
|||
|
|
|||
|
string realPath = MetaPath.GetPathFromMetaPath(currentPath);
|
|||
|
|
|||
|
if (!indexedKeys.Contains(realPath))
|
|||
|
continue;
|
|||
|
|
|||
|
// found foo.c and foo.c.meta
|
|||
|
// with the same chage types - move .meta to cache
|
|||
|
mCache.Add(currentPath);
|
|||
|
paths.RemoveAt(i);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static HashSet<string> BuildIndexedKeys(List<string> paths)
|
|||
|
{
|
|||
|
HashSet<string> result = new HashSet<string>();
|
|||
|
|
|||
|
foreach (string path in paths)
|
|||
|
{
|
|||
|
if (MetaPath.IsMetaPath(path))
|
|||
|
continue;
|
|||
|
|
|||
|
result.Add(path);
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
HashSet<string> mCache =
|
|||
|
new HashSet<string>();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|