namespace P4VSNetAddIn { using System; using System.IO; using System.Collections; using Microsoft.Office.Core; using Extensibility; using System.Runtime.InteropServices; using EnvDTE; using Microsoft.VisualStudio.VCProjectEngine; using System.Diagnostics; #region Read me for Add-in installation and setup information. #endregion /// /// The object for implementing an Add-in. /// /// [GuidAttribute("38F5632B-809F-4B7E-B3ED-580665020BC1"), ProgId("P4VSNetAddIn.Connect")] public class Connect : Object, IDTExtensibility2, IDTCommandTarget { /// /// Implements the constructor for the Add-in object. /// Place your initialization code within this method. /// public Connect() { } /// /// Implements the OnConnection method of the IDTExtensibility2 interface. /// Receives notification that the Add-in is being loaded. /// /// /// Root object of the host application. /// /// /// Describes how the Add-in is being loaded. /// /// /// Object representing this Add-in. /// /// public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) { applicationObject = (_DTE)application; addInInstance = (AddIn)addInInst; OutputWindow outputWindow = (OutputWindow)applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object; outputWindowPane = outputWindow.OutputWindowPanes.Add("Perforce"); //outputWindowPane.OutputString("Connect\n"); lastProjectItemAdded = DateTime.Now; try { if(connectMode == Extensibility.ext_ConnectMode.ext_cm_UISetup) AddGUIElements(addInInst); RegisterSolutionEvents(); } catch (SystemException e) { outputWindowPane.OutputString (e.ToString() + "\n"); } //outputWindowPane.OutputString("Done with connect\n"); } private void AddGUIElements(object addInInst) { //outputWindowPane.OutputString("Adding GUI\n"); object []contextGUIDS = new object[] { }; AddIn objAddIn = (AddIn)addInInst; commandEdit = applicationObject.Commands.AddNamedCommand( objAddIn, "P4EditItem", "P4 edit", "Opens item for edit", true, 0, ref contextGUIDS, 1 + 2); //1+2 == vsCommandStatusSupported+vsCommandStatusEnabled commandEdit.AddControl(applicationObject.CommandBars["Item"], 3); commandEdit.AddControl(applicationObject.CommandBars["Project"], 3); commandEdit.AddControl(applicationObject.CommandBars["Solution"], 7); // This only works if we have some custom keybindings try { commandEdit.Bindings = "Global::ctrl+shift+enter"; } catch (SystemException) { } commandRevert = applicationObject.Commands.AddNamedCommand( objAddIn, "P4Revert", "P4 revert", "Reverts the a document opened for edit", true, 0, ref contextGUIDS, 1 + 2); commandDiff = applicationObject.Commands.AddNamedCommand( objAddIn, "P4Diff", "P4 diff", "Diffs the item against the head of the depot", true, 0, ref contextGUIDS, 1 + 2); commandDiff.AddControl(applicationObject.CommandBars["Item"], 4); commandDiff.AddControl(applicationObject.CommandBars["Project"], 4); commandDiff.AddControl(applicationObject.CommandBars["Solution"], 8); commandBar = (CommandBar)applicationObject.Commands.AddCommandBar("P4", vsCommandBarType.vsCommandBarTypeToolbar, null, 1); commandEdit.AddControl(commandBar,1); commandDiff.AddControl(commandBar,2); commandRevert.AddControl(commandBar,3); //outputWindowPane.OutputString("Done adding GUI\n"); } /// /// Implements the OnDisconnection method of the IDTExtensibility2 interface. /// Receives notification that the Add-in is being unloaded. /// /// /// Describes how the Add-in is being unloaded. /// /// /// Array of parameters that are host application specific. /// /// public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom) { UnregisterSolutionEvents(); } private void RegisterSolutionEvents() { solutionEvents = (EnvDTE.SolutionEvents)applicationObject.Events.SolutionEvents; solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(this.SolutionOpened); solutionEvents.BeforeClosing += new _dispSolutionEvents_BeforeClosingEventHandler(this.SolutionClosed); } private void UnregisterSolutionEvents() { if (solutionEvents != null) { solutionEvents.Opened -= new _dispSolutionEvents_OpenedEventHandler(this.SolutionOpened); solutionEvents.BeforeClosing -= new _dispSolutionEvents_BeforeClosingEventHandler(this.SolutionClosed); } } /// /// Implements the OnAddInsUpdate method of the IDTExtensibility2 interface. /// Receives notification that the collection of Add-ins has changed. /// /// /// Array of parameters that are host application specific. /// /// public void OnAddInsUpdate(ref System.Array custom) { } /// /// Implements the OnStartupComplete method of the IDTExtensibility2 interface. /// Receives notification that the host application has completed loading. /// /// /// Array of parameters that are host application specific. /// /// public void OnStartupComplete(ref System.Array custom) { } /// /// Implements the OnBeginShutdown method of the IDTExtensibility2 interface. /// Receives notification that the host application is being unloaded. /// /// /// Array of parameters that are host application specific. /// /// public void OnBeginShutdown(ref System.Array custom) { } public void Exec(string commandName, vsCommandExecOption executeOption, ref object VariantIn, ref object VariantOut, ref bool handled) { handled = true; if(executeOption == EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault) { ArrayList selectedItems = new ArrayList(); GetSelectedItems(ref selectedItems); System.Collections.IEnumerator myEnumerator = selectedItems.GetEnumerator(); while ( myEnumerator.MoveNext() ) { string itemName = (string)myEnumerator.Current; //outputWindowPane.OutputString("Processing item: " + itemName + "\n"); if (itemName == "") continue; if (commandName == "P4VSNetAddIn.Connect.P4EditItem") { ActivatePerforceWindow(); ExecuteCommand("p4", "edit \"" + itemName + "\"", Path.GetDirectoryName(itemName)); RestoreActiveWindow(); } else if (commandName == "P4VSNetAddIn.Connect.P4Revert") { ActivatePerforceWindow(); ExecuteCommand("p4", "revert \"" + itemName + "\"", Path.GetDirectoryName(itemName)); RestoreActiveWindow(); } else if (commandName == "P4VSNetAddIn.Connect.P4Diff") { ActivatePerforceWindow(); ExecuteCommand("p4", "diff \"" + itemName + "\"", Path.GetDirectoryName(itemName)); RestoreActiveWindow(); } else { outputWindowPane.OutputString("Unhandled command " + commandName + "\n"); handled = false; } } } } private void GetSelectedItems (ref ArrayList selectedItems) { Window win = applicationObject.ActiveWindow; if (win == null || win == applicationObject.Windows.Item(Constants.vsWindowKindSolutionExplorer)) GetSelectedItemsInSolutionTree(ref selectedItems); else GetSelectedWindow(ref selectedItems); } private void GetSelectedWindow (ref ArrayList selectedItems) { Window win = applicationObject.ActiveWindow; Document doc = win.Document; if (doc != null) selectedItems.Add(doc.FullName); } private void GetSelectedItemsInSolutionTree (ref ArrayList selectedItems) { int count = applicationObject.SelectedItems.Count; for (int i = 1; i <= count; i++) { SelectedItem selectedItem = applicationObject.SelectedItems.Item(i); selectedItems.Add(GetFullSolutionItemName(selectedItem)); } } private string GetFullSolutionItemName (SelectedItem item) { ProjectItem projectItem = item.ProjectItem; if (projectItem != null) return projectItem.get_FileNames(1); Project project = item.Project; if (project != null) return project.FullName; // Must have been the solution return applicationObject.Solution.FullName; } public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object CommandText) { if (neededText == EnvDTE.vsCommandStatusTextWanted.vsCommandStatusTextWantedNone) { if (commandName == "P4VSNetAddIn.Connect.P4EditItem" || commandName == "P4VSNetAddIn.Connect.P4Revert" || commandName == "P4VSNetAddIn.Connect.P4Diff") { status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled; } } } public void SolutionOpened() { //outputWindowPane.OutputString("Solution opened\n"); VCProjectItem item = (VCProjectItem )applicationObject.Solution.Projects.Item(1).Object; VCProjectEngine projEngine = (VCProjectEngine)item.VCProjectEngine; vcprojectEvents = (VCProjectEngineEvents)projEngine.Events; vcprojectEvents.ItemAdded += new _dispVCProjectEngineEvents_ItemAddedEventHandler (this.ProjectItemAdded); vcprojectEvents.ItemRemoved += new _dispVCProjectEngineEvents_ItemRemovedEventHandler (this.ProjectItemRemoved); } public void SolutionClosed() { //outputWindowPane.OutputString("Solution closed\n"); if (vcprojectEvents != null) { vcprojectEvents.ItemAdded -= new _dispVCProjectEngineEvents_ItemAddedEventHandler (this.ProjectItemAdded); vcprojectEvents.ItemRemoved -= new _dispVCProjectEngineEvents_ItemRemovedEventHandler (this.ProjectItemRemoved); } } public void ProjectItemAdded (object item, object parent) { outputWindowPane.OutputString("Project item added\n"); // Make sure that a least a second has gone by since the last add of a project item DateTime currentTime = DateTime.Now; System.TimeSpan diff = currentTime.Subtract(lastProjectItemAdded); if (diff.Seconds <= 1) { lastProjectItemAdded = currentTime; return; } VCFile file = item as VCFile; if (file != null) { ActivatePerforceWindow(); ExecuteCommand("p4", "add " + file.FullPath, Path.GetDirectoryName(file.FullPath)); RestoreActiveWindow(); } else { VCProject project = item as VCProject; if (project != null) { outputWindowPane.OutputString("Added project " + project.Name + "\n"); lastProjectItemAdded = DateTime.Now; } else outputWindowPane.OutputString("Unknown project item added\n"); } } public void ProjectItemRemoved (object item, object parent) { outputWindowPane.OutputString("Project item removed\n"); VCFile file = item as VCFile; if (file == null) return; ActivatePerforceWindow(); ExecuteCommand("p4", "delete " + file.FullPath, Path.GetDirectoryName(file.FullPath)); RestoreActiveWindow(); } private void ActivatePerforceWindow () { activeWindow = applicationObject.ActiveWindow; outputWindowPane.Activate(); OutputWindow outputWindow = (OutputWindow)applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object; outputWindow.Parent.Activate(); } private void RestoreActiveWindow () { activeWindow.Activate(); } private bool ExecuteCommand (string command, string arguments, string workingPath) { ProcessStartInfo pi = new ProcessStartInfo(command, arguments); pi.CreateNoWindow = true; pi.RedirectStandardOutput = true; pi.RedirectStandardError = true; pi.UseShellExecute = false; pi.WorkingDirectory = workingPath; outputWindowPane.OutputString(command + " " + pi.Arguments + "\n"); System.Diagnostics.Process process = System.Diagnostics.Process.Start (pi); process.WaitForExit(); outputWindowPane.OutputString (process.StandardOutput.ReadToEnd()); outputWindowPane.OutputString (process.StandardError.ReadToEnd()); return (process.ExitCode == 0); } private _DTE applicationObject; private AddIn addInInstance; private Command commandEdit; private Command commandRevert; private Command commandDiff; private CommandBar commandBar; private EnvDTE.SolutionEvents solutionEvents; private VCProjectEngineEvents vcprojectEvents; private DateTime lastProjectItemAdded; private Window activeWindow; static private OutputWindowPane outputWindowPane; } }