Initial project commit

This commit is contained in:
2026-01-08 16:50:20 +00:00
commit f0c5a8b267
29596 changed files with 4861782 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
using System.Collections.Generic;
using UnityEditor;
using Codice.CM.Common;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetUtils;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal class AssetCopyPathOperation : IAssetMenuCopyPathOperation
{
internal AssetCopyPathOperation(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
IAssetStatusCache assetStatusCache,
AssetUVCSOperations.IAssetSelection assetSelection)
{
mWkInfo = wkInfo;
mPlasticAPI = plasticApi;
mAssetStatusCache = assetStatusCache;
mAssetSelection = assetSelection;
}
void IAssetMenuCopyPathOperation.CopyFilePath(bool relativePath)
{
List<string> selectedPaths = GetSelectedPaths.ForOperation(
mWkInfo,
mAssetSelection.GetSelectedAssets(),
mPlasticAPI,
mAssetStatusCache,
AssetMenuOperations.CopyFilePath,
includeMetaFiles: false);
EditorGUIUtility.systemCopyBuffer = GetFilePathList.FromSelectedPaths(
selectedPaths,
relativePath,
mWkInfo.ClientPath);
}
readonly WorkspaceInfo mWkInfo;
readonly IPlasticAPI mPlasticAPI;
readonly IAssetStatusCache mAssetStatusCache;
readonly AssetUVCSOperations.IAssetSelection mAssetSelection;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d2a9f8ad3405465db8e62d36f2686b68
timeCreated: 1730989830

View File

@@ -0,0 +1,274 @@
using Codice.Client.BaseCommands;
using PlasticGui;
using PlasticGui.WorkspaceWindow.Items;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal interface IAssetFilesFilterPatternsMenuOperations
{
void AddFilesFilterPatterns(
FilterTypes type, FilterActions action, FilterOperationType operation);
}
internal class AssetFilesFilterPatternsMenuBuilder
{
internal string IgnoredSubmenuItem { get { return mIgnoredSubmenuItem; } }
internal string HiddenChangesSubmenuItem { get { return mHiddenChangesSubmenuItem; } }
internal AssetFilesFilterPatternsMenuBuilder(
int ignoredMenuItemsPriority,
int hiddenChangesMenuItemsPriority)
{
mIgnoredMenuItemsPriority = ignoredMenuItemsPriority;
mHiddenChangesMenuItemsPriority = hiddenChangesMenuItemsPriority;
mIgnoredSubmenuItem = string.Format(
"{0}/{1}",
PlasticLocalization.GetString(PlasticLocalization.Name.PrefixUnityVersionControlMenu),
PlasticLocalization.GetString(PlasticLocalization.Name.MenuAddToIgnoreList));
mHiddenChangesSubmenuItem = string.Format(
"{0}/{1}",
PlasticLocalization.GetString(PlasticLocalization.Name.PrefixUnityVersionControlMenu),
PlasticLocalization.GetString(PlasticLocalization.Name.MenuAddToHiddenChangesList));
}
internal void SetOperations(
IAssetFilesFilterPatternsMenuOperations operations)
{
mOperations = operations;
}
internal void UpdateMenuItems(FilterMenuActions actions)
{
UpdateIgnoredMenuItems(actions);
UpdateHiddenChangesMenuItems(actions);
HandleMenuItem.UpdateAllMenus();
}
internal void RemoveMenuItems()
{
RemoveIgnoredMenuItems();
RemoveHiddenChangesMenuItems();
}
internal void IgnoredByName_Click()
{
if (mOperations == null)
ShowWindow.UVCS();
mOperations.AddFilesFilterPatterns(
FilterTypes.Ignored, FilterActions.ByName,
GetIgnoredFilterOperationType());
}
internal void IgnoredByExtension_Click()
{
if (mOperations == null)
ShowWindow.UVCS();
mOperations.AddFilesFilterPatterns(
FilterTypes.Ignored, FilterActions.ByExtension,
GetIgnoredFilterOperationType());
}
internal void IgnoredByFullPath_Click()
{
if (mOperations == null)
ShowWindow.UVCS();
mOperations.AddFilesFilterPatterns(
FilterTypes.Ignored, FilterActions.ByFullPath,
GetIgnoredFilterOperationType());
}
internal void HiddenChangesByName_Click()
{
if (mOperations == null)
ShowWindow.UVCS();
mOperations.AddFilesFilterPatterns(
FilterTypes.HiddenChanges, FilterActions.ByName,
GetHiddenChangesFilterOperationType());
}
internal void HiddenChangesByExtension_Click()
{
if (mOperations == null)
ShowWindow.UVCS();
mOperations.AddFilesFilterPatterns(
FilterTypes.HiddenChanges, FilterActions.ByExtension,
GetHiddenChangesFilterOperationType());
}
internal void HiddenChangesByFullPath_Click()
{
if (mOperations == null)
ShowWindow.UVCS();
mOperations.AddFilesFilterPatterns(
FilterTypes.HiddenChanges, FilterActions.ByFullPath,
GetHiddenChangesFilterOperationType());
}
void UpdateIgnoredMenuItems(FilterMenuActions actions)
{
RemoveIgnoredMenuItems();
mIgnoredSubmenuItem = string.Format(
"{0}/{1}",
PlasticLocalization.Name.PrefixUnityVersionControlMenu.GetString(),
actions.IgnoredTitle);
if (!actions.Operations.HasFlag(FilterMenuOperations.Ignore))
{
HandleMenuItem.AddMenuItem(
mIgnoredSubmenuItem,
mIgnoredMenuItemsPriority,
DisabledMenuItem_Click, ValidateDisabledMenuItem);
return;
}
mIgnoredByNameMenuItem = GetIgnoredMenuItemName(actions.FilterByName);
mIgnoredByExtensionMenuItem = GetIgnoredMenuItemName(actions.FilterByExtension);
mIgnoredByFullPathMenuItem = GetIgnoredMenuItemName(actions.FilterByFullPath);
HandleMenuItem.AddMenuItem(
mIgnoredByNameMenuItem,
mIgnoredMenuItemsPriority,
IgnoredByName_Click, ValidateEnabledMenuItem);
if (actions.Operations.HasFlag(FilterMenuOperations.IgnoreByExtension))
HandleMenuItem.AddMenuItem(
mIgnoredByExtensionMenuItem,
mIgnoredMenuItemsPriority,
IgnoredByExtension_Click, ValidateEnabledMenuItem);
HandleMenuItem.AddMenuItem(
mIgnoredByFullPathMenuItem,
mIgnoredMenuItemsPriority,
IgnoredByFullPath_Click, ValidateEnabledMenuItem);
}
void UpdateHiddenChangesMenuItems(FilterMenuActions actions)
{
RemoveHiddenChangesMenuItems();
mHiddenChangesSubmenuItem = string.Format(
"{0}/{1}",
PlasticLocalization.Name.PrefixUnityVersionControlMenu.GetString(),
actions.HiddenChangesTitle);
if (!actions.Operations.HasFlag(FilterMenuOperations.HideChanged))
{
HandleMenuItem.AddMenuItem(
mHiddenChangesSubmenuItem,
mHiddenChangesMenuItemsPriority,
DisabledMenuItem_Click, ValidateDisabledMenuItem);
return;
}
mHiddenChangesByNameMenuItem = GetHiddenChangesMenuItemName(actions.FilterByName);
mHiddenChangesByExtensionMenuItem = GetHiddenChangesMenuItemName(actions.FilterByExtension);
mHiddenChangesByFullPathMenuItem = GetHiddenChangesMenuItemName(actions.FilterByFullPath);
HandleMenuItem.AddMenuItem(
mHiddenChangesByNameMenuItem,
mIgnoredMenuItemsPriority,
HiddenChangesByName_Click, ValidateEnabledMenuItem);
if (actions.Operations.HasFlag(FilterMenuOperations.HideChangedByExtension))
HandleMenuItem.AddMenuItem(
mHiddenChangesByExtensionMenuItem,
mIgnoredMenuItemsPriority,
HiddenChangesByExtension_Click, ValidateEnabledMenuItem);
HandleMenuItem.AddMenuItem(
mHiddenChangesByFullPathMenuItem,
mIgnoredMenuItemsPriority,
HiddenChangesByFullPath_Click, ValidateEnabledMenuItem);
}
void RemoveIgnoredMenuItems()
{
HandleMenuItem.RemoveMenuItem(mIgnoredSubmenuItem);
HandleMenuItem.RemoveMenuItem(mIgnoredByNameMenuItem);
HandleMenuItem.RemoveMenuItem(mIgnoredByExtensionMenuItem);
HandleMenuItem.RemoveMenuItem(mIgnoredByFullPathMenuItem);
}
void RemoveHiddenChangesMenuItems()
{
HandleMenuItem.RemoveMenuItem(mHiddenChangesSubmenuItem);
HandleMenuItem.RemoveMenuItem(mHiddenChangesByNameMenuItem);
HandleMenuItem.RemoveMenuItem(mHiddenChangesByExtensionMenuItem);
HandleMenuItem.RemoveMenuItem(mHiddenChangesByFullPathMenuItem);
}
FilterOperationType GetIgnoredFilterOperationType()
{
return GetFilterOperationType(
mIgnoredByNameMenuItem,
PlasticLocalization.Name.MenuAddToIgnoreList);
}
FilterOperationType GetHiddenChangesFilterOperationType()
{
return GetFilterOperationType(
mHiddenChangesByNameMenuItem,
PlasticLocalization.Name.MenuAddToHiddenChangesList);
}
static FilterOperationType GetFilterOperationType(string menuItemName, PlasticLocalization.Name expectedTitle)
{
string[] split = menuItemName.Split('/');
if (split.Length < 2)
return FilterOperationType.Remove;
string parentMenu = split[split.Length - 2];
return parentMenu.StartsWith(expectedTitle.GetString())
? FilterOperationType.Add
: FilterOperationType.Remove;
}
void DisabledMenuItem_Click() { }
bool ValidateEnabledMenuItem() { return true; }
bool ValidateDisabledMenuItem() { return false; }
string GetIgnoredMenuItemName(string filterPattern)
{
return UnityMenuItem.GetText(
mIgnoredSubmenuItem,
UnityMenuItem.EscapedText(filterPattern));
}
string GetHiddenChangesMenuItemName(string filterPattern)
{
return UnityMenuItem.GetText(
mHiddenChangesSubmenuItem,
UnityMenuItem.EscapedText(filterPattern));
}
IAssetFilesFilterPatternsMenuOperations mOperations;
string mIgnoredSubmenuItem;
string mHiddenChangesSubmenuItem;
string mIgnoredByNameMenuItem;
string mHiddenChangesByNameMenuItem;
string mIgnoredByExtensionMenuItem;
string mHiddenChangesByExtensionMenuItem;
string mIgnoredByFullPathMenuItem;
string mHiddenChangesByFullPathMenuItem;
readonly int mIgnoredMenuItemsPriority;
readonly int mHiddenChangesMenuItemsPriority;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4eb3fe08d1dc86419dee5ddcc40baae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,301 @@
using System;
using UnityEditor.VersionControl;
using Codice;
using Codice.Client.Commands.Tree;
using Codice.Client.Commands.WkTree;
using Codice.CM.Common;
using PlasticGui;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetsOverlays;
using Unity.PlasticSCM.Editor.AssetUtils;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
[Flags]
internal enum AssetMenuOperations : byte
{
None = 0,
Checkout = 1 << 0,
Diff = 1 << 1,
History = 1 << 2,
Add = 1 << 3,
Checkin = 1 << 4,
Undo = 1 << 5,
CopyFilePath = 1 << 6
}
internal class SelectedAssetGroupInfo
{
internal int SelectedCount;
internal bool IsControlledSelection;
internal bool IsCheckedInSelection;
internal bool IsCheckedOutSelection;
internal bool IsChangedSelection;
internal bool IsPrivateSelection;
internal bool IsAddedSelection;
internal bool IsFileSelection;
internal bool IsMovedSelection;
internal bool HasAnyAddedInSelection;
internal bool HasAnyRemoteLockedInSelection;
internal static SelectedAssetGroupInfo BuildFromAssetList(
WorkspaceInfo wkInfo,
AssetList assetList,
IPlasticAPI plasticApi,
IAssetStatusCache statusCache)
{
bool isCheckedInSelection = true;
bool isControlledSelection = true;
bool isCheckedOutSelection = true;
bool isChangedSelection = true;
bool isPrivateSelection = true;
bool isAddedSelection = true;
bool isFileSelection = true;
bool isMovedSelection = true;
bool hasAnyAddedInSelection = false;
bool hasAnyRemoteLockedInSelection = false;
int selectedCount = 0;
foreach (Asset asset in assetList)
{
string fullPath = AssetsPath.GetFullPathUnderWorkspace.
ForAsset(wkInfo.ClientPath, asset.path);
if (fullPath == null)
continue;
SelectedAssetGroupInfo singleFileGroupInfo = BuildFromSingleFile(
fullPath, asset.isFolder, wkInfo, plasticApi, statusCache);
if (!singleFileGroupInfo.IsCheckedInSelection)
isCheckedInSelection = false;
if (!singleFileGroupInfo.IsControlledSelection)
isControlledSelection = false;
if (!singleFileGroupInfo.IsCheckedOutSelection)
isCheckedOutSelection = false;
if (!singleFileGroupInfo.IsChangedSelection)
isChangedSelection = false;
if (!singleFileGroupInfo.IsPrivateSelection)
isPrivateSelection = false;
if (!singleFileGroupInfo.IsAddedSelection)
isAddedSelection = false;
if (!singleFileGroupInfo.IsFileSelection)
isFileSelection = false;
if (!singleFileGroupInfo.IsMovedSelection)
isMovedSelection = false;
if (singleFileGroupInfo.HasAnyAddedInSelection)
hasAnyAddedInSelection = true;
if (singleFileGroupInfo.HasAnyRemoteLockedInSelection)
hasAnyRemoteLockedInSelection = true;
selectedCount++;
}
return new SelectedAssetGroupInfo()
{
IsCheckedInSelection = isCheckedInSelection,
IsCheckedOutSelection = isCheckedOutSelection,
IsChangedSelection = isChangedSelection,
IsControlledSelection = isControlledSelection,
IsPrivateSelection = isPrivateSelection,
IsAddedSelection = isAddedSelection,
IsFileSelection = isFileSelection,
IsMovedSelection = isMovedSelection,
HasAnyAddedInSelection = hasAnyAddedInSelection,
HasAnyRemoteLockedInSelection = hasAnyRemoteLockedInSelection,
SelectedCount = selectedCount,
};
}
internal static SelectedAssetGroupInfo BuildFromSingleFile(
string fullPath,
bool isDirectory,
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
IAssetStatusCache statusCache)
{
bool isCheckedInSelection = true;
bool isControlledSelection = true;
bool isCheckedOutSelection = true;
bool isChangedSelection = false;
bool isPrivateSelection = true;
bool isAddedSelection = true;
bool isFileSelection = true;
bool isMovedSelection = false;
bool hasAnyAddedInSelection = false;
bool hasAnyRemoteLockedInSelection = false;
WorkspaceTreeNode wkTreeNode = plasticApi.
GetWorkspaceTreeNode(wkInfo, fullPath);
if (isDirectory)
isFileSelection = false;
if (CheckWorkspaceTreeNodeStatus.IsPrivate(wkTreeNode))
isControlledSelection = false;
else
isPrivateSelection = false;
if (CheckWorkspaceTreeNodeStatus.IsCheckedOut(wkTreeNode))
isCheckedInSelection = false;
else
isCheckedOutSelection = false;
if (CheckWorkspaceTreeNodeStatus.IsAdded(wkTreeNode))
hasAnyAddedInSelection = true;
else
isAddedSelection = false;
if (wkTreeNode != null)
{
TreeChangedNode treeChangedNode = plasticApi.
GetChangedNodeForPath(wkInfo, fullPath);
if (treeChangedNode != null)
isMovedSelection = treeChangedNode.MovedDst;
}
AssetStatus assetStatus = statusCache.GetStatus(fullPath);
if (ClassifyAssetStatus.IsLockedRemote(assetStatus))
hasAnyRemoteLockedInSelection = true;
if (ClassifyAssetStatus.IsChanged(assetStatus))
isChangedSelection = true;
return new SelectedAssetGroupInfo()
{
IsCheckedInSelection = isCheckedInSelection,
IsCheckedOutSelection = isCheckedOutSelection,
IsChangedSelection = isChangedSelection,
IsControlledSelection = isControlledSelection,
IsPrivateSelection = isPrivateSelection,
IsAddedSelection = isAddedSelection,
IsFileSelection = isFileSelection,
IsMovedSelection = isMovedSelection,
HasAnyAddedInSelection = hasAnyAddedInSelection,
HasAnyRemoteLockedInSelection = hasAnyRemoteLockedInSelection,
SelectedCount = 1,
};
}
}
internal interface IAssetMenuUVCSOperations
{
void ShowPendingChanges();
void Add();
void Checkout();
void Checkin();
void Undo();
void ShowDiff();
void ShowHistory();
}
internal interface IAssetMenuCopyPathOperation
{
void CopyFilePath(bool relativePath);
}
internal static class AssetMenuUpdater
{
internal static AssetMenuOperations GetAvailableMenuOperations(
SelectedAssetGroupInfo info)
{
AssetMenuOperations result = AssetMenuOperations.None;
if (info.SelectedCount == 0)
{
return result;
}
result |= AssetMenuOperations.CopyFilePath;
if (info.IsControlledSelection &&
info.IsCheckedInSelection &&
info.IsFileSelection &&
!info.HasAnyRemoteLockedInSelection)
{
result |= AssetMenuOperations.Checkout;
}
if (info.IsFileSelection &&
info.IsPrivateSelection)
{
result |= AssetMenuOperations.Add;
}
if (info.IsFileSelection &&
(info.IsPrivateSelection ||
(info.IsControlledSelection &&
(info.IsCheckedOutSelection ||
info.IsChangedSelection))))
{
result |= AssetMenuOperations.Checkin;
}
if ((info.IsControlledSelection &&
info.IsMovedSelection) ||
(info.IsFileSelection &&
info.IsControlledSelection &&
(info.IsCheckedOutSelection ||
info.IsChangedSelection)))
{
result |= AssetMenuOperations.Undo;
}
if (info.SelectedCount == 1 &&
info.IsControlledSelection &&
!info.HasAnyAddedInSelection &&
info.IsFileSelection)
{
result |= AssetMenuOperations.Diff;
}
if (info.SelectedCount == 1 &&
info.IsControlledSelection &&
!info.HasAnyAddedInSelection)
{
result |= AssetMenuOperations.History;
}
return result;
}
internal static bool ShouldMenuOperationBeEnabled(
WorkspaceInfo wkInfo,
IPlasticAPI plasticAPI,
AssetUVCSOperations.IAssetSelection assetSelection,
IAssetStatusCache statusCache,
AssetMenuOperations operation)
{
AssetList assetList = assetSelection.GetSelectedAssets();
if (assetList.Count == 0)
return false;
SelectedAssetGroupInfo selectedGroupInfo = SelectedAssetGroupInfo.
BuildFromAssetList(wkInfo, assetList, plasticAPI, statusCache);
if (assetList.Count != selectedGroupInfo.SelectedCount)
return false;
AssetMenuOperations operations = AssetMenuUpdater.
GetAvailableMenuOperations(selectedGroupInfo);
return operations.HasFlag(operation);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c456fa791a741a045a8a99ee73af2ae6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,352 @@
using System.IO;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.VersionControl;
using Codice.Client.BaseCommands;
using Codice.Client.Commands;
using Codice.Client.Commands.WkTree;
using Codice.Client.Common;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using GluonGui;
using PlasticGui;
using PlasticGui.Gluon;
using PlasticGui.WorkspaceWindow;
using PlasticGui.WorkspaceWindow.Diff;
using PlasticGui.WorkspaceWindow.Items;
using Unity.PlasticSCM.Editor.AssetMenu.Dialogs;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.AssetUtils.Processor;
using Unity.PlasticSCM.Editor.Tool;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.Views.PendingChanges.Dialogs;
using GluonIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.IncomingChangesUpdater;
using GluonCheckoutOperation = GluonGui.WorkspaceWindow.Views.WorkspaceExplorer.Explorer.Operations.CheckoutOperation;
using GluonUndoCheckoutOperation = GluonGui.WorkspaceWindow.Views.WorkspaceExplorer.Explorer.Operations.UndoCheckoutOperation;
using GluonAddoperation = GluonGui.WorkspaceWindow.Views.WorkspaceExplorer.Explorer.Operations.AddOperation;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal class AssetUVCSOperations :
IAssetMenuUVCSOperations,
IAssetFilesFilterPatternsMenuOperations
{
internal interface IAssetSelection
{
AssetList GetSelectedAssets();
}
internal AssetUVCSOperations(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
ViewHost viewHost,
IWorkspaceWindow workspaceWindow,
IViewSwitcher viewSwitcher,
IGluonViewSwitcher gluonViewSwitcher,
IMergeViewLauncher mergeViewLauncher,
IHistoryViewLauncher historyViewLauncher,
IAssetStatusCache assetStatusCache,
IAssetSelection assetSelection,
ISaveAssets saveAssets,
LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
WorkspaceOperationsMonitor workspaceOperationsMonitor,
PendingChangesUpdater pendingChangesUpdater,
IncomingChangesUpdater developerIncomingChangesUpdater,
GluonIncomingChangesUpdater gluonIncomingChangesUpdater,
ShelvedChangesUpdater shelvedChangesUpdater,
bool isGluonMode)
{
mWkInfo = wkInfo;
mPlasticAPI = plasticApi;
mViewHost = viewHost;
mWorkspaceWindow = workspaceWindow;
mViewSwitcher = viewSwitcher;
mGluonViewSwitcher = gluonViewSwitcher;
mMergeViewLauncher = mergeViewLauncher;
mHistoryViewLauncher = historyViewLauncher;
mAssetStatusCache = assetStatusCache;
mAssetSelection = assetSelection;
mSaveAssets = saveAssets;
mShowDownloadPlasticExeWindow = showDownloadPlasticExeWindow;
mWorkspaceOperationsMonitor = workspaceOperationsMonitor;
mPendingChangesUpdater = pendingChangesUpdater;
mDeveloperIncomingChangesUpdater = developerIncomingChangesUpdater;
mGluonIncomingChangesUpdater = gluonIncomingChangesUpdater;
mShelvedChangesUpdater = shelvedChangesUpdater;
mIsGluonMode = isGluonMode;
mGuiMessage = new UnityPlasticGuiMessage();
mProgressControls = new EditorProgressControls(
mGuiMessage, UnityConstants.UVCS_WINDOW_TITLE);
}
void IAssetMenuUVCSOperations.ShowPendingChanges()
{
mViewSwitcher.ShowPendingChanges();
}
void IAssetMenuUVCSOperations.Add()
{
List<string> selectedPaths = GetSelectedPaths.ForOperation(
mWkInfo,
mAssetSelection.GetSelectedAssets(),
mPlasticAPI,
mAssetStatusCache,
AssetMenuOperations.Add);
if (mIsGluonMode)
{
GluonAddoperation.Add(
mWkInfo,
mViewHost,
mProgressControls,
mGuiMessage,
selectedPaths.ToArray(),
false,
mPendingChangesUpdater,
mGluonIncomingChangesUpdater,
() => RefreshAsset.VersionControlCache(mAssetStatusCache));
return;
}
AddOperation.Run(
mWkInfo,
mWorkspaceWindow,
mProgressControls,
null,
null,
selectedPaths,
false,
mPendingChangesUpdater,
mDeveloperIncomingChangesUpdater,
mShelvedChangesUpdater,
() => RefreshAsset.VersionControlCache(mAssetStatusCache));
}
void IAssetMenuUVCSOperations.Checkout()
{
List<string> selectedPaths = GetSelectedPaths.ForOperation(
mWkInfo,
mAssetSelection.GetSelectedAssets(),
mPlasticAPI,
mAssetStatusCache,
AssetMenuOperations.Checkout);
if (mIsGluonMode)
{
GluonCheckoutOperation.Checkout(
mViewHost,
mProgressControls,
mGuiMessage,
selectedPaths.ToArray(),
false,
mPendingChangesUpdater,
mGluonIncomingChangesUpdater,
() => RefreshAsset.VersionControlCache(mAssetStatusCache),
mWkInfo);
return;
}
CheckoutOperation.Checkout(
mWorkspaceWindow,
null,
mProgressControls,
selectedPaths,
mPendingChangesUpdater,
mDeveloperIncomingChangesUpdater,
mShelvedChangesUpdater,
() => RefreshAsset.VersionControlCache(mAssetStatusCache),
mWkInfo);
}
void IAssetMenuUVCSOperations.Checkin()
{
List<string> selectedPaths = GetSelectedPaths.ForOperation(
mWkInfo,
mAssetSelection.GetSelectedAssets(),
mPlasticAPI,
mAssetStatusCache,
AssetMenuOperations.Checkin);
if (!CheckinDialog.CheckinPaths(
mWkInfo,
selectedPaths,
mAssetStatusCache,
mIsGluonMode,
mWorkspaceWindow,
mViewHost,
mWorkspaceOperationsMonitor,
mPendingChangesUpdater,
mSaveAssets,
mGuiMessage,
mMergeViewLauncher,
mGluonViewSwitcher))
return;
RefreshAsset.UnityAssetDatabase(mAssetStatusCache);
}
void IAssetMenuUVCSOperations.Undo()
{
List<string> selectedPaths = GetSelectedPaths.ForOperation(
mWkInfo,
mAssetSelection.GetSelectedAssets(),
mPlasticAPI,
mAssetStatusCache,
AssetMenuOperations.Undo);
mSaveAssets.ForPathsWithoutConfirmation(
mWkInfo.ClientPath, selectedPaths, mWorkspaceOperationsMonitor);
if (mIsGluonMode)
{
GluonUndoCheckoutOperation.UndoCheckout(
mWkInfo,
mViewHost,
mProgressControls,
selectedPaths.ToArray(),
false,
mPendingChangesUpdater,
mGluonIncomingChangesUpdater,
() => RefreshAsset.UnityAssetDatabase(mAssetStatusCache));
return;
}
UndoCheckoutOperation.Run(
mWorkspaceWindow,
null,
mProgressControls,
selectedPaths,
mPendingChangesUpdater,
mDeveloperIncomingChangesUpdater,
mShelvedChangesUpdater,
() => RefreshAsset.UnityAssetDatabase(mAssetStatusCache));
}
void IAssetMenuUVCSOperations.ShowDiff()
{
string selectedPath = AssetsSelection.GetSelectedPath(
mWkInfo.ClientPath,
mAssetSelection.GetSelectedAssets());
DiffInfo diffInfo = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
string symbolicName = GetSymbolicName(mWkInfo, selectedPath);
string extension = Path.GetExtension(selectedPath);
diffInfo = PlasticGui.Plastic.API.BuildDiffInfoForDiffWithPrevious(
selectedPath, symbolicName, selectedPath, extension, mWkInfo);
},
/*afterOperationDelegate*/ delegate
{
if (waiter.Exception != null)
{
ExceptionsHandler.DisplayException(waiter.Exception);
return;
}
DiffOperation.DiffWithPrevious(
diffInfo,
PlasticExeLauncher.BuildForShowDiff(mWkInfo, mIsGluonMode, mShowDownloadPlasticExeWindow),
null);
});
}
void IAssetMenuUVCSOperations.ShowHistory()
{
Asset selectedAsset = AssetsSelection.GetSelectedAsset(
mWkInfo.ClientPath,
mAssetSelection.GetSelectedAssets());
string selectedPath = AssetsPath.GetFullPath.ForPath(selectedAsset.path);
WorkspaceTreeNode node = PlasticGui.Plastic.API.
GetWorkspaceTreeNode(mWkInfo, selectedPath);
mHistoryViewLauncher.ShowHistoryView(
node.RepSpec,
node.RevInfo.ItemId,
selectedPath,
selectedAsset.isFolder);
}
void IAssetFilesFilterPatternsMenuOperations.AddFilesFilterPatterns(
FilterTypes type,
FilterActions action,
FilterOperationType operation)
{
List<string> selectedPaths = AssetsSelection.GetSelectedPaths(
mWkInfo.ClientPath,
mAssetSelection.GetSelectedAssets());
string[] rules = FilterRulesGenerator.GenerateRules(
selectedPaths, mWkInfo.ClientPath, action, operation);
bool isApplicableToAllWorkspaces = !mIsGluonMode;
bool isAddOperation = operation == FilterOperationType.Add;
FilterRulesConfirmationData filterRulesConfirmationData =
FilterRulesConfirmationDialog.AskForConfirmation(
rules, isAddOperation, isApplicableToAllWorkspaces, EditorWindow.focusedWindow);
AddFilesFilterPatternsOperation.Run(
mWkInfo,
mWorkspaceWindow,
type,
operation,
filterRulesConfirmationData,
mPendingChangesUpdater);
}
static string GetSymbolicName(WorkspaceInfo wkInfo, string selectedPath)
{
WorkspaceTreeNode node = PlasticGui.Plastic.API.
GetWorkspaceTreeNode(wkInfo, selectedPath);
string branchName = string.Empty;
BranchInfoCache.TryGetBranchName(
node.RepSpec, node.RevInfo.BranchId, out branchName);
string userName = PlasticGui.Plastic.API.GetUserName(
node.RepSpec.Server, node.RevInfo.Owner);
string symbolicName = string.Format(
"cs:{0}@{1} {2} {3}",
node.RevInfo.Changeset,
string.Format("br:{0}", branchName),
userName,
"Workspace Revision");
return symbolicName;
}
readonly WorkspaceInfo mWkInfo;
readonly IPlasticAPI mPlasticAPI;
readonly ViewHost mViewHost;
readonly IWorkspaceWindow mWorkspaceWindow;
readonly IViewSwitcher mViewSwitcher;
readonly IGluonViewSwitcher mGluonViewSwitcher;
readonly IMergeViewLauncher mMergeViewLauncher;
readonly IHistoryViewLauncher mHistoryViewLauncher;
readonly IAssetStatusCache mAssetStatusCache;
readonly IAssetSelection mAssetSelection;
readonly ISaveAssets mSaveAssets;
readonly LaunchTool.IShowDownloadPlasticExeWindow mShowDownloadPlasticExeWindow;
readonly WorkspaceOperationsMonitor mWorkspaceOperationsMonitor;
readonly PendingChangesUpdater mPendingChangesUpdater;
readonly IncomingChangesUpdater mDeveloperIncomingChangesUpdater;
readonly GluonIncomingChangesUpdater mGluonIncomingChangesUpdater;
readonly ShelvedChangesUpdater mShelvedChangesUpdater;
readonly bool mIsGluonMode;
readonly GuiMessage.IGuiMessage mGuiMessage;
readonly EditorProgressControls mProgressControls;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c8b452bcd72d8248a3297ff656f0a7a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,141 @@
using System.Collections.Generic;
using System.IO;
using UnityEditor.VersionControl;
using PlasticGui.WorkspaceWindow.Items;
using Unity.PlasticSCM.Editor.AssetsOverlays;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetUtils;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal static class AssetsSelection
{
internal static Asset GetSelectedAsset(
string wkPath,
AssetList assetList)
{
if (assetList.Count == 0)
return null;
foreach (Asset asset in assetList)
{
if (AssetsPath.GetFullPathUnderWorkspace.
ForAsset(wkPath, asset.path) == null)
continue;
return asset;
}
return null;
}
internal static string GetSelectedPath(
string wkPath,
AssetList assetList)
{
Asset result = GetSelectedAsset(wkPath, assetList);
if (result == null)
return null;
return AssetsPath.GetFullPath.ForPath(result.path);
}
internal static List<string> GetSelectedPaths(
string wkPath,
IEnumerable<Asset> assetList)
{
List<string> result = new List<string>();
foreach (Asset asset in assetList)
{
string fullPath = AssetsPath.GetFullPathUnderWorkspace.
ForAsset(wkPath, asset.path);
if (fullPath == null)
continue;
result.Add(fullPath);
}
return result;
}
internal static SelectedPathsGroupInfo GetSelectedPathsGroupInfo(
string wkPath,
AssetList assetList,
IAssetStatusCache statusCache)
{
SelectedPathsGroupInfo result = new SelectedPathsGroupInfo();
if (assetList.Count == 0)
return result;
result.IsRootSelected = false;
result.IsCheckedoutEverySelected = true;
result.IsDirectoryEverySelected = true;
result.IsCheckedinEverySelected = true;
result.IsChangedEverySelected = true;
foreach (Asset asset in assetList)
{
string fullPath = AssetsPath.GetFullPathUnderWorkspace.
ForAsset(wkPath, asset.path);
if (fullPath == null)
continue;
if (MetaPath.IsMetaPath(fullPath))
fullPath = MetaPath.GetPathFromMetaPath(fullPath);
AssetStatus status = statusCache.GetStatus(fullPath);
string assetName = GetAssetName(asset);
result.IsCheckedoutEverySelected &= ClassifyAssetStatus.IsCheckedOut(status);
result.IsDirectoryEverySelected &= asset.isFolder;
result.IsCheckedinEverySelected &= false; // TODO: not implemented yet
result.IsChangedEverySelected &= false; // TODO: not implemented yet
result.IsAnyDirectorySelected |= asset.isFolder;
result.IsAnyPrivateSelected |= ClassifyAssetStatus.IsPrivate(status) || ClassifyAssetStatus.IsIgnored(status);
result.FilterInfo.IsAnyIgnoredSelected |= ClassifyAssetStatus.IsIgnored(status);
result.FilterInfo.IsAnyHiddenChangedSelected |= ClassifyAssetStatus.IsHiddenChanged(status);
result.SelectedCount++;
if (result.SelectedCount == 1)
{
result.FirstIsControlled = ClassifyAssetStatus.IsControlled(status);
result.FirstIsDirectory = asset.isFolder;
result.FilterInfo.CommonName = assetName;
result.FilterInfo.CommonExtension = Path.GetExtension(assetName);
result.FilterInfo.CommonFullPath = asset.assetPath;
continue;
}
if (result.FilterInfo.CommonName != assetName)
result.FilterInfo.CommonName = null;
if (result.FilterInfo.CommonExtension != Path.GetExtension(assetName))
result.FilterInfo.CommonExtension = null;
if (result.FilterInfo.CommonFullPath != asset.assetPath)
result.FilterInfo.CommonFullPath = null;
}
return result;
}
static string GetAssetName(Asset asset)
{
if (asset.isFolder)
return Path.GetFileName(Path.GetDirectoryName(asset.path));
return asset.fullName;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1686ac2e1d109ed43bf2dec74fed784f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f5d6c6c129fff0140a040d43aedb9547
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,381 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Codice.Client.Common.WebApi;
using Codice.CM.Common;
using PlasticGui;
using PlasticGui.CloudDrive.Workspaces;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.CloudDrive;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.AssetMenu.Dialogs
{
internal class AddToCloudDriveDialog :
PlasticDialog,
FillOrganizationsAndProjects.INotify,
FillCloudWorkspaces.IAddToCloudDriveDialog
{
protected override Rect DefaultRect
{
get
{
var baseRect = base.DefaultRect;
return new Rect(baseRect.x, baseRect.y, 600, 350);
}
}
internal static void ShowDialog(
string[] assetPaths,
IPlasticWebRestApi restApi,
IPlasticAPI plasticApi,
EditorWindow parentWindow)
{
AddToCloudDriveDialog dialog = Create(assetPaths, plasticApi);
dialog.InitializeProposedOrganizationProject(restApi);
FillOrganizationsAndProjects.LoadOrganizations(
restApi,
plasticApi,
dialog.mProgressControls,
dialog);
ResponseType dialogResult = dialog.RunModal(parentWindow);
if (dialogResult != ResponseType.Ok)
return;
CloudDriveWindow cloudDriveWindow = ShowWindow.CloudDrive();
cloudDriveWindow.CopyPaths(
dialog.mSelectedOrganization,
dialog.mSelectedProject,
dialog.mSelectedCloudDrive.WorkspaceInfo,
assetPaths,
dialog.mCloudDriveRelativePath);
}
protected override string GetTitle()
{
return PlasticLocalization.Name.AddToUnityCloudDriveTitle.GetString();
}
protected override string GetExplanation()
{
return PlasticLocalization.Name.AddToCloudDriveDescription.GetString();
}
protected override void DoComponentsArea()
{
bool isOperationRunning = mProgressControls.ProgressData.IsWaitingAsyncResult;
GUI.enabled = !isOperationRunning;
EntryBuilder.CreateComboBoxEntry(
PlasticLocalization.Name.OrganizationLabel.GetString(),
mSelectedOrganization,
mOrganizations,
OnOrganizationSelected,
ENTRY_WIDTH,
ENTRY_X);
GUILayout.Space(5);
if (CloudServer.IsUnityOrganization(mSelectedOrganization))
{
EntryBuilder.CreateComboBoxEntry(
PlasticLocalization.Name.ProjectLabel.GetString(),
mSelectedProject,
mProjects,
OnProjectSelected,
ENTRY_WIDTH,
ENTRY_X);
GUILayout.Space(5);
}
string selectedDriveName = mSelectedCloudDrive != null ?
mSelectedCloudDrive.RepositoryInfo.Name.GetLastPartFromSeparator('/') : string.Empty;
List<string> driveNames = mCloudDrives.Select(
workspace => workspace.RepositoryInfo.Name.GetLastPartFromSeparator('/')).ToList();
EntryBuilder.CreateComboBoxEntry(
PlasticLocalization.Name.CloudDriveLabel.GetString(),
selectedDriveName,
driveNames,
OnDriveSelected,
ENTRY_WIDTH,
ENTRY_X);
GUILayout.Space(10);
using (new EditorGUILayout.HorizontalScope())
{
mCloudDriveRelativePath = EntryBuilder.CreateTextEntry(
PlasticLocalization.Name.RelativePathLabel.GetString(),
mCloudDriveRelativePath,
ENTRY_WIDTH - BROWSE_BUTTON_WIDTH,
ENTRY_X);
Rect browseButtonRect = new Rect(
ENTRY_X + ENTRY_WIDTH - BROWSE_BUTTON_WIDTH + BUTTON_MARGIN,
GUILayoutUtility.GetLastRect().y,
BROWSE_BUTTON_WIDTH - BUTTON_MARGIN,
20);
if (GUI.Button(browseButtonRect, "..."))
DoBrowseForPath();
}
GUI.enabled = true;
}
void FillOrganizationsAndProjects.INotify.OrganizationsRetrieved(List<string> organizations)
{
mOrganizations = organizations;
mSelectedOrganization = GetDefaultValue(mProposedOrganization, mOrganizations);
if (mSelectedOrganization == null)
return;
OnOrganizationSelected(mSelectedOrganization);
Repaint();
}
void FillOrganizationsAndProjects.INotify.ProjectsRetrieved(List<string> projects)
{
mProjects = projects;
mSelectedProject = GetDefaultValue(mProposedProject, mProjects);
if (mSelectedProject == null)
return;
OnProjectSelected(mSelectedProject);
Repaint();
}
void FillCloudWorkspaces.IAddToCloudDriveDialog.CloudDrivesRetrieved(
List<CloudDriveWorkspace> workspaces)
{
mCloudDrives = workspaces;
if (mCloudDrives.Count > 0)
mSelectedCloudDrive = mCloudDrives[0];
Repaint();
}
static AddToCloudDriveDialog Create(string[] assetPaths, IPlasticAPI plasticApi)
{
var instance = CreateInstance<AddToCloudDriveDialog>();
instance.IsResizable = false;
instance.mPlasticApi = plasticApi;
instance.mCloudDriveRelativePath = GetProposedCloudDriveRelativePath(assetPaths);
instance.mEnterKeyAction = instance.OkButtonAction;
instance.mEscapeKeyAction = instance.CancelButtonAction;
return instance;
}
void OnOrganizationSelected(object organization)
{
mSelectedOrganization = organization != null ? organization.ToString() : null;
mProposedOrganization = mSelectedOrganization;
mSelectedProject = null;
mSelectedCloudDrive = null;
mProjects.Clear();
mCloudDrives.Clear();
if (!CloudServer.IsUnityOrganization(mSelectedOrganization))
{
OnProjectSelected(string.Empty);
return;
}
FillOrganizationsAndProjects.LoadProjects(
mSelectedOrganization, mPlasticApi, mProgressControls, this);
}
void OnProjectSelected(object project)
{
mSelectedProject = project != null ? project.ToString() : null;
mProposedProject = mSelectedProject;
mSelectedCloudDrive = null;
mCloudDrives.Clear();
if (string.IsNullOrEmpty(mSelectedOrganization))
return;
FillCloudWorkspaces.LoadWorkspaces(
mSelectedOrganization, mSelectedProject, this, mProgressControls);
}
void OnDriveSelected(object selectedDrive)
{
string driveName = selectedDrive != null ? selectedDrive.ToString() : null;
mSelectedCloudDrive = mCloudDrives.FirstOrDefault(
wkInfo =>
wkInfo.RepositoryInfo.Name.GetLastPartFromSeparator('/') == driveName);
Repaint();
}
void DoBrowseForPath()
{
if (mSelectedCloudDrive == null)
{
((IProgressControls)mProgressControls).ShowError(
PlasticLocalization.Name.SelectCloudDriveFirst.GetString());
return;
}
string workspacePath = AssetsPath.GetFullPath.ForPath(mSelectedCloudDrive.WorkspaceInfo.ClientPath);
string selectedPath = EditorUtility.SaveFolderPanel(
PlasticLocalization.Name.SelectDestinationPath.GetString(),
workspacePath,
"");
if (string.IsNullOrEmpty(selectedPath))
return;
string selectedFullPath = AssetsPath.GetFullPath.ForPath(selectedPath);
if (string.IsNullOrEmpty(selectedFullPath))
return;
if (!selectedFullPath.StartsWith(workspacePath))
{
((IProgressControls)mProgressControls).ShowError(
PlasticLocalization.Name.PathMustBeWithinWorkspace.GetString());
return;
}
((IProgressControls)mProgressControls).HideProgress();
if (selectedFullPath == workspacePath)
{
mCloudDriveRelativePath = "/";
return;
}
mCloudDriveRelativePath = selectedFullPath.Substring(workspacePath.Length).Replace('\\', '/');
}
protected override void DoOkButton()
{
bool isValid = mSelectedCloudDrive != null && mCloudDriveRelativePath.StartsWith("/");
if (!isValid || mProgressControls.ProgressData.IsWaitingAsyncResult)
GUI.enabled = false;
if (NormalButton(PlasticLocalization.Name.AddToCloudDriveButton.GetString()))
{
OkButtonAction();
}
GUI.enabled = true;
}
static string GetProposedCloudDriveRelativePath(string[] assetPaths)
{
if (assetPaths.Length == 0)
return string.Empty;
string commonRoot = Path.GetDirectoryName(
assetPaths[0].TrimEnd(
Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
for (int i = 1; i < assetPaths.Length; i++)
{
commonRoot = GetCommonRoot(
commonRoot,
Path.GetDirectoryName(
assetPaths[i].TrimEnd(
Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
}
return '/' + commonRoot.Replace('\\', '/');
}
static string GetCommonRoot(string path1, string path2)
{
string[] path1Parts = path1.Split(Path.DirectorySeparatorChar);
string[] path2Parts = path2.Split(Path.DirectorySeparatorChar);
int commonPartsCount = Mathf.Min(path1Parts.Length, path2Parts.Length);
for (int i = 0; i < commonPartsCount; i++)
{
if (path1Parts[i] != path2Parts[i])
{
commonPartsCount = i;
break;
}
}
return string.Join(
Path.DirectorySeparatorChar.ToString(),
path1Parts,
0,
commonPartsCount);
}
static string GetDefaultValue(string proposedValue, List<string> values)
{
if (values.Count == 0)
return null;
if (!string.IsNullOrEmpty(proposedValue) && values.Contains(proposedValue))
return proposedValue;
return values[0];
}
void InitializeProposedOrganizationProject(IPlasticWebRestApi restApi)
{
GetProposedOrganizationProject.Values proposedOrganizationProject =
GetProposedOrganizationProject.FromCloudProjectSettings();
mProposedOrganization = proposedOrganizationProject != null ?
proposedOrganizationProject.Organization :
GetDefaultServer.FromConfig(restApi);
mProposedProject = proposedOrganizationProject != null ?
proposedOrganizationProject.Project :
Application.productName;
}
List<string> mOrganizations = new List<string>();
List<string> mProjects = new List<string>();
List<CloudDriveWorkspace> mCloudDrives = new List<CloudDriveWorkspace>();
string mProposedOrganization;
string mProposedProject;
string mSelectedOrganization;
string mSelectedProject;
CloudDriveWorkspace mSelectedCloudDrive;
string mCloudDriveRelativePath;
IPlasticAPI mPlasticApi;
const float ENTRY_WIDTH = 400;
const float ENTRY_X = 120f;
const float BROWSE_BUTTON_WIDTH = 30;
const float BUTTON_MARGIN = 5;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c8d9f1a2b3e4f5a6b7c8d9e0f1a2b3c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,391 @@
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 PlasticGui.WorkspaceWindow;
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.Tree;
#if !UNITY_6000_0_OR_NEWER
using EditorGUI = Unity.PlasticSCM.Editor.UnityInternals.UnityEditor.EditorGUI;
#endif
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,
IPendingChangesUpdater pendingChangesUpdater,
ISaveAssets saveAssets,
GuiMessage.IGuiMessage guiMessage,
IMergeViewLauncher mergeViewLauncher,
IGluonViewSwitcher gluonViewSwitcher)
{
MetaCache metaCache = new MetaCache();
metaCache.Build(paths);
CheckinDialog dialog = Create(
wkInfo,
paths,
assetStatusCache,
metaCache,
isGluonMode,
workspaceWindow,
viewHost,
workspaceOperationsMonitor,
pendingChangesUpdater,
saveAssets,
guiMessage,
mergeViewLauncher,
gluonViewSwitcher);
return dialog.RunModal(focusedWindow) == ResponseType.Ok;
}
protected override void DoComponentsArea()
{
Title(PlasticLocalization.GetString(PlasticLocalization.Name.CheckinOnlyComment));
Rect commentRect = GUILayoutUtility.GetRect(
new GUIContent(string.Empty),
EditorStyles.textArea,
GUILayout.MinHeight(120),
GUILayout.ExpandWidth(true));
GUI.SetNextControlName(CHECKIN_TEXTAREA_NAME);
mComment = EditorGUI.ScrollableTextAreaInternal(
commentRect,
mComment,
ref mScrollPosition,
EditorStyles.textArea);
if (!mTextAreaFocused)
{
UnityEditor.EditorGUI.FocusTextInControl(CHECKIN_TEXTAREA_NAME);
mTextAreaFocused = true;
}
Title(PlasticLocalization.GetString(PlasticLocalization.Name.Files));
DoFileList(
mWkInfo,
mPaths,
mAssetStatusCache,
mMetaCache);
}
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.GetFolderIcon() :
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(
true,
UnityConstants.TREEVIEW_ROW_HEIGHT);
DoListViewItem(selectionRect, fileIcon, label, assetStatus);
}
GUILayout.EndScrollView();
}
void DoListViewItem(
Rect itemRect,
Texture fileIcon,
string label,
AssetsOverlays.AssetStatus statusToDraw)
{
int iconPadding = 2;
Texture overlayIcon = DrawAssetOverlayIcon.GetOverlayIcon(statusToDraw);
itemRect = DrawTreeViewItem.DrawIconLeft(
itemRect,
itemRect.height - 2 * iconPadding,
fileIcon,
null,
overlayIcon);
GUI.Label(itemRect, label);
}
internal override void OkButtonAction()
{
if (!IsCheckinButtonEnabled())
return;
bool isCancelled;
mSaveAssets.ForPathsWithConfirmation(
mWkInfo.ClientPath, 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,
mPendingChangesUpdater);
return;
}
CheckinDialogOperations.CheckinPaths(
mWkInfo,
mPaths,
mComment,
mWorkspaceWindow,
this,
mGuiMessage,
mProgressControls,
mMergeViewLauncher,
mPendingChangesUpdater);
}
protected override void DoOkButton()
{
GUI.enabled = IsCheckinButtonEnabled();
try
{
if (!NormalButton(PlasticLocalization.GetString(
PlasticLocalization.Name.CheckinButton)))
return;
}
finally
{
if (!mSentCheckinTrackEvent)
{
TrackFeatureUseEvent.For(
PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
TrackFeatureUseEvent.Features.UnityPackage.ContextMenuCheckinDialogCheckin);
mSentCheckinTrackEvent = true;
}
GUI.enabled = true;
}
OkButtonAction();
}
internal override void CancelButtonAction()
{
if (!mSentCancelTrackEvent)
{
TrackFeatureUseEvent.For(
PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
TrackFeatureUseEvent.Features.UnityPackage.ContextMenuCheckinDialogCancel);
mSentCancelTrackEvent = true;
}
base.CancelButtonAction();
}
bool IsCheckinButtonEnabled()
{
return !string.IsNullOrEmpty(mComment) && !mIsRunningCheckin;
}
static CheckinDialog Create(
WorkspaceInfo wkInfo,
List<string> paths,
IAssetStatusCache assetStatusCache,
MetaCache metaCache,
bool isGluonMode,
IWorkspaceWindow workspaceWindow,
ViewHost viewHost,
WorkspaceOperationsMonitor workspaceOperationsMonitor,
IPendingChangesUpdater pendingChangesUpdater,
ISaveAssets saveAssets,
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.mWorkspaceWindow = workspaceWindow;
instance.mViewHost = viewHost;
instance.mWorkspaceOperationsMonitor = workspaceOperationsMonitor;
instance.mPendingChangesUpdater = pendingChangesUpdater;
instance.mSaveAssets = saveAssets;
instance.mGuiMessage = guiMessage;
instance.mMergeViewLauncher = mergeViewLauncher;
instance.mGluonViewSwitcher = gluonViewSwitcher;
instance.mEnterKeyAction = instance.OkButtonAction;
instance.AddControlConsumingEnterKey(CHECKIN_TEXTAREA_NAME);
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;
IWorkspaceWindow mWorkspaceWindow;
WorkspaceOperationsMonitor mWorkspaceOperationsMonitor;
IPendingChangesUpdater mPendingChangesUpdater;
ISaveAssets mSaveAssets;
ViewHost mViewHost;
IMergeViewLauncher mMergeViewLauncher;
IGluonViewSwitcher mGluonViewSwitcher;
GuiMessage.IGuiMessage mGuiMessage;
const string CHECKIN_TEXTAREA_NAME = "checkin_textarea";
Vector2 mScrollPosition;
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>();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 678db227e4ffec949980d309c0532b08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using Codice.Client.BaseCommands;
using Codice.Client.Commands;
using Codice.Client.Commands.CheckIn;
using Codice.Client.Common;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.CM.Common.Checkin.Partial;
using GluonGui;
using PlasticGui;
using PlasticGui.Gluon;
using PlasticGui.WorkspaceWindow;
using PlasticGui.WorkspaceWindow.PendingChanges;
namespace Unity.PlasticSCM.Editor.AssetMenu.Dialogs
{
internal static class CheckinDialogOperations
{
internal static void CheckinPaths(
WorkspaceInfo wkInfo,
List<string> paths,
string comment,
IWorkspaceWindow workspaceWindow,
CheckinDialog dialog,
GuiMessage.IGuiMessage guiMessage,
IProgressControls progressControls,
IMergeViewLauncher mergeViewLauncher,
IPendingChangesUpdater pendingChangesUpdater)
{
BaseCommandsImpl baseCommands = new BaseCommandsImpl();
progressControls.ShowProgress("Checkin in files");
IThreadWaiter waiter = ThreadWaiter.GetWaiter(50);
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
ApplyLocalChanges(wkInfo, paths);
CheckinParams ciParams = new CheckinParams();
ciParams.paths = paths.ToArray();
ciParams.comment = comment;
ciParams.time = DateTime.MinValue;
ciParams.flags = CheckinFlags.Recurse | CheckinFlags.ProcessSymlinks;
baseCommands.CheckIn(wkInfo, ciParams);
},
/*afterOperationDelegate*/ delegate
{
progressControls.HideProgress();
((IPlasticDialogCloser)dialog).CloseDialog();
if (waiter.Exception is CmClientMergeNeededException)
{
// we need to explicitly call EditorWindow.Close() to ensure
// that the dialog is closed before asking the user
dialog.Close();
if (!UserWantsToShowIncomingView(guiMessage))
return;
ShowIncomingChanges.FromCheckin(
wkInfo,
mergeViewLauncher,
progressControls);
return;
}
if (waiter.Exception != null)
{
ExceptionsHandler.DisplayException(waiter.Exception);
return;
}
if (pendingChangesUpdater != null)
pendingChangesUpdater.Update(DateTime.Now);
workspaceWindow.RefreshView(ViewType.HistoryView);
workspaceWindow.RefreshView(ViewType.BranchesView);
workspaceWindow.RefreshView(ViewType.ChangesetsView);
workspaceWindow.RefreshView(ViewType.LocksView);
});
}
internal static void CheckinPathsPartial(
WorkspaceInfo wkInfo,
List<string> paths,
string comment,
ViewHost viewHost,
CheckinDialog dialog,
GuiMessage.IGuiMessage guiMessage,
IProgressControls progressControls,
IGluonViewSwitcher gluonViewSwitcher,
IPendingChangesUpdater pendingChangesUpdater)
{
BaseCommandsImpl baseCommands = new BaseCommandsImpl();
progressControls.ShowProgress(PlasticLocalization.GetString(
PlasticLocalization.Name.CheckinInFilesProgress));
IThreadWaiter waiter = ThreadWaiter.GetWaiter(50);
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
ApplyLocalChanges(wkInfo, paths);
baseCommands.PartialCheckin(wkInfo, paths, comment);
},
/*afterOperationDelegate*/ delegate
{
progressControls.HideProgress();
((IPlasticDialogCloser)dialog).CloseDialog();
if (waiter.Exception is CheckinConflictsException)
{
// we need to explicitly call EditorWindow.Close() to ensure
// that the dialog is closed before asking the user
dialog.Close();
if (!UserWantsToShowIncomingView(guiMessage))
return;
gluonViewSwitcher.ShowIncomingChangesView();
return;
}
if (waiter.Exception != null)
{
ExceptionsHandler.DisplayException(waiter.Exception);
return;
}
if (pendingChangesUpdater != null)
pendingChangesUpdater.Update(DateTime.Now);
viewHost.RefreshView(ViewType.HistoryView);
viewHost.RefreshView(ViewType.LocksView);
});
}
static bool UserWantsToShowIncomingView(GuiMessage.IGuiMessage guiMessage)
{
GuiMessage.GuiMessageResponseButton result = guiMessage.ShowQuestion(
PlasticLocalization.GetString(PlasticLocalization.Name.CheckinConflictsTitle),
PlasticLocalization.GetString(PlasticLocalization.Name.UnityCheckinConflictsExplanation),
PlasticLocalization.GetString(PlasticLocalization.Name.CheckinShowIncomingChangesView),
PlasticLocalization.GetString(PlasticLocalization.Name.CancelButton),
null);
return result == GuiMessage.GuiMessageResponseButton.Positive;
}
static void ApplyLocalChanges(WorkspaceInfo wkInfo, List<string> paths)
{
ApplyLocalChangesOptions options = new ApplyLocalChangesOptions();
options.bIncludeDependencies = true;
options.MatchingOptions = new MovedMatchingOptions();
options.TypesToApply =
ChangeTypes.Changed |
ChangeTypes.Private |
ChangeTypes.LocallyDeleted |
ChangeTypes.LocallyMoved;
options.Operation = DependenciesOperation.Checkin;
options.bProcessSymlinks = true;
ApplyChanges.Apply(wkInfo, paths, options, null, out _, out _);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c44a2ac668da0a04d9e567739215b2eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,341 @@
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEditor.VersionControl;
using UnityEngine;
using UnityEngine.SceneManagement;
using Codice.Client.Common.EventTracking;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.AssetUtils.Processor;
using Unity.PlasticSCM.Editor.Tool;
using Unity.PlasticSCM.Editor.UI;
using GluonIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.IncomingChangesUpdater;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal static class HierarchyViewAssetMenu
{
internal static void Enable(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
IAssetStatusCache assetStatusCache)
{
if (mIsEnabled)
return;
mLog.Debug("Enable");
mWkInfo = wkInfo;
mPlasticAPI = plasticApi;
mAssetStatusCache = assetStatusCache;
mIsEnabled = true;
mAssetSelection = new HierarchyViewAssetSelection();
mAssetMenuCopyPathOperation = new AssetCopyPathOperation(
wkInfo, mPlasticAPI, assetStatusCache, mAssetSelection);
SceneHierarchyHooks.addItemsToSceneHeaderContextMenu += OnSceneHeaderContextMenu;
SceneHierarchyHooks.addItemsToSubSceneHeaderContextMenu += OnSubSceneHeaderContextMenu;
SceneHierarchyHooks.addItemsToGameObjectContextMenu += OnGameObjectContextMenu;
}
internal static void Disable()
{
mLog.Debug("Enable");
mIsEnabled = false;
mWkInfo = null;
mPlasticAPI = null;
mAssetStatusCache = null;
mAssetSelection = null;
mAssetMenuUVCSOperations = null;
mAssetMenuCopyPathOperation = null;
SceneHierarchyHooks.addItemsToSceneHeaderContextMenu -= OnSceneHeaderContextMenu;
SceneHierarchyHooks.addItemsToSubSceneHeaderContextMenu -= OnSubSceneHeaderContextMenu;
SceneHierarchyHooks.addItemsToGameObjectContextMenu -= OnGameObjectContextMenu;
}
internal static void BuildOperations(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
GluonGui.ViewHost viewHost,
WorkspaceWindow workspaceWindow,
IViewSwitcher viewSwitcher,
PlasticGui.Gluon.IGluonViewSwitcher gluonViewSwitcher,
IMergeViewLauncher mergeViewLauncher,
IHistoryViewLauncher historyViewLauncher,
IAssetStatusCache assetStatusCache,
ISaveAssets saveAssets,
LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
WorkspaceOperationsMonitor workspaceOperationsMonitor,
PendingChangesUpdater pendingChangesUpdater,
IncomingChangesUpdater developerIncomingChangesUpdater,
GluonIncomingChangesUpdater gluonIncomingChangesUpdater,
ShelvedChangesUpdater shelvedChangesUpdater,
bool isGluonMode)
{
if (!mIsEnabled)
Enable(wkInfo, plasticApi, assetStatusCache);
AssetUVCSOperations assetUVCSOperations = new AssetUVCSOperations(
wkInfo,
plasticApi,
viewHost,
workspaceWindow,
viewSwitcher,
gluonViewSwitcher,
mergeViewLauncher,
historyViewLauncher,
assetStatusCache,
mAssetSelection,
saveAssets,
showDownloadPlasticExeWindow,
workspaceOperationsMonitor,
pendingChangesUpdater,
developerIncomingChangesUpdater,
gluonIncomingChangesUpdater,
shelvedChangesUpdater,
isGluonMode);
mAssetMenuUVCSOperations = assetUVCSOperations;
}
static void OnSceneHeaderContextMenu(GenericMenu menu, Scene scene)
{
LoadMenuForAssetPath(menu, scene.path);
}
static void OnSubSceneHeaderContextMenu(GenericMenu menu, SceneHierarchyHooks.SubSceneInfo subSceneInfo)
{
LoadMenuForAssetPath(menu, subSceneInfo.scene.path);
}
static void OnGameObjectContextMenu(GenericMenu menu, GameObject gameObject)
{
string prefabAssetPath;
if (TryGetAssetPathForPrefab(gameObject, out prefabAssetPath))
{
LoadMenuForAssetPath(menu, prefabAssetPath);
}
}
static bool TryGetAssetPathForPrefab(GameObject gameObject, out string assetPath)
{
assetPath = null;
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null && prefabStage.prefabContentsRoot == gameObject)
{
assetPath = prefabStage.assetPath;
}
return assetPath != null;
}
static void LoadMenuForAssetPath(GenericMenu menu, string assetPath)
{
string assetFullPath = AssetsPath.GetFullPathUnderWorkspace.ForAsset(mWkInfo.ClientPath, assetPath);
if (assetFullPath == null)
return;
mAssetSelection.SetActiveAsset(new Asset(assetFullPath));
AddItemsToMenu(menu);
}
static void AddItemsToMenu(GenericMenu menu)
{
menu.AddSeparator(string.Empty);
menu.AddItem(
GetPlasticMenuItemContent(PlasticLocalization.Name.PendingChangesPlasticMenu),
false,
PendingChanges);
menu.AddSeparator(GetSubMenuName());
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.AddPlasticMenu),
Add,
AssetMenuOperations.Add
);
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.CheckoutPlasticMenu),
Checkout,
AssetMenuOperations.Checkout
);
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.CheckinPlasticMenu),
Checkin,
AssetMenuOperations.Checkin
);
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.UndoPlasticMenu),
Undo,
AssetMenuOperations.Undo
);
menu.AddSeparator(GetSubMenuName());
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.CopyFilePathMenuItem),
CopyFilePath,
AssetMenuOperations.CopyFilePath
);
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.CopyRelativeFilePathMenuItem),
CopyRelativeFilePath,
AssetMenuOperations.CopyFilePath
);
menu.AddSeparator(GetSubMenuName());
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.DiffPlasticMenu),
Diff,
AssetMenuOperations.Diff
);
AddMenuItemForConditionalOperation(
menu,
GetPlasticMenuItemContent(PlasticLocalization.Name.HistoryPlasticMenu),
History,
AssetMenuOperations.History
);
}
static void AddMenuItemForConditionalOperation(
GenericMenu menu,
GUIContent menuContent,
GenericMenu.MenuFunction menuAction,
AssetMenuOperations operation)
{
if (ValidateOperation(operation))
{
menu.AddItem(menuContent, false, menuAction);
}
else
{
menu.AddDisabledItem(menuContent);
}
}
static void PendingChanges()
{
ShowWindow.UVCS();
mAssetMenuUVCSOperations.ShowPendingChanges();
}
static void Add()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Add();
}
static void Checkout()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Checkout();
}
static void Checkin()
{
TrackFeatureUseEvent.For(
PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
TrackFeatureUseEvent.Features.UnityPackage.HierarchyContextMenuCheckinOption);
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Checkin();
}
static void Undo()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Undo();
}
static void CopyFilePath()
{
mAssetMenuCopyPathOperation.CopyFilePath(relativePath: false);
}
static void CopyRelativeFilePath()
{
mAssetMenuCopyPathOperation.CopyFilePath(relativePath: true);
}
static void Diff()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.ShowDiff();
}
static void History()
{
ShowWindow.UVCS();
mAssetMenuUVCSOperations.ShowHistory();
}
static bool ValidateOperation(AssetMenuOperations operation)
{
return AssetMenuUpdater.ShouldMenuOperationBeEnabled(
mWkInfo, mPlasticAPI, mAssetSelection, mAssetStatusCache, operation);
}
static GUIContent GetPlasticMenuItemContent(PlasticLocalization.Name name)
{
string menuText = string.Format("{0}{1}",
GetSubMenuName(),
name.GetString());
return EditorGUIUtility.TrTextContent(menuText);
}
static string GetSubMenuName()
{
return PlasticLocalization.Name.UnityVersionControl.GetString() + "/";
}
static bool mIsEnabled;
static WorkspaceInfo mWkInfo;
static IPlasticAPI mPlasticAPI;
static IAssetStatusCache mAssetStatusCache;
static HierarchyViewAssetSelection mAssetSelection;
static IAssetMenuUVCSOperations mAssetMenuUVCSOperations;
static IAssetMenuCopyPathOperation mAssetMenuCopyPathOperation;
static readonly ILog mLog = PlasticApp.GetLogger("HierarchyViewMenu");
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c50ac3c60fd045b38f5449bb43db257d
timeCreated: 1751878870

