using UnityEditor; using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text.RegularExpressions; using System.Linq; using System.IO; using Perforce.P4; using log4net; namespace P4Connect { [Serializable] public class ConfigAsset : ScriptableObject { // These are the config values // We serialize this Class and place it in the P4Connect/Editor Asset Hierarchy public string ServerURI; public string Username; [HideInInspector] public string Password; public string Workspace; public string Hostname; public string Charset; public bool UnityVSSupport; public bool PerforceEnabled; public bool IncludeProjectFiles; public bool IncludeSolutionFiles; public bool ShowPaths; public bool AskBeforeCheckout; public bool DisplayStatusIcons; public string DiffToolPathname; public bool DisplayP4Timings; public bool DisplayP4Commands; public bool CheckStatusForMenus; public int CheckStatusForMenusMaxItems; public int ConnectionTimeOut; public bool WarnOnSpecialCharacters; public string IgnoreName; public bool EnableLog; public Logger.LogLevel ConsoleLogLevel; public string LogPath; public string IgnoreLines; // Copy the contents of this ConfigAsset into the P4Connect Config class. public void CopyAssetToConfig() { Config.ServerURI = ServerURI; Config.Username = Username; Config.Password = Password; Config.Workspace = Workspace; Config.Hostname = Hostname; Config.Charset = Charset; Config.UnityVSSupport = UnityVSSupport; Config.PerforceEnabled = PerforceEnabled; Config.IncludeProjectFiles = IncludeProjectFiles; Config.IncludeSolutionFiles = IncludeSolutionFiles; Config.ShowPaths = ShowPaths; Config.AskBeforeCheckout = AskBeforeCheckout; Config.DisplayStatusIcons = DisplayStatusIcons; Config.DiffToolPathname = DiffToolPathname; Config.DisplayP4Timings = DisplayP4Timings; Config.DisplayP4Commands = DisplayP4Commands; Config.CheckStatusForMenus = CheckStatusForMenus; Config.CheckStatusForMenusMaxItems = CheckStatusForMenusMaxItems; Config.ConnectionTimeOut = ConnectionTimeOut; Config.WarnOnSpecialCharacters = WarnOnSpecialCharacters; Config.IgnoreName = IgnoreName; Config.EnableLog = EnableLog; Config.ConsoleLogLevel = ConsoleLogLevel; Config.LogPath = LogPath; Config.IgnoreLines = IgnoreLines; } // Seed a ConfigAsset with data from the Config Class public void CopyConfigToAsset() { ServerURI = Config.ServerURI; Username = Config.Username; Password = Config.Password; Workspace = Config.Workspace; Hostname = Config.Hostname; Charset = Config.Charset; UnityVSSupport = Config.UnityVSSupport; PerforceEnabled = Config.PerforceEnabled; IncludeProjectFiles = Config.IncludeProjectFiles; IncludeSolutionFiles = Config.IncludeSolutionFiles; ShowPaths = Config.ShowPaths; AskBeforeCheckout = Config.AskBeforeCheckout; DisplayStatusIcons = Config.DisplayStatusIcons; DiffToolPathname = Config.DiffToolPathname; DisplayP4Timings = Config.DisplayP4Timings; DisplayP4Commands = Config.DisplayP4Commands; CheckStatusForMenus = Config.CheckStatusForMenus; CheckStatusForMenusMaxItems = Config.CheckStatusForMenusMaxItems; ConnectionTimeOut = Config.ConnectionTimeOut; WarnOnSpecialCharacters = Config.WarnOnSpecialCharacters; IgnoreName = Config.IgnoreName; EnableLog = Config.EnableLog; ConsoleLogLevel = Config.ConsoleLogLevel; LogPath = Config.LogPath; IgnoreLines = Config.IgnoreLines; } } // This Editor window allows the user to set and store // Perforce connection settings that will be used to // Check out files on Save / Move / Delete / etc... // The connection parameters are saved as Editor Preferences // which means they go the registry. public class Config : EditorWindow { private static readonly ILog log = LogManager.GetLogger(typeof(Config)); static string P4CONFIG_DEFAULT = ".p4config"; // Event triggered when the configuration changes public delegate void OnPrefsChanged(); public static event OnPrefsChanged PrefsChanged; #region Properties // Give access to the Server URI public static string ServerURI { get; set; } // Give access to the User Name public static string Username { get; set; } // Give access to the Password public static string Password { get; set; } // Give access to the Workspace Name public static string Workspace { get; set; } // Give access to whether we integrate with UnityVS public static bool UnityVSSupport { get; set; } // Give access to whether the integration is turned on or not public static bool PerforceEnabled { get; set; } // Give access to whether we check out solution files public static bool IncludeSolutionFiles { get; set; } // Give access to whether we check out project files public static bool IncludeProjectFiles { get; set; } // Give access to whether we print out paths or just filenames public static bool ShowPaths { get; set; } // Give access to whether we automatically check out on edit public static bool AskBeforeCheckout { get; set; } // Give access to whether we want to display Icons in the Project view public static bool DisplayStatusIcons { get; set; } // The host name, if different than the local machine public static string Hostname { get; set; } // The host name, if different than the local machine public static string Charset { get; set; } // The location of the Diff tool public static string DiffToolPathname { get; set; } // Whether or not to display timing info for debugging public static bool DisplayP4Timings { get; set; } // Whether to display the commands sent to P4 public static bool DisplayP4Commands { get; set; } // Whether or not to check the status of files before showing the contextual menu public static bool CheckStatusForMenus { get; set; } // Whether or not to warn when adding files with special characters public static bool WarnOnSpecialCharacters { get; set; } // Whether or not to check the status of files before showing the contextual menu public static int CheckStatusForMenusMaxItems { get; set; } // How many files to submit at once public static int OperationBatchCount { get; set; } // How long to keep connections open public static int ConnectionTimeOut { get; set; } // Provide an Ignore file name public static string IgnoreName { get; set; } // Additional Ignore Lines public static string IgnoreLines { get; set; } // Enable log4net Logging public static bool EnableLog { get; set; } // What log level to display in the console? public static Logger.LogLevel ConsoleLogLevel { get; set; } // Where to save log output public static string LogPath { get; set; } #endregion static bool FoundConfigAsset; // Helper property to indicate that P4 can be used public static bool ValidConfiguration { get { return PerforceEnabled && _CurrentState == ConfigurationState.SettingsValid; } } public const string P4BridgeDLLName = "p4bridge.dll"; public const string P4BridgeDYLIBName = "libp4bridge.dylib"; public const int MaxPendingItems = 200; #region Registry Names // These are the names under which the connection settings are stored in the registry public const string ServerURIPrefName = "ServerURI"; public const string UserNamePrefName = "UserName"; public const string PasswordPrefName = "Password"; public const string WorkspacePrefName = "Workspace"; public const string PerforceEnabledPrefName = "Enabled"; public const string UnityVSSupportPrefName = "UnityVSSupport"; public const string IncludeProjectFilesPrefName = "IncludeProjectFiles"; public const string IncludeSolutionFilesPrefName = "IncludeSolutionFiles"; public const string ShowPathsPrefName = "ShowPaths"; public const string AskBeforeCheckoutPrefName = "AskBeforeCheckout"; public const string DisplayStatusIconsPrefName = "DisplayStatusIcons"; public const string HostnamePrefName = "Hostname"; public const string DiffToolPathnamePrefName = "DiffToolPathname"; public const string DisplayP4TimingsPrefName = "DisplayTimings"; public const string DisplayP4CommandsPrefName = "DisplayCommands"; public const string CheckStatusForMenusPrefName = "CheckStatusForMenus"; public const string CheckStatusForMenusMaxItemsPrefName = "CheckStatusForMenusMaxItems"; public const string OperationBatchCountPrefName = "OperationBatchCount"; public const string ConnectionTimeOutPrefName = "ConnectionTimeOut"; public const string WarnOnSpecialCharactersPrefName = "WarnOnSpecialCharacters"; public const string UseIgnorePrefName = "UseIgnore"; public const string IgnoreNamePrefName = "IgnoreName"; public const string EnableLogPrefName = "EnableLog"; public const string ConsoleLogLevelPrefName = "ConsoleLogLevel"; public const string LogPathPrefName = "LogPath"; public const string IgnoreLinesPrefName = "IgnoreLines"; #endregion // The current state of the configuration, whether it is valid to be used enum ConfigurationState { Unknown = 0, MetaFilesInvalid, MetaFilesValid, ServerInvalid, ServerValid, UsernamePassInvalid, UsernamePassValid, WorkspaceInvalid, WorkspaceValid, ProjectRootInvalid, ProjectRootValid, SettingsValid, } // The current state of the configuration, whether it is valid to be used static ConfigurationState _CurrentState = ConfigurationState.Unknown; bool _Repaint = false; /// /// Set some default configuration values /// static Config() // Config Window Constructor { Initialize(); } static void ResetValues() { Debug.Log("ResetValues"); // Set some default values ServerURI = "localhost:1666"; Username = Environment.UserName; Password = ""; Workspace = Username + "_" + Main.ProjectName + "_" + Environment.MachineName; UnityVSSupport = false; PerforceEnabled = true; IncludeProjectFiles = false; IncludeSolutionFiles = false; ShowPaths = false; AskBeforeCheckout = false; DisplayStatusIcons = true; Hostname = ""; Charset = ""; DiffToolPathname = ""; DisplayP4Timings = false; DisplayP4Commands = false; CheckStatusForMenus = true; CheckStatusForMenusMaxItems = 10; ConnectionTimeOut = 30; WarnOnSpecialCharacters = true; FoundConfigAsset = false; IgnoreName = ""; IgnoreLines = ""; EnableLog = false; LogPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\p4connect.log"; ConsoleLogLevel = Logger.LogLevel.Info; } static Config window = null; // Add menu item to show the configuration panel [MenuItem("Edit/Perforce Settings", false, 300)] public static void ShowWindow() { // Show existing window instance. If one doesn't exist, make one. window = EditorWindow.GetWindow("P4 Settings"); window.name = "P4 Settings"; window.title = "P4 Settings"; window.minSize = new UnityEngine.Vector2(500.0f, 500.0f); } public static void Refresh() { if (window != null) window.Repaint(); } /// /// Static Constructor, reads connection settings from Prefs at least once /// public static void Initialize() { FoundConfigAsset = readConfigAsset(); if (!FoundConfigAsset) { Debug.Log("Loading Configuration from EditorPrefs"); ReadPrefs(); } CachedSerializationMode = EditorSettings.serializationMode; Refresh(); } /// /// Checks the that settings are valid /// public static void CheckSettings() { if (PerforceEnabled) { // We only display a message when something changes ConfigurationState prevState = _CurrentState; _CurrentState = ConfigurationState.Unknown; UpdateConfigState(true); // Run config state machine // If the state is different then when we started if (_CurrentState != prevState) { Icons.UpdateDisplay(); if (_CurrentState != ConfigurationState.SettingsValid) { Debug.LogWarning("P4Connect - Perforce integration is enabled but inactive. Go to Edit->Perforce Settings to update your settings"); } else if (prevState != ConfigurationState.SettingsValid) { Debug.Log("P4Connect - Perforce Integration is Active"); } } //if (_CurrentState == ConfigurationState.SettingsValid) //{ // SetProjectRootDirectory(); //} } } /// /// Updates the current configuration state after checking all the settings /// public static void UpdateConfigState(bool fast) { try { switch (_CurrentState) { case ConfigurationState.Unknown: // The unknown state starts by checking the meta files goto case ConfigurationState.MetaFilesInvalid; case ConfigurationState.MetaFilesInvalid: EditorUtility.DisplayProgressBar("P4Connect - Hold on", "Checking Meta Files", 0.2f); if (P4Connect.VerifySettings.CheckMetaFiles()) { // Meta files are valid, move on _CurrentState = ConfigurationState.MetaFilesValid; goto case ConfigurationState.MetaFilesValid; } else { // Stay in this state _CurrentState = ConfigurationState.MetaFilesInvalid; break; } case ConfigurationState.MetaFilesValid: if (fast) { goto case ConfigurationState.ProjectRootInvalid; // jump ahead for a quick connection } goto case ConfigurationState.ServerInvalid; case ConfigurationState.ServerInvalid: EditorUtility.DisplayProgressBar("P4Connect - Hold on", "Checking Server", 0.4f); if (P4Connect.VerifySettings.CheckServerURI()) { Debug.Log("ServerValid"); // Server is valid, move on _CurrentState = ConfigurationState.ServerValid; goto case ConfigurationState.ServerValid; } else { Debug.Log("ServerInvalid"); // Stay here _CurrentState = ConfigurationState.ServerInvalid; break; } case ConfigurationState.ServerValid: goto case ConfigurationState.UsernamePassInvalid; case ConfigurationState.UsernamePassInvalid: EditorUtility.DisplayProgressBar("P4Connect - Hold on", "Checking Login", 0.6f); if (P4Connect.VerifySettings.CheckUsernamePassword()) { // Username / Password is valid, move on _CurrentState = ConfigurationState.UsernamePassValid; goto case ConfigurationState.UsernamePassValid; } else { // Stay here _CurrentState = ConfigurationState.UsernamePassInvalid; break; } case ConfigurationState.UsernamePassValid: goto case ConfigurationState.WorkspaceInvalid; case ConfigurationState.WorkspaceInvalid: EditorUtility.DisplayProgressBar("P4Connect - Hold on", "Checking Workspace", 0.8f); if (P4Connect.VerifySettings.CheckWorkspace()) { // Workspace is valid _CurrentState = ConfigurationState.WorkspaceValid; goto case ConfigurationState.WorkspaceValid; } else { // Stay here _CurrentState = ConfigurationState.WorkspaceInvalid; break; } case ConfigurationState.WorkspaceValid: goto case ConfigurationState.ProjectRootInvalid; case ConfigurationState.ProjectRootInvalid: EditorUtility.DisplayProgressBar("P4Connect - Hold on", "Checking Project Root", 0.9f); if (P4Connect.VerifySettings.CheckProjectRoot()) { // Root is valid _CurrentState = ConfigurationState.ProjectRootValid; goto case ConfigurationState.ProjectRootValid; } else { // Stay here _CurrentState = ConfigurationState.ProjectRootInvalid; break; } case ConfigurationState.ProjectRootValid: _CurrentState = ConfigurationState.SettingsValid; goto case ConfigurationState.SettingsValid; case ConfigurationState.SettingsValid: break; } EditorUtility.ClearProgressBar(); if (_CurrentState != ConfigurationState.SettingsValid) { string msg = String.Format("Bad Settings, current state is {0}", _CurrentState.ToString()); EditorUtility.DisplayDialog("p4connect", msg, "Ok"); } } catch(Exception ex) { log.Debug("exception", ex); } } public static void SetProjectRootDirectory() { if (Config.ValidConfiguration) { Engine.PerformConnectionOperation(con => { // project root in perforce syntax var spec = FileSpec.LocalSpec(System.IO.Path.Combine(Main.RootPath, "...")); //log.DebugFormat("spec: {0}", spec.ToString()); var mappings = con.P4Client.GetClientFileMappings(spec); //log.DebugFormat("mappings: {0}", Logger.FileSpecListToString(mappings)); if (mappings != null && mappings.Count > 0) { // string ProjectRoot; string clientProjectRoot = mappings[0].ClientPath.Path; //log.DebugFormat("clientProjectRoot: {0} ", clientProjectRoot); int projectRootOffset = clientProjectRoot.ToLowerInvariant().IndexOf(Config.Workspace.ToLowerInvariant()); //log.DebugFormat("projectRootOffset: {0}", projectRootOffset); if (projectRootOffset != -1) { //ProjectRoot = clientProjectRoot.Substring(projectRootOffset + Config.Workspace.Length); //log.DebugFormat("ProjectRoot1: {0} ", ProjectRoot); //ProjectRoot = ProjectRoot.TrimStart(System.IO.Path.DirectorySeparatorChar, '/'); //if (ProjectRoot.EndsWith("...")) // ProjectRoot = ProjectRoot.Substring(0, ProjectRoot.Length - 3); //ProjectRoot = ProjectRoot.TrimEnd(System.IO.Path.DirectorySeparatorChar, '/'); //ProjectRoot = ProjectRoot.Replace('/', System.IO.Path.DirectorySeparatorChar); //log.Debug("SetProjectRootDirectory - ProjectRoot: " + ProjectRoot); } else { Debug.LogError("P4Connect - Your Project does not appear to be under your workspace root."); } } }); } } // static objects frequently used to create controls static GUILayoutOption _BoxWidth = GUILayout.MaxWidth(200.0f); static GUILayoutOption _EnumWidth = GUILayout.Width(75.0f); static GUILayoutOption _CheckWidth = GUILayout.Width(16.0f); static GUILayoutOption _TextWidth = GUILayout.Width(250.0f); static GUILayoutOption _ButtonWidth = GUILayout.Width(80.0f); static GUILayoutOption _IntWidth = GUILayout.Width(30.0f); int _FrameIndex = 0; int _MaxFrameCount = 3; // seems to be the right number of repaints needed to display something //Vector2 scroll = new Vector2(0,0); // Track scroll position in the additional ignore TextArea /// /// Called by Unity when the windows needs to be updated /// void OnGUI() { EditorGUILayout.BeginVertical(); // Main Window over status // A global checkbox to turn perforce integration on/off bool newPerforceEnabled = EditorGUILayout.BeginToggleGroup("Enable Perforce Integration", PerforceEnabled); // Check for a changed value if (newPerforceEnabled != PerforceEnabled) { PerforceEnabled = newPerforceEnabled; if (PerforceEnabled) { if (_FrameIndex >= _MaxFrameCount) // UI has been running a while { CheckSettings(); } } } if (PerforceEnabled) { if (_FrameIndex < _MaxFrameCount) // UI was just created, need to wait a bit before display updates { if (Event.current.type == EventType.Repaint) { ++_FrameIndex; _Repaint = true; } } if (_FrameIndex == _MaxFrameCount) { CheckSettings(); // Delayed a few frames, now we try to connect. ++_FrameIndex; } EditorGUILayout.BeginHorizontal(); // Main Window EditorGUILayout.BeginVertical(); // Left panel { EditorGUILayout.BeginVertical("box"); // Load Settings GUILayout.Label("Load Settings"); EditorGUI.BeginDisabledGroup(_CurrentState == ConfigurationState.SettingsValid); { if (GUILayout.Button("Load Defaults", EditorStyles.miniButton, _BoxWidth)) { ResetValues(); _CurrentState = ConfigurationState.Unknown; Repaint(); } if (GUILayout.Button("Load P4 Environment", EditorStyles.miniButton, _BoxWidth)) { if (!ReadEnvironment()) { EditorUtility.DisplayDialog("Read Perforce Environment", "No Perforce Environment variables found!", "OK"); } _CurrentState = ConfigurationState.Unknown; Repaint(); } if (GUILayout.Button("Load P4Config", EditorStyles.miniButton, _BoxWidth)) { string configName = Environment.GetEnvironmentVariable("P4CONFIG"); if (string.IsNullOrEmpty(configName)) { configName = P4CONFIG_DEFAULT; // If not in environment, use the default. } string p4configFile = FindP4ConfigFile(configName); if (string.IsNullOrEmpty(p4configFile)) { Debug.Log("P4Config file " + configName + " Not Found"); } else { LoadP4ConfigFile(p4configFile); Debug.Log("P4Config Found at: " + Path.GetFullPath(p4configFile)); } _CurrentState = ConfigurationState.Unknown; Repaint(); } if (GUILayout.Button("Load Editor Prefs", EditorStyles.miniButton, _BoxWidth)) { ReadPrefs(); _CurrentState = ConfigurationState.Unknown; Repaint(); } if (GUILayout.Button("Load Config Asset", EditorStyles.miniButton, _BoxWidth)) { if (!readConfigAsset()) { EditorUtility.DisplayDialog("Read Configuration Asset", "No Configuration Asset found!", "OK"); } _CurrentState = ConfigurationState.Unknown; Repaint(); } } EditorGUI.EndDisabledGroup(); // Settings Valid EditorGUILayout.EndVertical(); // Load Settings GUILayout.FlexibleSpace(); EditorGUILayout.BeginVertical("box"); // Save Settings GUILayout.Label("Save Settings"); if (GUILayout.Button("Clear Editor Prefs", EditorStyles.miniButton, _BoxWidth)) { if (EditorUtility.DisplayDialog("Remove All EditorPrefs", "Are you sure you want to remove ALL editorPrefs?", "OK", "Cancel")) { EditorPrefs.DeleteAll(); //DeleteAllEditorPrefs(); // This call doesn't work on all entries! Unity Bug? } } if (GUILayout.Button("Save EditorPrefs", EditorStyles.miniButton, _BoxWidth)) { WritePrefs(); } if (GUILayout.Button("Save Config Asset", EditorStyles.miniButton, _BoxWidth)) { writeConfigAsset(); } if (GUILayout.Button("Delete Config Asset", EditorStyles.miniButton, _BoxWidth)) { if (EditorUtility.DisplayDialog("Delete Configuration Asset", "Are you sure you want to delete this configuration?", "OK", "Cancel")) { deleteConfigAsset(); } } EditorGUILayout.EndVertical(); // Save Settings } EditorGUILayout.EndVertical(); // left panel EditorGUILayout.BeginVertical(); // The right panel GUILayout.BeginVertical("Box"); // connection box GUILayout.Label("Connection Settings", EditorStyles.boldLabel); // Disable connection settings if already connected EditorGUI.BeginDisabledGroup(_CurrentState == ConfigurationState.SettingsValid); { EditorGUILayout.BeginHorizontal(); { // The edit field for the server ServerURI = EditorGUILayout.TextField("\tServer URI", ServerURI); } EditorGUILayout.EndHorizontal(); if (_CurrentState == ConfigurationState.ServerInvalid) { EditorGUILayout.HelpBox("Invalid Server URI", MessageType.Error); } EditorGUILayout.BeginHorizontal(); { Username = EditorGUILayout.TextField("\tUsername", Username); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { Password = EditorGUILayout.PasswordField("\tPassword", Password); } EditorGUILayout.EndHorizontal(); if (_CurrentState == ConfigurationState.UsernamePassInvalid) { EditorGUILayout.HelpBox("Invalid Username / Password", MessageType.Error); } EditorGUILayout.BeginHorizontal(); { Workspace = EditorGUILayout.TextField("\tWorkspace", Workspace); } EditorGUILayout.EndHorizontal(); if (_CurrentState == ConfigurationState.WorkspaceInvalid) { EditorGUILayout.HelpBox("Invalid Workspace", MessageType.Error); } if (_CurrentState == ConfigurationState.ProjectRootInvalid) { // The project isn't under the workspace root string perforcePath = "//" + Workspace + "/..."; string rootPath = P4Connect.Main.RootPath; EditorGUILayout.HelpBox("Invalid Workspace. The client path:\n" + "\t" + perforcePath + "\n" + "maps to this folder:\n" + "\t" + VerifySettings.LastWorkspaceMapping + "\n" + "which is not a parent directory of the project's root:\n" + "\t" + rootPath, MessageType.Error); } EditorGUILayout.BeginHorizontal(); { Hostname = EditorGUILayout.TextField("\tP4HOST", Hostname); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { Charset = EditorGUILayout.TextField("\tP4CHARSET", Charset); } EditorGUILayout.EndHorizontal(); } EditorGUI.EndDisabledGroup(); // Connection Valid EditorGUILayout.BeginHorizontal(); if (GUILayout.Button((_CurrentState == ConfigurationState.SettingsValid ? "Disconnect" : "Connect"), EditorStyles.miniButton, _BoxWidth)) { if (_CurrentState == ConfigurationState.SettingsValid) { _CurrentState = ConfigurationState.Unknown; } else { EditorGUILayout.HelpBox("Please Wait! Checking Perforce Settings. This can take a while ...", MessageType.Info); CheckSettings(); } } EditorGUILayout.EndHorizontal(); GUILayout.EndVertical(); // Connection Box GUILayout.Label("Interface", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tDisplay Status Icons", _TextWidth); DisplayStatusIcons = EditorGUILayout.Toggle(DisplayStatusIcons, _CheckWidth); GUILayout.Label("\tShow File Paths in Console", _TextWidth); ShowPaths = EditorGUILayout.Toggle(ShowPaths, _CheckWidth); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tGray out invalid menu options", _TextWidth); CheckStatusForMenus = EditorGUILayout.Toggle(CheckStatusForMenus, _CheckWidth); GUILayout.Label("Don't check if more than"); CheckStatusForMenusMaxItems = EditorGUILayout.IntField(CheckStatusForMenusMaxItems, _IntWidth); GUILayout.Label("files selected"); GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tDiff Tool Executable", _TextWidth); DiffToolPathname = EditorGUILayout.TextField("", DiffToolPathname); if (GUILayout.Button("Browse...", EditorStyles.miniButton, _ButtonWidth)) { string dir; string path; GUI.FocusControl(""); if (DiffToolPathname.Length > 0) { dir = System.IO.Directory.GetParent(DiffToolPathname).FullName; } else { dir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFiles); } path = EditorUtility.OpenFilePanel("Choose Diff Tool Executable", dir, ""); if (path.Length > 0) { DiffToolPathname = path; } } } EditorGUILayout.EndHorizontal(); GUILayout.Label("Behaviour", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tAsk before checkout on edit", _TextWidth); AskBeforeCheckout = EditorGUILayout.Toggle(AskBeforeCheckout, _CheckWidth); } GUILayout.Label("\tReserved character warning (@#*%)", _TextWidth); WarnOnSpecialCharacters = EditorGUILayout.Toggle(WarnOnSpecialCharacters, _CheckWidth); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label("\tInclude Solution Files", _TextWidth); IncludeSolutionFiles = EditorGUILayout.Toggle(IncludeSolutionFiles, _CheckWidth); GUILayout.Label("\tInclude Project Files", _TextWidth); IncludeProjectFiles = EditorGUILayout.Toggle(IncludeProjectFiles, _CheckWidth); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label("\tIntegrate with UnityVS", _TextWidth); UnityVSSupport = EditorGUILayout.Toggle(UnityVSSupport, _CheckWidth); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tClose Perforce connection after"); ConnectionTimeOut = EditorGUILayout.IntField(ConnectionTimeOut, _IntWidth); GUILayout.Label("seconds"); GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tP4IGNORE", _TextWidth); IgnoreName = EditorGUILayout.TextField(IgnoreName); if (GUILayout.Button("Browse...", EditorStyles.miniButton, _ButtonWidth)) { string dir; string path; GUI.FocusControl(""); if (IgnoreName.Length > 0) { dir = System.IO.Directory.GetParent(IgnoreName).FullName; } else { dir = Main.RootPath; } path = EditorUtility.OpenFilePanel("Choose P4Ignore File", dir, ""); if (path.Length > 0) { IgnoreName = path; } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tAdditional Ignore Lines", _TextWidth); //scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.Width(pathWidth + 10.0f), GUILayout.MaxHeight(50.0f)); //scroll = EditorGUILayout.BeginScrollView(scroll); IgnoreLines = EditorGUILayout.TextArea(IgnoreLines, GUILayout.MinHeight(16.0f), GUILayout.MinWidth(200.0f)); //EditorGUILayout.EndScrollView(); } EditorGUILayout.EndHorizontal(); GUILayout.Label("Advanced", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); GUILayout.Label("\tDisplay P4 Timings", _TextWidth); DisplayP4Timings = EditorGUILayout.Toggle(DisplayP4Timings, _CheckWidth); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tEnable Logging", _TextWidth); bool newEnableLog = EditorGUILayout.Toggle(EnableLog, _CheckWidth); GUILayout.Label("Console Log Level: "); ConsoleLogLevel = (Logger.LogLevel)EditorGUILayout.EnumPopup(ConsoleLogLevel, _EnumWidth); GUILayout.FlexibleSpace(); if (newEnableLog != EnableLog) { EnableLog = newEnableLog; Logger.Initialize(); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("\tLog File", _TextWidth); LogPath = EditorGUILayout.TextField(LogPath); if (GUILayout.Button("Browse...", EditorStyles.miniButton, _ButtonWidth)) { string dir; string path; GUI.FocusControl(""); if (LogPath.Length > 0) { dir = System.IO.Directory.GetParent(LogPath).FullName; } else { dir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory); } path = EditorUtility.SaveFilePanel("Set P4Connect Log File", dir, "p4connect", "log"); if (path.Length > 0) { LogPath = path; EnableLog = true; } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); // Right Panel EditorGUILayout.EndHorizontal(); // Main Window } // If PerforceEnabled EditorGUILayout.EndToggleGroup(); // Status lines if (PerforceEnabled) { if (_CurrentState == ConfigurationState.MetaFilesInvalid) { EditorGUILayout.HelpBox("You must set the Editor Version Control to \"Meta Files\" under Edit->Project Settings->Editor", MessageType.Warning); } else if (_CurrentState != ConfigurationState.SettingsValid) { EditorGUILayout.HelpBox("Perforce Integration is INACTIVE. Please Verify your Settings!", MessageType.Warning); } else { EditorGUILayout.HelpBox("Perforce Integration is ACTIVE.", MessageType.Info); } } else { EditorGUILayout.HelpBox("Perforce Integration is DISABLED.", MessageType.Info); } // Display the bottom "Status" line EditorGUILayout.BeginHorizontal(); GUILayout.Label("Project: " + Main.RootPath); GUILayout.FlexibleSpace(); GUILayout.Label("P4Connect " + Version.p4ConnectVersion + " " + Version.build, EditorStyles.miniLabel); if (GUILayout.Button("Visit Website", EditorStyles.miniButton)) { System.Diagnostics.Process.Start("http://www.perforce.com/perforce/doc.current/manuals/p4connectguide/index.html"); } EditorGUILayout.EndHorizontal(); // bottom line EditorGUILayout.EndVertical(); // Main Window over status } void OnSelectionChange() { // UnityEngine.Object cursel = Selection.activeObject; } void OnInspectorUpdate() { if (_Repaint) { _Repaint = false; Repaint(); } } // Check for the "well known" Perforce environment variables. public static bool ReadEnvironment() { string value; bool found = false; value = Environment.GetEnvironmentVariable("P4PORT"); if (value != null) { Config.ServerURI = value; found = true; } value = Environment.GetEnvironmentVariable("P4USER"); if (value != null) { Config.Username = value; found = true; } value = Environment.GetEnvironmentVariable("P4PASSWD"); if (value != null) { Config.Password = value; found = true; } value = Environment.GetEnvironmentVariable("P4CLIENT"); if (value != null) { Config.Workspace = value; found = true; } value = Environment.GetEnvironmentVariable("P4HOST"); if (value != null) { Config.Hostname = value; found = true; } value = Environment.GetEnvironmentVariable("P4CHARSET"); if (value != null) { Config.Charset = value; found = true; } value = Environment.GetEnvironmentVariable("P4IGNORE"); if (value != null) { Config.IgnoreName = value; found = true; } Config.Refresh(); return found; } #region EditorPreferences // Utility method to read connection prefs from the registry public static void ReadPrefs() { // Check if the keys exist, and if so, read the values out // Otherwise, leave the existing values if (HasStringPrefNotEmpty(ServerURIPrefName)) ServerURI = GetPrefString(ServerURIPrefName); if (HasStringPrefNotEmpty(UserNamePrefName)) Username = GetPrefString(UserNamePrefName); if (HasStringPrefNotEmpty(PasswordPrefName)) { // Password = Secure.DecryptString(GetPrefString(PasswordPrefName)); Password = GetPrefString(PasswordPrefName); } if (HasStringPrefNotEmpty(WorkspacePrefName)) Workspace = GetPrefString(WorkspacePrefName); if (HasPref(UnityVSSupportPrefName)) UnityVSSupport = GetPrefBool(UnityVSSupportPrefName); if (HasPref(IncludeProjectFilesPrefName)) IncludeProjectFiles = GetPrefBool(IncludeProjectFilesPrefName); if (HasPref(IncludeSolutionFilesPrefName)) IncludeSolutionFiles = GetPrefBool(IncludeSolutionFilesPrefName); if (HasPref(ShowPathsPrefName)) ShowPaths = GetPrefBool(ShowPathsPrefName); if (HasPref(AskBeforeCheckoutPrefName)) AskBeforeCheckout = GetPrefBool(AskBeforeCheckoutPrefName); if (HasPref(DisplayStatusIconsPrefName)) DisplayStatusIcons = GetPrefBool(DisplayStatusIconsPrefName); if (HasStringPrefNotEmpty(HostnamePrefName)) Hostname = GetPrefString(HostnamePrefName); if (HasStringPrefNotEmpty(DiffToolPathnamePrefName)) DiffToolPathname = GetPrefString(DiffToolPathnamePrefName); if (HasPref(DisplayP4TimingsPrefName)) DisplayP4Timings = GetPrefBool(DisplayP4TimingsPrefName); if (HasPref(DisplayP4CommandsPrefName)) DisplayP4Commands = GetPrefBool(DisplayP4CommandsPrefName); if (HasPref(CheckStatusForMenusPrefName)) CheckStatusForMenus = GetPrefBool(CheckStatusForMenusPrefName); if (HasPref(CheckStatusForMenusMaxItemsPrefName)) CheckStatusForMenusMaxItems = GetPrefInt(CheckStatusForMenusMaxItemsPrefName); if (HasPref(OperationBatchCountPrefName)) OperationBatchCount = GetPrefInt(OperationBatchCountPrefName); if (HasPref(ConnectionTimeOutPrefName)) ConnectionTimeOut = GetPrefInt(ConnectionTimeOutPrefName); if (HasPref(WarnOnSpecialCharactersPrefName)) WarnOnSpecialCharacters = GetPrefBool(WarnOnSpecialCharactersPrefName); if (HasStringPrefNotEmpty(IgnoreNamePrefName)) IgnoreName = GetPrefString(IgnoreNamePrefName); if (HasStringPrefNotEmpty(IgnoreLinesPrefName)) IgnoreLines = GetPrefString(IgnoreLinesPrefName); if (HasPref(EnableLogPrefName)) EnableLog = GetPrefBool(EnableLogPrefName); if (HasPref(ConsoleLogLevelPrefName)) ConsoleLogLevel = (Logger.LogLevel)GetPrefInt(ConsoleLogLevelPrefName); if (HasStringPrefNotEmpty(LogPathPrefName)) LogPath = GetPrefString(LogPathPrefName); Config.Refresh(); // Notify users that prefs changed if (PrefsChanged != null) PrefsChanged(); } // Utility method to write our the connection prefs to the registry public static void WritePrefs() { SetPrefString(ServerURIPrefName, ServerURI); SetPrefString(UserNamePrefName, Username); if (!String.IsNullOrEmpty(Password)) { SetPrefString(PasswordPrefName, Password); // SetPrefString(PasswordPrefName, Secure.EncryptString(Password)); // Crashes Unity! } SetPrefString(WorkspacePrefName, Workspace); SetPrefBool(PerforceEnabledPrefName, PerforceEnabled); SetPrefBool(UnityVSSupportPrefName, UnityVSSupport); SetPrefBool(IncludeProjectFilesPrefName, IncludeProjectFiles); SetPrefBool(IncludeSolutionFilesPrefName, IncludeSolutionFiles); SetPrefBool(ShowPathsPrefName, ShowPaths); SetPrefBool(AskBeforeCheckoutPrefName, AskBeforeCheckout); SetPrefBool(DisplayStatusIconsPrefName, DisplayStatusIcons); SetPrefString(HostnamePrefName, Hostname); SetPrefString(DiffToolPathnamePrefName, DiffToolPathname); SetPrefBool(DisplayP4TimingsPrefName, DisplayP4Timings); SetPrefBool(DisplayP4CommandsPrefName, DisplayP4Commands); SetPrefBool(CheckStatusForMenusPrefName, CheckStatusForMenus); SetPrefInt(CheckStatusForMenusMaxItemsPrefName, CheckStatusForMenusMaxItems); SetPrefInt(OperationBatchCountPrefName, OperationBatchCount); SetPrefInt(ConnectionTimeOutPrefName, ConnectionTimeOut); SetPrefBool(WarnOnSpecialCharactersPrefName, WarnOnSpecialCharacters); SetPrefString(IgnoreNamePrefName, IgnoreName); SetPrefString(IgnoreLinesPrefName, IgnoreLines); SetPrefBool(EnableLogPrefName, EnableLog); SetPrefInt(ConsoleLogLevelPrefName, (int)ConsoleLogLevel); SetPrefString(LogPathPrefName, LogPath); } static string GetFullPrefName(string aPrefName) { return "P4Connect_" + Main.ProjectName + "_" + aPrefName; } static bool HasPref(string aPrefName) { return EditorPrefs.HasKey(GetFullPrefName(aPrefName)); } static bool HasStringPrefNotEmpty(string aPrefName) { return (!String.IsNullOrEmpty(EditorPrefs.GetString(GetFullPrefName(aPrefName)))); } static void SetPrefString(string aPrefName, string aPref) { EditorPrefs.SetString(GetFullPrefName(aPrefName), aPref); } static void SetPrefInt(string aPrefName, int aPref) { EditorPrefs.SetInt(GetFullPrefName(aPrefName), aPref); } static void SetPrefBool(string aPrefName, bool aPref) { EditorPrefs.SetBool(GetFullPrefName(aPrefName), aPref); } static string GetPrefString(string aPrefName) { return EditorPrefs.GetString(GetFullPrefName(aPrefName)); } static int GetPrefInt(string aPrefName) { return EditorPrefs.GetInt(GetFullPrefName(aPrefName)); } static bool GetPrefBool(string aPrefName) { return EditorPrefs.GetBool(GetFullPrefName(aPrefName)); } // [MenuItem("Edit/Delete Project EditorPrefs", false, 300)] static void DeleteAllEditorPrefs() { Debug.Log("DeletePrefs()"); // Delete All keys for this project EditorPrefs.DeleteKey(ServerURIPrefName); EditorPrefs.DeleteKey(UserNamePrefName); EditorPrefs.DeleteKey(PasswordPrefName); EditorPrefs.DeleteKey(WorkspacePrefName); EditorPrefs.DeleteKey(UnityVSSupportPrefName); EditorPrefs.DeleteKey(IncludeProjectFilesPrefName); EditorPrefs.DeleteKey(IncludeSolutionFilesPrefName); EditorPrefs.DeleteKey(ShowPathsPrefName); EditorPrefs.DeleteKey(AskBeforeCheckoutPrefName); EditorPrefs.DeleteKey(DisplayStatusIconsPrefName); EditorPrefs.DeleteKey(HostnamePrefName); EditorPrefs.DeleteKey(DiffToolPathnamePrefName); EditorPrefs.DeleteKey(DisplayP4TimingsPrefName); EditorPrefs.DeleteKey(DisplayP4CommandsPrefName); EditorPrefs.DeleteKey(CheckStatusForMenusPrefName); EditorPrefs.DeleteKey(CheckStatusForMenusMaxItemsPrefName); EditorPrefs.DeleteKey(OperationBatchCountPrefName); EditorPrefs.DeleteKey(ConnectionTimeOutPrefName); EditorPrefs.DeleteKey(WarnOnSpecialCharactersPrefName); EditorPrefs.DeleteKey(IgnoreNamePrefName); EditorPrefs.DeleteKey(IgnoreLinesPrefName); EditorPrefs.DeleteKey(EnableLogPrefName); EditorPrefs.DeleteKey(ConsoleLogLevelPrefName); } #endregion public static SerializationMode CachedSerializationMode { get; private set; } #region P4CONFIG public static string FindP4ConfigFile(string config) { string directoryName; if (!String.IsNullOrEmpty(config)) { string path = Application.dataPath; while (path != null) { directoryName = Path.GetDirectoryName(path); if (!String.IsNullOrEmpty(directoryName)) { string[] files = System.IO.Directory.GetFiles(directoryName, config); if (files.Count() > 0) { return files[0]; } } path = directoryName; } } return null; } public static void LoadP4ConfigFile(string path) { string line; char[] equalsChars = { '=' }; System.IO.StreamReader file = new System.IO.StreamReader(path); while ((line = file.ReadLine()) != null) { string[] segments = line.Split(equalsChars); if (segments.Length >= 2) { string key = segments[0]; string val = segments[1]; switch (segments[0]) { case "P4PORT": { ServerURI = val; } break; case "P4USER": { Username = val; } break; case "P4CLIENT": { Workspace = val; } break; case "P4PASSWD": { Password = val; } break; case "P4HOST": { Hostname = val; } break; case "P4CHARSET": { Charset = val; } break; } } } file.Close(); } #endregion #region ConfigAsset static string configAssetPath = "Assets/P4Connect/Editor/Config.asset"; public static void writeConfigAsset() { ConfigAsset asset = ScriptableObject.CreateInstance(); asset.CopyConfigToAsset(); AssetDatabase.CreateAsset(asset, configAssetPath); AssetDatabase.SaveAssets(); } public static bool readConfigAsset() { ConfigAsset asset = AssetDatabase.LoadAssetAtPath(configAssetPath, (typeof(ConfigAsset))) as ConfigAsset; if (asset != null) { Debug.Log("Loaded Asset"); asset.CopyAssetToConfig(); Config.Refresh(); return true; } else { Debug.Log("Failed to Load Asset"); return false; } } public static void deleteConfigAsset() { if (!AssetDatabase.DeleteAsset(configAssetPath)) { System.IO.File.Delete(System.IO.Path.Combine(Main.RootPath, configAssetPath)); } } /* If the inspector is used to view a Config Asset, these properties control the presentation */ [CustomEditor(typeof(ConfigAsset))] public class ConfigAssetPropertiesEditor : Editor { public override void OnInspectorGUI() { GUI.enabled = false; DrawDefaultInspector(); GUI.enabled = true; } } #endregion } }