// // Copyright 2014 Perforce Software Inc. // using Perforce.Model; using Perforce.View; using Perforce.ViewModel; using Perforce.P4; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; using System.Windows; using Technewlogic.WpfDialogManagement; using Microsoft.Office.Interop.Outlook; using OutlookApp = Microsoft.Office.Interop.Outlook.Application; namespace Perforce.Helper { public class CommandHelper { public static void OpenFileFromShelf(string depotPath = null) { Log.TraceFunction(); var helper = Utility.GetPerforceHelper(); var filename = helper.GetFileFromShelf(depotPath); OpenLocalFile(filename); } public static void OpenFileFromServer(string depotPath=null, int revision = -1) { Log.TraceFunction(); var helper = Utility.GetPerforceHelper(); var filename = helper.GetFileFromServer(depotPath, revision); OpenLocalFile(filename); } public static void OpenLocalFile(string filename=null) { Log.TraceFunction(); if (filename != null) { var ext = Path.GetExtension(filename); if (filename.Contains(" ")) { filename = string.Format("\"{0}\"", filename); } var extHelper = Utility.GetExtensionHelper(); var appName = extHelper.GetMapping(ext); try { if (appName != null) { Process.Start(appName, filename); } else { Process.Start(filename); } } catch (System.Exception ex) { UIHelper.ShowMessage(string.Format("Error encountered while opening file:\n{0}", ex.Message)); } } } public static bool IsFileLocked(string filename) { Log.TraceFunction(); var file = new FileInfo(filename); FileStream stream = null; try { stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (IOException) { //the file is unavailable because it is: //still being written to //or being processed by another thread //or does not exist (has already been processed) return true; } finally { if (stream != null) stream.Close(); } //file is not locked return false; } public static void SendEmail(string perforceUser, string referenceFile = null) { Log.TraceFunction(); var helper = Utility.GetPerforceHelper(); var user = helper.GetUserInfo(perforceUser); if (user != null) { var email = user.EmailAddress; OutlookApp outlookApp = new OutlookApp(); MailItem mailItem = outlookApp.CreateItem(OlItemType.olMailItem); var subject = string.Empty; if (referenceFile != null) { subject = string.Format("Mail regarding {0}", referenceFile); } else { subject = "Mail from Perforce"; } mailItem.To = email; mailItem.Subject = subject; mailItem.HTMLBody = string.Format("{0},

This email is regarding the following file that is locked in DESI:

{1}", user.FullName, referenceFile); //Set a high priority to the message mailItem.Importance = OlImportance.olImportanceHigh; mailItem.Display(); } } public static void AddToFavorites(ListingItem item) { Log.TraceFunction(); var path = string.Empty; SELECTOR_TYPE type = item.ColumnContext.Selector.SelectorType; switch (type) { case SELECTOR_TYPE.WORKSPACE: path = item.ClientPath; break; case SELECTOR_TYPE.SERVER: path = item.DepotPath; break; } var favItem = new FavoriteFolderItem { FolderName = item.LabelText, FolderPath = path, Selector = type }; var favHelper = Utility.GetFavoritesHelper(); favHelper.SaveFavorite(favItem); UIHelper.RefreshFavorites(); } public static void RemoveFromFavorites(FavoriteFolderItem item) { Log.TraceFunction(); var favHelper = Utility.GetFavoritesHelper(); favHelper.RemoveFavorite(item); UIHelper.RefreshFavorites(); } public static void RemoveFromTags(FavoriteTagItem item) { Log.TraceFunction(); var favHelper = Utility.GetFavoritesHelper(); favHelper.RemoveFavoriteTag(item); UIHelper.RefreshFavoriteTags(); } public static void ShowFileInExplorer(string filename=null) { Log.TraceFunction(); if (filename != null) { Log.Debug("===== trying to open " + filename + " in explorer"); Process.Start("explorer.exe", "/select, " + filename); } } public static void CheckoutAndOpenFile(ListingItem item) { Log.TraceFunction(); if (item is FileItem) { var fileItem = item as FileItem; var main = App.Current.MainWindow as MainWindow; var waitDialog = main.DialogManager.CreateWaitDialog(string.Format("Opening {0}...", item.LabelText), DialogMode.None); waitDialog.HorizontalDialogAlignment = HorizontalAlignment.Center; waitDialog.VerticalDialogAlignment = VerticalAlignment.Top; waitDialog.Show(() => { if (fileItem.Metadata != null && fileItem.Metadata.Action == FileAction.None) { CheckoutFiles(items: item); } else { System.IO.File.SetAttributes(item.ClientPath, FileAttributes.Normal); } var count = 0; while (count < 100 && IsFileLocked(item.ClientPath)) { count++; Thread.Sleep(100); } OpenLocalFile(item.ClientPath); }); } } public static void CheckoutFiles(bool serverOnly=false, params ListingItem[] items) { Log.TraceFunction(); if (items != null && items.Length > 0) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { paths.Add(item.ClientPath); } else { paths.Add(item.ClientPath + "/..."); } } var result = helper.CheckoutFiles(serverOnly, paths.ToArray()); UIHelper.RefreshSelectorAsync(SELECTOR_TYPE.PENDING); } } public static void AddFiles(params ListingItem[] items) { Log.TraceFunction(); UIHelper.SetBusyState(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { paths.Add(item.ClientPath); } else { paths.Add(item.DepotPath + "/..."); } } helper.MarkFileForAdd(paths.ToArray()); UIHelper.RefreshSelector(SELECTOR_TYPE.PENDING); } } public static void RevertFiles(params ListingItem[] items) { Log.TraceFunction(); UIHelper.SetBusyState(); Utility.StopBackgroundProcesses(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { paths.Add(item.ClientPath); } else { paths.Add(item.ClientPath + "/..."); } } helper.RevertFiles(serverOnly: false, paths: paths.ToArray()); UIHelper.RefreshSelector(SELECTOR_TYPE.PENDING); UIHelper.RefreshSelector(SELECTOR_TYPE.TRASH); } Utility.StartBackgroundProcesses(); } public static void DeleteFiles(params ListingItem[] items) { Log.TraceFunction(); UIHelper.SetBusyState(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); var path = string.Empty; foreach (var item in items) { if (item is FileItem) { if ((item as FileItem).Metadata.Action != FileAction.None) { RevertFiles(item); } path = item.ClientPath; } else { path = item.ClientPath + "/..."; if (helper.PathHasAnyOpened(path)) { var message = new StringBuilder(); message.AppendFormat("Unable to delete {0}\n", item.LabelText); message.AppendLine("There are files that are opened by other users"); UIHelper.ShowMessage(message.ToString()); paths.Clear(); break; } } paths.Add(path); } if (paths.Count > 0) { var deleted = helper.DeleteFiles(serverOnly: true, paths: paths.ToArray()); foreach (var item in items) { if (item is FileItem && System.IO.File.Exists(item.ClientPath)) { ForceDeleteFile(item.ClientPath); } else if (System.IO.Directory.Exists(item.ClientPath)) { ForceDeleteDirectory(item.ClientPath); } } UIHelper.RefreshCurrent(); UIHelper.RefreshSelector(SELECTOR_TYPE.TRASH); } } } public static void ForceDeleteFile(string path) { Log.TraceFunction(); System.IO.File.SetAttributes(path, FileAttributes.Normal); System.IO.File.Delete(path); } public static void ForceDeleteDirectory(string path) { Log.TraceFunction(); DirectoryInfo root; Stack fols; DirectoryInfo fol; fols = new Stack(); root = new DirectoryInfo(path); fols.Push(root); while (fols.Count > 0) { fol = fols.Pop(); fol.Attributes = fol.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden); foreach (DirectoryInfo d in fol.GetDirectories()) { fols.Push(d); } foreach (FileInfo f in fol.GetFiles()) { f.Attributes = f.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden); f.Delete(); } } root.Delete(true); } public static P4CommandResult ReconcileFiles(params ListingItem[] items) { Log.TraceFunction(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { paths.Add(item.ClientPath); } else { paths.Add(item.ClientPath + "/..."); } } return helper.ReconcileFiles(paths.ToArray()); } else { return null; } } public static void ShelveFiles(params ListingItem[] items) { Log.TraceFunction(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { paths.Add(item.DepotPath); } else { paths.Add(item.DepotPath + "/..."); } } helper.ShelveFiles(paths.ToArray()); } } public static void UnshelveFiles(params ListingItem[] items) { Log.TraceFunction(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { var shelvedChangeIds = helper.GetShelvedLocations(item.DepotPath); shelvedChangeIds.Sort(); if (shelvedChangeIds != null && shelvedChangeIds.Count > 0) { // unshelve the file in the most recent changetlist helper.UnshelveFiles(changeId: shelvedChangeIds[shelvedChangeIds.Count - 1], paths: item.DepotPath); // clean up older shelved items for(int i=0; i < shelvedChangeIds.Count - 1; i++) { helper.DeleteShelvedFiles(changeId: shelvedChangeIds[i], paths: item.DepotPath); } } } else { paths.Add(item.DepotPath + "/..."); } } if (paths.Count > 0) { helper.UnshelveFiles(paths: paths.ToArray()); } } } public static void DeleteShelvedFiles(params ListingItem[] items) { Log.TraceFunction(); if (items != null) { var helper = Utility.GetPerforceHelper(); var paths = new List(); foreach (var item in items) { if (item is FileItem) { var shelvedChangeIds = helper.GetShelvedLocations(item.DepotPath); if (shelvedChangeIds != null && shelvedChangeIds.Count > 0) { foreach (var id in shelvedChangeIds) { helper.DeleteShelvedFiles(changeId: id, paths: item.DepotPath); } } } else { paths.Add(item.DepotPath + "/..."); } } if (paths.Count > 0) { helper.DeleteShelvedFiles(paths: paths.ToArray()); } } } public static void SyncWorkspace() { Log.TraceFunction(); var p4 = Utility.GetPerforceHelper(); UIHelper.SetBusyState(); p4.RunSync("//..."); } public static void SubmitChangelist(int changeId = 0, string[] selected = null) { Log.TraceFunction(); UIHelper.SetBusyState(); Utility.StopBackgroundProcesses(); var helper = Utility.GetPerforceHelper(); helper.CleanChangelist(); var main = App.Current.MainWindow as MainWindow; var form = new SubmitForm(changeId, selected); var dialog = main.DialogManager.CreateCustomContentDialog(form, Technewlogic.WpfDialogManagement.DialogMode.OkCancel); dialog.OkText = "Submit"; dialog.CanOk = false; dialog.Ok = () => { OnSubmit(form); }; dialog.Cancel = () => { Utility.StartBackgroundProcesses(); }; dialog.VerticalDialogAlignment = VerticalAlignment.Top; dialog.HorizontalDialogAlignment = HorizontalAlignment.Center; form.ParentDialog = dialog; dialog.Show(); form.RefreshForm(); } public static void SubmitItems(params ListingItem[] selectedItems) { Log.TraceFunction(); var helper = Utility.GetPerforceHelper(); var selected = new List(); if (selectedItems != null && selectedItems.Length > 0) { foreach (var itm in selectedItems) { if (itm is FolderItem) { var currentChangelist = helper.GetCurrentPendingChangelist(); if (currentChangelist != null && currentChangelist.Files != null && currentChangelist.Files.Count > 0) { var folderPath = itm.DepotPath; foreach (var f in currentChangelist.Files) { if (f.DepotPath.Path.StartsWith(folderPath)) { if (!selected.Contains(f.DepotPath.Path)) { selected.Add(f.DepotPath.Path); } if (f.Action == FileAction.MoveAdd) { var detail = helper.RunFstat(f.DepotPath.Path); if (detail.MovedFile != null && !selected.Contains(detail.MovedFile.Path)) { selected.Add(detail.MovedFile.Path); } } } else if (f.Action == FileAction.MoveAdd) { var detail = helper.RunFstat(f.DepotPath.Path); if (detail.MovedFile != null && detail.MovedFile.Path.StartsWith(folderPath)) { selected.Add(f.DepotPath.Path); selected.Add(detail.MovedFile.Path); } } } } } else { if(!selected.Contains(itm.DepotPath)) { selected.Add(itm.DepotPath); } var md = helper.RunFstat(itm.DepotPath); if (md.Action == FileAction.MoveAdd) { if (!selected.Contains(md.MovedFile.Path)) { selected.Add(md.MovedFile.Path); } } else if (md.Action == FileAction.MoveDelete) { if (!selected.Contains(md.MovedFile.Path)) { selected.Add(md.MovedFile.Path); } } } } } if (selected.Count > 0) { SubmitChangelist(selected: selected.ToArray()); } } public static void SubmitFile(ListingItem item) { Log.TraceFunction(); var fileitem = item as FileItem; if (fileitem != null) { var selected = new List(); selected.Add(item.DepotPath); if (fileitem.Metadata.Action == FileAction.MoveAdd) { selected.Add(fileitem.Metadata.MovedFile.Path); } SubmitChangelist(selected: selected.ToArray()); } } public static void SubmitFolder(FolderItem folder) { Log.TraceFunction(); var helper = Utility.GetPerforceHelper(); var currentChangelist = helper.GetCurrentPendingChangelist(); if (currentChangelist != null && currentChangelist.Files != null && currentChangelist.Files.Count > 0) { var folderPath = folder.DepotPath; var selected = new List(); foreach (var f in currentChangelist.Files) { if (f.DepotPath.Path.StartsWith(folderPath)) { if (!selected.Contains(f.DepotPath.Path)) { selected.Add(f.DepotPath.Path); } if(f.Action == FileAction.MoveAdd) { var detail = helper.RunFstat(f.DepotPath.Path); if(detail.MovedFile != null && !selected.Contains(detail.MovedFile.Path)) { selected.Add(detail.MovedFile.Path); } } } else if (f.Action == FileAction.MoveAdd) { var detail = helper.RunFstat(f.DepotPath.Path); if(detail.MovedFile != null && detail.MovedFile.Path.StartsWith(folderPath)) { selected.Add(f.DepotPath.Path); selected.Add(detail.MovedFile.Path); } } } SubmitChangelist(selected: selected.ToArray()); } } public static void OnSubmit(SubmitForm form) { Log.TraceFunction(); var main = App.Current.MainWindow as MainWindow; var helper = Utility.GetPerforceHelper(); var currentChangelist = helper.GetCurrentPendingChangelist(); var files = new List(); foreach (var f in form.Model.ChangelistFiles) { if (f.Selected) { files.Add(f.Path); } } if (files.Count > 0) { var newChangelist = helper.CreateChangelist(form.DescriptionText.Text.Trim()); helper.MoveFilesToNewChangelist(files, newChangelist.Id); currentChangelist = helper.GetChangelist(currentChangelist.Id); newChangelist = helper.GetChangelist(newChangelist.Id); var waitDialog = main.DialogManager.CreateWaitDialog("Submitting files to server...", "Submit Complete", DialogMode.Ok); waitDialog.HorizontalDialogAlignment = HorizontalAlignment.Center; waitDialog.VerticalDialogAlignment = VerticalAlignment.Top; waitDialog.CanOk = false; waitDialog.Show(() => { var results = helper.SubmitChangelist(newChangelist); if (results != null && !results.HasError) { var changeIdAfterSubmit = -1; if (results.Results != null) { changeIdAfterSubmit = results.Results.ChangeIdAfterSubmit; } // only display change dialog if files were submitted if (changeIdAfterSubmit > 0) { // files were submitted... clean up any shelved files foreach (var sf in results.Results.Files) { var shelvedChangeIds = helper.GetShelvedLocations(sf.File.DepotPath.Path); if (shelvedChangeIds != null && shelvedChangeIds.Count > 0) { foreach (var id in shelvedChangeIds) { helper.DeleteShelvedFiles(changeId: id, paths: sf.File.DepotPath.Path); } } } waitDialog.ReadyMessage = string.Format("Files submitted as change @{0}", changeIdAfterSubmit); } else { waitDialog.ReadyMessage = "No files were changed."; // clean up the empty changelist helper.DeleteChangelist(newChangelist.Id); } } else if (results != null && results.HasError) { waitDialog.ReadyMessage = string.Format("SUBMIT ERROR:\n\n {0}", results.Message); // error in submitting... move files back to original changelist helper.MoveFilesToNewChangelist(files, currentChangelist.Id); helper.DeleteChangelist(newChangelist.Id); } else { waitDialog.ReadyMessage = "SUBMIT FAILED: returned null"; } waitDialog.CanOk = true; Utility.StartBackgroundProcesses(); }); } } // while this method is called "MoveLocalFiles", it will actually perform a copy // if the source and destination are on different volumes public static void MoveLocalFiles(string[] paths, string targetDir) { Log.TraceFunction(); foreach (var p in paths) { if(IsDirectory(p)) { var d = new DirectoryInfo(p).Name; var t = Path.Combine(targetDir, d); var dRoot = new DirectoryInfo(p).Root; var tRoot = new DirectoryInfo(t).Root; if (dRoot.Equals(tRoot)) { Directory.Move(p, t); } else { Utility.CopyDirectory(p, t); } } else { var f = Path.GetFileName(p); var fRoot = Path.GetPathRoot(p); var t = Path.Combine(targetDir, f); var tRoot = Path.GetPathRoot(t); if (fRoot.Equals(tRoot)) { System.IO.File.Move(p, t); } else { System.IO.File.Copy(p, t); } } } } private static bool IsDirectory(string path) { Log.TraceFunction(); var fa = System.IO.File.GetAttributes(path); bool isDirectory = false; if ((fa & FileAttributes.Directory) != 0) { isDirectory = true; } return isDirectory; } } }