View File

@@ -0,0 +1,19 @@
using UnityEditor.VersionControl;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal class HierarchyViewAssetSelection : AssetUVCSOperations.IAssetSelection
{
AssetList AssetUVCSOperations.IAssetSelection.GetSelectedAssets()
{
return mSelectedAsset != null ? new AssetList() { mSelectedAsset } : new AssetList();
}
internal void SetActiveAsset(Asset asset)
{
mSelectedAsset = asset;
}
Asset mSelectedAsset;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 19397b4b199145c5bd9ee8c1c7d5938d
timeCreated: 1751879990

View File

@@ -0,0 +1,61 @@
using System;
using UnityEditor;
using UnityEditor.VersionControl;
using Unity.PlasticSCM.Editor.AssetUtils;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal class ProjectViewAssetSelection : AssetUVCSOperations.IAssetSelection
{
internal ProjectViewAssetSelection(Action assetSelectionChangedAction)
{
mAssetSelectionChangedAction = assetSelectionChangedAction;
Selection.selectionChanged += SelectionChanged;
}
internal void Dispose()
{
Selection.selectionChanged -= SelectionChanged;
}
void SelectionChanged()
{
// Selection.selectionChanged gets triggered on both
// project view and scene view. We only want to trigger
// the action if user selects on project view (has assets)
if (HasSelectedAssets())
mAssetSelectionChangedAction();
}
AssetList AssetUVCSOperations.IAssetSelection.GetSelectedAssets()
{
if (Selection.assetGUIDs.Length == 0)
return new AssetList();
AssetList result = new AssetList();
foreach (string guid in Selection.assetGUIDs)
{
string assetPath = AssetsPath.GetFullPath.ForGuid(guid);
if (string.IsNullOrEmpty(assetPath))
continue;
result.Add(new Asset(assetPath));
}
return result;
}
bool HasSelectedAssets()
{
// Objects in project view have GUIDs, objects in scene view don't
return Selection.assetGUIDs.Length > 0;
}
Action mAssetSelectionChangedAction;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8a49294ba135a2408fd1b26bcda6f97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,84 @@
using System.Linq;
using UnityEditor;
using PlasticGui;
using Unity.PlasticSCM.Editor.AssetMenu.Dialogs;
using Unity.PlasticSCM.Editor.CloudDrive;
using Unity.PlasticSCM.Editor.CloudDrive.CreateWorkspace;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal static class ProjectViewCloudDriveAssetMenu
{
internal static void AddMenuItem()
{
HandleMenuItem.AddMenuItem(
PlasticLocalization.Name.AddToUnityCloudDriveMenu.GetString(),
ProjectViewUVCSAssetMenu.BASE_MENU_ITEM_PRIORITY,
AddToCloudDrive,
ValidateAddToCloudDrive);
HandleMenuItem.UpdateAllMenus();
}
internal static void RemoveMenuItem()
{
HandleMenuItem.RemoveMenuItem(
PlasticLocalization.Name.AddToUnityCloudDriveMenu.GetString());
}
static void AddToCloudDrive()
{
if (PlasticGuiConfig.Get().Configuration.ShowCloudDriveWelcomeView ||
UnityConfigurationChecker.NeedsConfiguration())
{
ShowWindow.CloudDrive();
return;
}
if (!CloudDriveWindow.HasCloudDriveWorkspaces())
{
CreateWorkspaceDialog.CreateWorkspace(
PlasticGui.Plastic.WebRestAPI,
PlasticGui.Plastic.API,
EditorWindow.focusedWindow,
(createdWorkspace) => { ShowAddToCloudDriveDialog(); });
return;
}
ShowAddToCloudDriveDialog();
}
static void ShowAddToCloudDriveDialog()
{
string[] selectedPaths = GetSelectedAssetPaths();
if (selectedPaths.Length == 0)
return;
AddToCloudDriveDialog.ShowDialog(
selectedPaths,
PlasticGui.Plastic.WebRestAPI,
PlasticGui.Plastic.API,
EditorWindow.focusedWindow);
}
static bool ValidateAddToCloudDrive()
{
return Selection.assetGUIDs != null && Selection.assetGUIDs.Length > 0;
}
static string[] GetSelectedAssetPaths()
{
if (Selection.assetGUIDs == null || Selection.assetGUIDs.Length == 0)
return new string[0];
return Selection.assetGUIDs
.Select(guid => AssetDatabase.GUIDToAssetPath(guid))
.Where(path => !string.IsNullOrEmpty(path))
.ToArray();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9874d2fcd73d40b6940619e9cd482ad4
timeCreated: 1756131709

View File

@@ -0,0 +1,351 @@
using UnityEditor.VersionControl;
using Codice.CM.Common;
using Codice.Client.Common.EventTracking;
using Codice.LogWrapper;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using PlasticGui.WorkspaceWindow.Items;
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.Tool;
using GluonIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.IncomingChangesUpdater;
namespace Unity.PlasticSCM.Editor.AssetMenu
{
internal static class ProjectViewUVCSAssetMenu
{
internal static void Enable(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
IAssetStatusCache assetStatusCache)
{
if (mIsEnabled)
return;
mLog.Debug("Enable");
mWkInfo = wkInfo;
mPlasticAPI = plasticApi;
mAssetStatusCache = assetStatusCache;
mIsEnabled = true;
mAssetSelection = new ProjectViewAssetSelection(UpdateFilterMenuItems);
mAssetMenuCopyPathOperation = new AssetCopyPathOperation(
wkInfo, mPlasticAPI, assetStatusCache, mAssetSelection);
mFilterMenuBuilder = new AssetFilesFilterPatternsMenuBuilder(
IGNORE_MENU_ITEMS_PRIORITY,
HIDDEN_MENU_ITEMS_PRIORITY);
AddMenuItems();
}
internal static void Disable()
{
mLog.Debug("Disable");
mIsEnabled = false;
RemoveMenuItems();
if (mAssetSelection != null)
mAssetSelection.Dispose();
mWkInfo = null;
mAssetStatusCache = null;
mAssetSelection = null;
mFilterMenuBuilder = null;
mAssetMenuUVCSOperations = null;
mAssetMenuCopyPathOperation = null;
}
internal static void BuildOperations(
WorkspaceInfo wkInfo,
IPlasticAPI plasticApi,
GluonGui.ViewHost viewHost,
WorkspaceWindow workspaceWindow,
IViewSwitcher viewSwitcher,
PlasticGui.Gluon.IGluonViewSwitcher gluonViewSwitcher,
IMergeViewLauncher mergeViewLauncher,
IHistoryViewLauncher historyViewLauncher,
IAssetStatusCache assetStatusCache,
ISaveAssets saveAssets,
LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
WorkspaceOperationsMonitor workspaceOperationsMonitor,
PendingChangesUpdater pendingChangesUpdater,
IncomingChangesUpdater developerIncomingChangesUpdater,
GluonIncomingChangesUpdater gluonIncomingChangesUpdater,
ShelvedChangesUpdater shelvedChangesUpdater,
bool isGluonMode)
{
if (!mIsEnabled)
Enable(wkInfo, plasticApi, assetStatusCache);
AssetUVCSOperations assetUVCSOperations = new AssetUVCSOperations(
wkInfo,
plasticApi,
viewHost,
workspaceWindow,
viewSwitcher,
gluonViewSwitcher,
mergeViewLauncher,
historyViewLauncher,
assetStatusCache,
mAssetSelection,
saveAssets,
showDownloadPlasticExeWindow,
workspaceOperationsMonitor,
pendingChangesUpdater,
developerIncomingChangesUpdater,
gluonIncomingChangesUpdater,
shelvedChangesUpdater,
isGluonMode);
mAssetMenuUVCSOperations = assetUVCSOperations;
mFilterMenuBuilder.SetOperations(assetUVCSOperations);
}
static void RemoveMenuItems()
{
mFilterMenuBuilder.RemoveMenuItems();
HandleMenuItem.RemoveMenuItem(
PlasticLocalization.GetString(PlasticLocalization.Name.PrefixUnityVersionControlMenu));
HandleMenuItem.UpdateAllMenus();
}
static void UpdateFilterMenuItems()
{
AssetList assetList = ((AssetUVCSOperations.IAssetSelection)
mAssetSelection).GetSelectedAssets();
SelectedPathsGroupInfo info = AssetsSelection.GetSelectedPathsGroupInfo(
mWkInfo.ClientPath, assetList, mAssetStatusCache);
FilterMenuActions actions =
assetList.Count != info.SelectedCount ?
new FilterMenuActions() :
FilterMenuUpdater.GetMenuActions(info);
mFilterMenuBuilder.UpdateMenuItems(actions);
}
static void AddMenuItems()
{
// TODO: Try removing this
// Somehow first item always disappears. So this is a filler item
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.PendingChangesPlasticMenu),
PENDING_CHANGES_MENU_ITEM_PRIORITY,
PendingChanges, ValidatePendingChanges);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.PendingChangesPlasticMenu),
PENDING_CHANGES_MENU_ITEM_PRIORITY,
PendingChanges, ValidatePendingChanges);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.AddPlasticMenu),
ADD_MENU_ITEM_PRIORITY,
Add, ValidateAdd);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.CheckoutPlasticMenu),
CHECKOUT_MENU_ITEM_PRIORITY,
Checkout, ValidateCheckout);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.CheckinPlasticMenu),
CHECKIN_MENU_ITEM_PRIORITY,
Checkin, ValidateCheckin);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.UndoPlasticMenu),
UNDO_MENU_ITEM_PRIORITY,
Undo, ValidateUndo);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.CopyFilePathMenuItem),
COPY_FILE_PATH_MENU_ITEM_PRIORITY,
CopyFilePath,
ValidateCopyFilePath);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.CopyRelativeFilePathMenuItem),
COPY_RELATIVE_FILE_PATH_MENU_ITEM_PRIORITY,
CopyRelativeFilePath,
ValidateCopyFilePath);
UpdateFilterMenuItems();
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.DiffPlasticMenu),
GetPlasticShortcut.ForAssetDiff(),
DIFF_MENU_ITEM_PRIORITY,
Diff, ValidateDiff);
HandleMenuItem.AddMenuItem(
GetPlasticMenuItemName(PlasticLocalization.Name.HistoryPlasticMenu),
GetPlasticShortcut.ForHistory(),
HISTORY_MENU_ITEM_PRIORITY,
History, ValidateHistory);
HandleMenuItem.UpdateAllMenus();
}
static void PendingChanges()
{
ShowWindow.UVCS();
mAssetMenuUVCSOperations.ShowPendingChanges();
}
static bool ValidatePendingChanges()
{
return true;
}
static void Add()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Add();
}
static bool ValidateAdd()
{
return ValidateOperation(AssetMenuOperations.Add);
}
static void Checkout()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Checkout();
}
static bool ValidateCheckout()
{
return ValidateOperation(AssetMenuOperations.Checkout);
}
static void Checkin()
{
TrackFeatureUseEvent.For(
PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
TrackFeatureUseEvent.Features.UnityPackage.ProjectContextMenuCheckinOption);
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Checkin();
}
static bool ValidateCheckin()
{
return ValidateOperation(AssetMenuOperations.Checkin);
}
static void Undo()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.Undo();
}
static bool ValidateUndo()
{
return ValidateOperation(AssetMenuOperations.Undo);
}
static void CopyFilePath()
{
mAssetMenuCopyPathOperation.CopyFilePath(relativePath: false);
}
static void CopyRelativeFilePath()
{
mAssetMenuCopyPathOperation.CopyFilePath(relativePath: true);
}
static bool ValidateCopyFilePath()
{
return ValidateOperation(AssetMenuOperations.CopyFilePath);
}
static void Diff()
{
if (mAssetMenuUVCSOperations == null)
ShowWindow.UVCS();
mAssetMenuUVCSOperations.ShowDiff();
}
static bool ValidateDiff()
{
return ValidateOperation(AssetMenuOperations.Diff);
}
static void History()
{
ShowWindow.UVCS();
mAssetMenuUVCSOperations.ShowHistory();
}
static bool ValidateHistory()
{
return ValidateOperation(AssetMenuOperations.History);
}
static bool ValidateOperation(AssetMenuOperations operation)
{
return AssetMenuUpdater.ShouldMenuOperationBeEnabled(
mWkInfo, mPlasticAPI, mAssetSelection, mAssetStatusCache, operation);
}
static string GetPlasticMenuItemName(PlasticLocalization.Name name)
{
return string.Format("{0}/{1}",
PlasticLocalization.GetString(PlasticLocalization.Name.PrefixUnityVersionControlMenu),
PlasticLocalization.GetString(name));
}
static IAssetMenuUVCSOperations mAssetMenuUVCSOperations;
static IAssetMenuCopyPathOperation mAssetMenuCopyPathOperation;
static ProjectViewAssetSelection mAssetSelection;
static AssetFilesFilterPatternsMenuBuilder mFilterMenuBuilder;
static bool mIsEnabled;
static IAssetStatusCache mAssetStatusCache;
static IPlasticAPI mPlasticAPI;
static WorkspaceInfo mWkInfo;
#if UNITY_6000_0_OR_NEWER
// Puts Unity Version Control in a new section, as it precedes the Create menu with the old value
internal const int BASE_MENU_ITEM_PRIORITY = 71;
#else
// Puts Unity Version Control right below the Create menu
internal const int BASE_MENU_ITEM_PRIORITY = 19;
#endif
// incrementing the "order" param by 11 causes the menu system to add a separator
const int PENDING_CHANGES_MENU_ITEM_PRIORITY = BASE_MENU_ITEM_PRIORITY;
const int ADD_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 11;
const int CHECKOUT_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 12;
const int CHECKIN_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 13;
const int UNDO_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 14;
const int COPY_FILE_PATH_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 25;
const int COPY_RELATIVE_FILE_PATH_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 26;
const int IGNORE_MENU_ITEMS_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 37;
const int HIDDEN_MENU_ITEMS_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 38;
const int DIFF_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 49;
const int HISTORY_MENU_ITEM_PRIORITY = PENDING_CHANGES_MENU_ITEM_PRIORITY + 50;
static readonly ILog mLog = PlasticApp.GetLogger("ProjectViewAssetMenu");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c8a8e3e4456f9149905cf2c80aa41a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: