//
// Copyright 2014 Perforce Software Inc.
//
using Perforce.Model;
using Perforce.View;
using Perforce.ViewModel;
using Microsoft.Win32;
using Perforce.P4;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
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) {
var helper = Utility.GetPerforceHelper();
var filename = helper.GetFileFromShelf(depotPath);
OpenLocalFile(filename);
}
public static void OpenFileFromServer(string depotPath=null, int revision = -1) {
var helper = Utility.GetPerforceHelper();
var filename = helper.GetFileFromServer(depotPath, revision);
OpenLocalFile(filename);
}
public static void OpenLocalFile(string filename=null) {
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) {
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) {
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 Piper:
{1}", user.FullName, referenceFile);
//Set a high priority to the message
mailItem.Importance = OlImportance.olImportanceHigh;
mailItem.Display();
}
}
public static void AddToFavorites(ListingItem item) {
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) {
var favHelper = Utility.GetFavoritesHelper();
favHelper.RemoveFavorite(item);
UIHelper.RefreshFavorites();
}
public static void RemoveFromTags(FavoriteTagItem item) {
var favHelper = Utility.GetFavoritesHelper();
favHelper.RemoveFavoriteTag(item);
UIHelper.RefreshFavoriteTags();
}
public static void ShowFileInExplorer(string filename=null) {
if (filename != null) {
Console.WriteLine("===== trying to open " + filename + " in explorer");
Process.Start("explorer.exe", "/select, " + filename);
}
}
public static void CheckoutAndOpenFile(ListingItem item) {
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) {
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.DepotPath);
} else {
paths.Add(item.DepotPath + "/...");
}
}
var result = helper.CheckoutFiles(serverOnly, paths.ToArray());
UIHelper.RefreshSelectorAsync(SELECTOR_TYPE.PENDING);
}
}
public static void AddFiles(params ListingItem[] items) {
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) {
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.DepotPath);
} else {
paths.Add(item.DepotPath + "/...");
}
}
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) {
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.DepotPath;
} else {
path = item.DepotPath + "/...";
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) {
System.IO.File.SetAttributes(path, FileAttributes.Normal);
System.IO.File.Delete(path);
}
public static void ForceDeleteDirectory(string path) {
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) {
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 + "/...");
}
}
return helper.ReconcileFiles(paths.ToArray());
} else {
return null;
}
}
public static void ShelveFiles(params ListingItem[] items) {
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) {
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) {
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() {
var helper = Utility.GetPerforceHelper();
UIHelper.SetBusyState();
helper.SyncWorkspaceFiles();
}
public static void SubmitChangelist(int changeId = 0, string[] selected = null) {
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;
form.ParentDialog = dialog;
dialog.Show();
form.RefreshForm();
}
public static void SubmitItems(params ListingItem[] selectedItems) {
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.GetFileMetaData(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.GetFileMetaData(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.GetFileMetaData(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) {
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) {
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.GetFileMetaData(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.GetFileMetaData(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) {
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) {
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) {
var fa = System.IO.File.GetAttributes(path);
bool isDirectory = false;
if ((fa & FileAttributes.Directory) != 0) {
isDirectory = true;
}
return isDirectory;
}
}
}