using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
namespace VisualStudio.AddInLibrary.Menus
{
/// <summary>
/// Base class for implementing a menu item AKA Command
/// </summary>
public abstract class BaseMenu
{
#region Properties
/// <summary>
/// The kind of menu we want to create
/// </summary>
protected MenuType MainMenuType { get; set; }
/// <summary>
/// Visual Studio instance
/// </summary>
public DTE2 VStudioApplication { get; set; }
/// <summary>
/// AddIn instance
/// </summary>
public AddIn AddInInstance { get; set; }
/// <summary>
/// Assembly containing our resources
/// </summary>
protected System.Reflection.Assembly ResourceAssembly { get; set; }
#endregion
#region Member variables
/// <summary>
/// STATIC List containing Menu items AND asscociated Commands
/// </summary>
private static Dictionary<string, VSCommandInfo> CommandDescriptionList = new Dictionary<string, VSCommandInfo>();
/// <summary>
/// the popup menu object we created if we choose MenuType.Popup
/// </summary>
private CommandBarPopup m_Popup =null;
protected ResourceManager ResourceMANAGER = null;
#endregion
/// <summary>
/// Constructor
/// </summary>
/// <param name="BaseMenuParams">Paremeter class containing add-in instance, VS instance ...</param>
public BaseMenu(BaseMenuParams _params)
{
VStudioApplication = _params.VisualStudioInstance;
AddInInstance = _params.AddInInstance;
ResourceAssembly = _params.ResourceAssembly;
ResourceMANAGER = new ResourceManager(ResourceAssembly.GetName().Name + ".Resources", ResourceAssembly);
}
/// <summary>
/// Add a command object to our command list
/// </summary>
/// <param name="item">the menu we want to add</param>
protected void AddCommand(VSCommandInfo item)
{
string cmdId = AddInInstance.ProgID + "." + item.Name;
if (!CommandDescriptionList.ContainsKey(cmdId))
{
item.UniqueID = cmdId;
CommandDescriptionList.Add(cmdId, item);
}
else
MessageBox.Show(cmdId + " already exists in this plugin !", "Error : " + AddInInstance.ProgID, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
/// <summary>
/// clear our command list
/// </summary>
protected void ClearCommands(object owner)
{
foreach (KeyValuePair<string, VSCommandInfo> kvp in CommandDescriptionList)
{
VSCommandInfo desc = kvp.Value;
if (desc.Owner == owner || desc.Owner==null)
CommandDescriptionList.Remove(kvp.Key);
}
}
/// <summary>
/// Remove our menus from VStudio
/// </summary>
protected void RemoveMenu(object owner)
{
try
{
if (m_Popup != null)
m_Popup.Delete(true);
else
{
foreach (KeyValuePair<string, VSCommandInfo> kvp in CommandDescriptionList)
{
VSCommandInfo desc = kvp.Value;
if ((desc.Owner==owner || desc.Owner==null) && desc.Control != null)
{
desc.Control.Delete(true);
desc.Control = null;
}
}
}
m_Popup = null;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Return null OR a Visual Studio Command Bar (context menus too)
/// </summary>
/// <param name="commandBarName"></param>
/// <returns></returns>
private CommandBar GetVisualStudioCommandBar(bool IsOnMainMenu, string commandBarName)
{
string MyMenu=commandBarName;
if (ResourceAssembly == null)
{
MessageBox.Show("The \"ResourceAssembly\" property is not defined\nin derived class \"" + this.GetType().Name + " \" !", "VisualStudio.AddInLibrary : ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
try
{
string resourceName = ResourceAssembly.GetName().Name + ".CommandBar";
ResourceManager resourceManager = new ResourceManager(resourceName,ResourceAssembly);
CultureInfo cultureInfo = new CultureInfo(VStudioApplication.LocaleID);
MyMenu = resourceManager.GetString(String.Concat(cultureInfo.TwoLetterISOLanguageName, MyMenu));
if (String.IsNullOrEmpty(MyMenu))
MyMenu = commandBarName;
}
catch
{
MyMenu = commandBarName;
}
try
{
if (IsOnMainMenu)
{
CommandBar menuBar = ((CommandBars)VStudioApplication.CommandBars)["MenuBar"];
if (menuBar != null)
{
CommandBarControl ctl = menuBar.Controls[MyMenu];
if (ctl != null)
{
CommandBarPopup pop = (CommandBarPopup)ctl;
if (pop != null)
return pop.CommandBar;
}
}
}
else
return ((CommandBars)VStudioApplication.DTE.CommandBars)[MyMenu];
}
catch(Exception ex)
{
MessageBox.Show("Error while attaching to main menu \"" + MyMenu +"\" !"+ ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
return null;
}
/// <summary>
/// Main entry point for creating Menus with SubMenus
/// </summary>
/// <param name="MainMenuToAttach">Parent menu to attach to</param>
/// <param name="SubMenu">Our Menu name</param>
/// <param name="t">Menu type (popup, classic ...) </param>
/// <param name="position">Our position</param>
/// <param name="separator">need separator ?</param>
/// <returns></returns>
protected bool AddMenu(object owner,string MainMenuToAttach,bool IsOnMainMenu, string SubMenu, MenuType t, int position, bool separator)
{
bool ret = false;
CommandBar _commandBar = GetVisualStudioCommandBar(IsOnMainMenu,MainMenuToAttach);
MainMenuType = t;
if (_commandBar != null)
{
CommandBarControl ctl = (CommandBarControl)(_commandBar.FindControl(Missing.Value, Missing.Value, SubMenu, Missing.Value, Missing.Value));
if (ctl != null) ctl.Delete(true);
switch (MainMenuType)
{
case MenuType.Popup:
CommandBarPopup popup = CreatePopupMenu(_commandBar, SubMenu, position, separator);
m_Popup = popup;
BuildMenuItems(owner,true,popup,null);
ret = true;
break;
case MenuType.Default:
BuildMenuItems(owner,false,null,_commandBar);
ret = true;
break;
case MenuType.Unknown:
break;
}
}
return ret;
}
/// <summary>
/// Create Menu / Sub-menus / Events ...
/// </summary>
protected void BuildMenuItems(object owner,bool isPopup, CommandBarPopup popup,CommandBar cmd)
{
foreach (KeyValuePair<string, VSCommandInfo> kvp in CommandDescriptionList)
{
VSCommandInfo desc = kvp.Value;
if (desc.Owner == owner || desc.Owner == null)
AddMenuItem(owner, isPopup,popup,cmd, desc);
}
}
/// <summary>
/// Create a popup menu linked to an existing menu
/// </summary>
/// <param name="cmd">Main command bar to attach to</param>
/// <param name="subPopupMenuName">Menu name in command bar</param>
/// <param name="position">position in command bar</param>
/// <param name="separator">is there a separator for our item in the command bar ?</param>
/// <returns></returns>
public CommandBarPopup CreatePopupMenu(CommandBar cmd, string subPopupMenuName, int position, bool separator)
{
if (position < 0) position = 1;
if (position > cmd.Controls.Count) position = cmd.Controls.Count - 1;
if (cmd.Controls.Count <= 0) position = 1;
CommandBarPopup menu = (CommandBarPopup)cmd.Controls.Add(MsoControlType.msoControlPopup, 1, "", position, true);
menu.Caption = subPopupMenuName;
menu.TooltipText = "";
if (separator) menu.BeginGroup = true;
return menu;
}
/// <summary>
/// Add a sub-menu item in our popup menu / vs menu
/// </summary>
/// <param name="parent">menu where we add items</param>
/// <param name="desc">the command object informations</param>
/// <returns></returns>
private void AddMenuItem(object owner, bool ispopup, CommandBarPopup popup, CommandBar cmd, VSCommandInfo desc)
{
if (popup == null && cmd==null) return ;
if (desc == null) return ;
CommandBarControl ctl = null;
try
{
object[] contextGUIDS = new object[] { };
Commands2 commands = (Commands2)VStudioApplication.Commands;
// checks existing command and delete it if necessary
try
{
if (desc.Owner == owner || desc.Owner == null)
{
Command test = VStudioApplication.Commands.Item(desc.UniqueID, -1);
if (test != null)
test.Delete();
}
}
catch
{
}
int idRes= desc.BitmapResourceId;
bool useOffice = desc.UseOfficeResources;
if (idRes <= 0)
{
idRes = 59;
useOffice = true;
}
Command command = commands.AddNamedCommand2(AddInInstance, desc.Name, desc.Caption, desc.ToolTip, useOffice, idRes, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
if (ispopup)
{
if (desc.Position == 0) desc.Position = popup.Controls.Count + 1;
ctl= (CommandBarControl) command.AddControl(popup.CommandBar, desc.Position);
}
else
{
if (desc.Position == 0) desc.Position = cmd.Controls.Count + 1;
ctl = (CommandBarControl)command.AddControl(cmd, desc.Position);
}
desc.Control = ctl;
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Adding Sub-Item : " + desc.Caption);
}
}
/// <summary>
/// check if command name is found in our internal list
/// </summary>
/// <param name="commandName"></param>
/// <returns></returns>
protected bool CommandExists(string commandName)
{
return CommandDescriptionList.ContainsKey(commandName);
}
/// <summary>
/// Check if the command belongs to owner
/// </summary>
/// <param name="owner">object instance asking information</param>
/// <param name="commandName">the command name</param>
/// <returns>True if command belongs to owner</returns>
protected bool IsItMyCommand(object owner, string commandName)
{
bool ret = false;
if (CommandExists(commandName))
{
VSCommandInfo desc = CommandDescriptionList[commandName];
return (desc.Owner==owner) ;
}
return ret;
}
/// <summary>
/// Find a command and returns infomations about it
/// </summary>
/// <param name="commandName">the command name</param>
/// <returns>CommandDescription</returns>
protected VSCommandInfo GetCommand(string commandName)
{
VSCommandInfo ret = null;
if (CommandExists(commandName))
return CommandDescriptionList[commandName];
return ret;
}
/// <summary>
/// Executes the code associated with a command
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public virtual bool Exec(string command)
{
bool ret = false;
VSCommandInfo cmd = GetCommand(command);
if (cmd!=null)
{
PerformActionForVSCommandDelegate action = cmd.Action;
if (action != null)
{
action();
ret = true;
}
}
return ret;
}
/// <summary>
/// Translate VS commandStatus to "readable" state
/// </summary>
/// <param name="NeededText"></param>
/// <returns></returns>
protected QueryMenuVSCommandStatus TranslateCommandState(vsCommandStatusTextWanted NeededText)
{
QueryMenuVSCommandStatus status = QueryMenuVSCommandStatus.Unknown;
switch (NeededText)
{
case vsCommandStatusTextWanted.vsCommandStatusTextWantedStatus:
status=QueryMenuVSCommandStatus.Step1_BeforeDisplay;
break;
case vsCommandStatusTextWanted.vsCommandStatusTextWantedName:
status=QueryMenuVSCommandStatus.Step2_GetText;
break;
case vsCommandStatusTextWanted.vsCommandStatusTextWantedNone:
status=QueryMenuVSCommandStatus.Step3_FinalState;
break;
}
return status;
}
}
}