How to customize the context menu in the solution explorer for a specific project type? - vsix

Description
I have developed a Visual Studio extension (VSPackage) which adds a new Project Type to Visual Studio (using CPS Project System). I also have added some Commands to the VSPackage.
When right clicking on my Project Node in the Solution Explorer, I want to have a customized context menu to appear.
Example
For example: in the screen shot below, I want to get rid of the Build command and add a custom command (e.x. mycommand).
I tried..
Setting the Parent of my custom command to IDM_VS_CTXT_PROJNODE.
Question
When I create a new Custom Project Type, How to create a new Context Menu for my Project Nodes in the Solution Explorer?
How to remove/add Commands to the Context Menu only for the Custom Projects:
If I have a C# project, the context menu should be the default one, if I add a MyProjectType project, I want to see a different context menu when right clicking on the Project Node in the Solution Explorer.

You were close with the IDM_VS_CTXT_PROJNODE parent.
Here is how I achieved it in my FluentMigratorRunner extension, which only shows its context menu item for a project if it has a reference to the FluentMigrator NuGet package.
Step 1: Add a submenu to the context menu
<Menus>
<Menu guid="guidCmdSet" id="packageMenu" priority="0x0300" type="Menu">
<Parent guid="guidSHLMainMenu" id="IDG_VS_CTXT_PROJECT_BUILD" />
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>DefaultInvisible</CommandFlag>
<Strings>
<ButtonText>CPSProject</ButtonText>
<CommandName>CPSProject</CommandName>
</Strings>
</Menu>
Note the added special CommandFlag elements.
Step 2: Add a group to the menu
<Groups>
<Group guid="guidCmdSet" id="packageMenuGroup" priority="0x0600">
<Parent guid="guidCmdSet" id="packageMenu" />
</Group>
</Groups>
Step 3: Add a button
<Button guid="guidCmdSet" id="specialBuildActionId" priority="0x0100" type="Button">
<Parent guid="guidCmdSet" id="packageMenuGroup" />
<CommandFlag>DynamicVisibility</CommandFlag>
<Strings>
<ButtonText>Special build</ButtonText>
</Strings>
Step 4: Add the menu in your *Package.cs
protected override async System.Threading.Tasks.Task InitializeAsync(System.Threading.CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
// Initialize the Fluent Migrator Menu, should only be visible for projects with FluentMigrator reference
var mcs = await GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
var menuCommandId = new CommandID(packageCmdSetGuidString, 0x1010);
var menuItem = new OleMenuCommand(null, menuCommandId);
menuItem.BeforeQueryStatus += MenuItem_BeforeQueryStatus;
mcs.AddCommand(menuItem);
}
private void MenuItem_BeforeQueryStatus(object sender, EventArgs e) =>
((OleMenuCommand)sender).Visible = ???;
Note the added BeforeQueryStatus eventhandler.
In that eventhandler you can check the type of the project and return a boolean controlling if the extra context menu should be shown yes or no

I'm not sure about removing the existing Build menu item... but as for having context menu items appear only when right-clicking on your custom project type, <VisibilityConstraints> might help:
(Excerpt from an example usage):
Often a package is being loaded to run a BeforeQueryStatus method for a button to determine its visibility. With <VisibilityConstraints> we can determine the visibility of a button without running BeforeQueryStatus and therefore don't need to load the package before the user clicks the button.
I've only ever used this strategy to show menu items for specific file types, but there are also some term types related to projects that might be more useful for this scenario.

Related

How to make Eclipse enabledWhen expression work for selection in non-focused view?

I have a handler which is connected to a menu contribution and a command. The menu contribution adds a button to a view and I want to have the button enabled depending on a selection in the Debug view.
So here's the expression:
<handler
class="com.example.myhandler"
commandId=" com.example.mycommand">
<enabledWhen>
<with
variable="selection">
<iterate
ifEmpty="false">
<instanceof
value="org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext">
</instanceof>
</iterate>
</with>
</enabledWhen>
</handler>
This works absolutely fine to the point where the Debug view has focus, meaning that if I select the element in the Debug view, the added button in a separate view is also enabled (as desired). As soon as I click on the view where I added the button via the menu contribution, then it's suddenly disabled (I guess because the selection is empty even though it's still selected; but the Debug view has no focus). How can I make this work so that the selection is still considered independently of the Debug view's focus state?
(You appear to be asking a DSF specific question, which has a different answer to the "general" case your title refers to. As such this answer probably solves your problem, but may not solve the general case.)
A complete example of extending DSF-GDB is provided in the CDT source repo in the org.eclipse.cdt.examples.dsf.gdb bundle.
That example defines a new command org.eclipse.cdt.examples.dsf.gdb.command.showVersion:
<!-- Example showing how to add a custom command with toolbar/menu contributions with DSF.
The example command id is org.eclipse.cdt.examples.dsf.gdb.command.showVersion.
In this example, when run it will display the version of GDB that is connected. -->
<extension point="org.eclipse.ui.commands">
<command
categoryId="org.eclipse.cdt.debug.ui.category.debugViewLayout"
description="Show the GDB Version in a pop-up"
id="org.eclipse.cdt.examples.dsf.gdb.command.showVersion"
name="Show GDB Version">
</command>
</extension>
It goes on to show how to contribute the command to the menus with the org.eclipse.ui.menus extension point. Then binds the command to a command handler with the org.eclipse.ui.handlers extension point.
Up until this point, DSF behaves the same as "normal" commands. But in DSF (using the retargettable command infrastructure provided by platform debug), the handler is not directly the command you are trying to run, but is a subclass of DebugCommandHandler.
DSF then can bind that command, using adapters to the concrete command implementation, depending on what the selected debug session in the Debug view is. In the show version case, this is GdbShowVersionHandler (implementation of IDebugCommandHandler). The handler has a canExecute which can connect to the back end if needed (gdb) to see if the current selection is applicable. The canExecute receives something that can be converted into a DSF context object like this:
private Optional<ICommandControlDMContext> getContext(final IDebugCommandRequest request) {
if (request.getElements().length != 1 || !(request.getElements()[0] instanceof IDMVMContext)) {
return Optional.empty();
}
final IDMVMContext context = (IDMVMContext) request.getElements()[0];
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(context.getDMContext(),
ICommandControlDMContext.class);
if (controlDmc != null)
return Optional.of(controlDmc);
return Optional.empty();
}
PS I added this example to CDT to help another extender a while back. The conversation on cdt-dev may be useful too? This was all added initially for this bug, with its associated gerrit which pulls all the changes for adding a new command into one place.

Eclipse hide action or actionset in Navigate menu

I am extending an extension point org.eclipse.ui.actionSets where I am creating element actionSet which contains action element inside. This asctionset is placed inside Navigate menu of eclipse For example:
<actionSet
label="%CNavigationActionSet.label"
description="%CNavigationActionSet.description"
visible="false"
id="xxx.ui.NavigationActionSet">
<action
class="xxx.opentype.OpenTypeAction"
definitionId="xxx.navigate.opentype"
helpContextId="xxxui.open_type_action"
icon="icons/xxx.gif"
id="xxx.ui.actions.OpenType"
label="Open Element"
menubarPath="navigate/open.ext2"
toolbarPath="org.eclipse.search.searchActionSet/Search"
tooltip="%OpenTypeAction.tooltip">
</action>
</actionSet>
Now I want to hide this action when certain conditions are met in Eclipse. Is there a way to hide (set visibility to false etc.) of this action in navigate menu?
Right now best what I figured out is to disable action when conditions are met, but this is not enough:
public class OpenTypeAction implements IWorkbenchWindowActionDelegate {
//... some code
#Override
public void selectionChanged(IAction action, ISelection selection) {
action.setEnabled(!areConditionsMet());
}
//... some code
}
/Edit: Solution for me would be also to hide whole actionSet instead of action, is that possible?
/Edit2: To clarify what my conditions are - my editor can contain files with multiple file extensions, I want to show this action only for files which end with certain file extension.

White/UI Automation doesn't recognize the container (pane control) in tab

I'm automating the windows application. I tried to access the pane element(which has text box, combo box controls) under tab control, but it's not accessible. White returns null.
I tried other techniques like UI automation TreeWalker (Rawview, Control view, content view), but nothing helps.
refer images in below links:
https://dl.dropboxusercontent.com/u/68446125/Tab.png
https://dl.dropboxusercontent.com/u/68446125/General%20Pane.png
As in picture 1, tab control is retrieved properly by White/UI Automation, but the child element General* Pane is not returned and it's controls are not accessible (Refer pic 2 highlighted), the first accessible child element is "General* tab Item".
Strange thing is, these controls are accessible in Inspect.exe (in windows SDK). I tried following methods to retrieve controls, but General* Pane is never accessible through White/UI Automation.
var tab = Window.Get<Tab>(SearchCriteria.ByControlType(ControlType.Tab).AndByClassName("TwoPageControl")); // Tab control is retrieved properly
var pane = tab.GetElement(SearchCriteria.ByControlType(ControlType.Pane).AndByText("General*")); // this line returns NULL
var pane1 = revWindow.GetElement(SearchCriteria.ByControlType(ControlType.Pane).AndByText("General*")); // this line returns NULL
var pane2 = revWindow.Get<Panel>(SearchCriteria.ByControlType(ControlType.Pane).AndByText("General*"));// throws exception "Failed to get ControlType=pane,Name=General*,ControlType=pane"
Tried windows UI automation code as well, but no luck.
System.Windows.Automation.Condition cd1 = new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab),
new PropertyCondition(AutomationElement.ClassNameProperty, "TwoPageControl"));
AutomationElement a = window.FindFirst(TreeScope.Descendants, cd1); // Tab control is returned properly here
TreeWalker rawViewWalker = TreeWalker.RawViewWalker;
AutomationElement cc = rawViewWalker.GetFirstChild(a); // General * Pane is not returned, instead General* Tab item is returned, though it's not the first child.
var cd = rawViewWalker.GetNextSibling(cc); // this returns next pane element available, not General * Pane.
Please help me how to access General * Pane and it's children under tab control. Any help is much appreciated.
I had exactly the same problem with my application. I use Inspect and open source UIAVerify where Pane element was visible as children of tab element. But when i compile Verify as a .Net 4.5 project, Pane element was not seen as part of tab. It only appears when I pointed it directly. I also search for my Pane element in Descendants of main window but there was nothing. I think it has something to do with dynamically creation of that pane content (i mean there is different content when you choose different tabItem).
I think you can't get access to that element from tree point of view.
My solution was to use AutomationElement.FromPoint Method.
http://msdn.microsoft.com/en-us/library/system.windows.automation.automationelement.frompoint(v=vs.110).aspx
I also think this shoud help if you have conntact with people developing program.
Some controls on a page are not visible for MS UI Automation
You can break up the TabControl to just the TabPanel, but without its ContentPresenter. You create your own ContentPresenter which used the content of the selected TabItem.
This way, White will be able to discover the controls in the ContentPresenter.
This is a workaround and it is a shame you have to change your WPF code just because "something goes wrong with UIA". But this is the best I could do.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl x:Name="uiTab" Grid.Row="1">
<TabControl.Template>
<ControlTemplate TargetType="TabControl">
<TabPanel IsItemsHost="True" VerticalAlignment="Stretch"/>
</ControlTemplate>
</TabControl.Template>
<TabItem Header="first">
<Button>FIRST</Button>
</TabItem>
<TabItem Header="second">
<Button>SECOND</Button>
</TabItem>
</TabControl>
<ContentPresenter Content="{Binding SelectedItem.Content, ElementName=uiTab}"/>
</Grid>

Eclipse RCP: Can I add a toolbar to an Editor Part?

I have succesfully managed to add view-specific toolbars to my RCP application by adding the following block to the org.eclipse.ui.menus extension point:
<menuContribution
allPopups="false"
locationURI="toolbar:my.package.path.views.ClassOfMyView">
<dynamic
class="my.package.path.toolbars.ViewToolBar"
id="MyViewToolbar">
</dynamic>
</menuContribution>
However, trying to do the same with my editorpart does not seem to work:
<menuContribution
allPopups="false"
locationURI="toolbar:my.package.path.views.ClassOfMyEditorPart">
<dynamic
class="my.package.path.toolbars.EditorPartToolBar"
id="MyEditorpartToolbar">
</dynamic>
</menuContribution>
Is there something obvious that I am missing, or is this simply not supported in RCP?
Following up on the hint about the Presentation API given by Tonny Madsen, I've come up with a solution to my problem. My solution is based on the following articles:
Eclipse RCP - Hide minimize / maximize buttons for editors and views (showing me how to supply my own presentation factory)
Incompatibilities between Eclipse 3.7 and 4.2 (helping me figure out why my presentation factory wasn't being used)
Custom RCP editor with the view header (helping me figure out how to make sure my presentation factory was being used)
To make my solution work, I ended up with changes in two files and a new class:
In the plugin.xml file, I added the following extension:
<extension point="org.eclipse.ui.presentationFactories">
<factory
name="Extended Presentation Factory"
class="org.eclipse.minicrm.ui.swt.custom.ExtendedPresentationFactory"
id="org.eclipse.minicrm.ui.swt.custom.ExtendedPresentationFactory"
/>
</extension>
This seems to be ignored by Eclipse 4.x, so to cater for those cases, I added the following line to the plugin_customisation.ini file:
org.eclipse.ui/presentationFactoryId = org.eclipse.minicrm.ui.swt.custom.ExtendedPresentationFactory
I then created the corresponding class:
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.internal.presentations.util.TabbedStackPresentation;
import org.eclipse.ui.presentations.IStackPresentationSite;
import org.eclipse.ui.presentations.StackPresentation;
import org.eclipse.ui.presentations.WorkbenchPresentationFactory;
#SuppressWarnings("restriction")
public class ExtendedPresentationFactory extends WorkbenchPresentationFactory {
private ToolBarManager m_toolBarManager = null;
private ToolBar m_toolbar = null;
#Override
public StackPresentation createEditorPresentation(final Composite parent, final IStackPresentationSite site) {
final TabbedStackPresentation presentation = (TabbedStackPresentation) super.createViewPresentation(parent, site);
m_toolbar = new ToolBar(presentation.getTabFolder().getToolbarParent(), 0);
m_toolBarManager = new ToolBarManager(m_toolbar);
m_toolBarManager.add(new MyAction1());
m_toolBarManager.add(new MyAction2());
m_toolBarManager.add(new MyAction3());
m_toolBarManager.update(true);
presentation.getTabFolder().setToolbar(m_toolbar);
return presentation;
}
}
This adds a toolbar with three buttons to my editor area.
I will still need to fiddle with some of the finer points (placement etc), but for a start it satisfies my need for a toolbar in the editor area.
These are some important visual differences between editors and views:
Editors provide additional actions to the top-level menu and the tool bar; views do not*
Views have an independent menu bar and tool bar; editors do not
There are at most one active editor in a perspective; there can be any number of active views
The are at most one view of each “type”; there can be any number of editors*
Editors are all placed in the “editor area”; views are placed in a number of “view stacks”
Some of these differences (marked with * above) can be ironed out using various functionality of the RCP platform:
The interface ISaveblePart can give a view the same life-cycle as an editor.
The menues extension point can add items to the main menu and tool bar when a view is active.
The views extension point can be used to allow multiple views of the same type.
With Eclipse 4, you can also combine editors and views in the same stack or folder.
But adding a menu or tool bar as seen with views require more work! But it can be done using the Presentation API, where most of the visual difference can be ironed out.
One additional comment: It is not toolbar:my.package.path.views.ClassOfMyView but toolbar:id-of-the-view.

Eclipse RCP: how to get Show View menu instead of a dialog

I've added to my perspective's org.eclipse.ui.menus
<command
commandId="org.eclipse.ui.views.showView"
style="pulldown">
</command>
This adds Show View item to main menu, but this item is not a menu (as in the Eclipse Window menu). Instead pressing it shows a dialog where I can select a view. How do I get a menu instead?
You have to create ContributionItem class like below:
public class MyShowViewContributionItem extends org.eclipse.ui.internal.ShowViewMenu {
public MyShowViewContributionItem() {
this("om.myplugin.myShowViewId");
}
public MyShowViewContributionItem(String id) {
super(org.eclipse.ui.PlatformUI.getWorkbench().getActiveWorkbenchWindow(), id);
}
}
then in your plugin.xml org.eclipse.ui.menus extension:
<menu
label="My Show View">
<dynamic
class="com.myplugin.MyShowViewContributionItem"
id="com.myplugin.myShowViewId">
</dynamic>
</menu>
Cheers,
Max
Just to share on my recent experiment in trying to do the same thing, what Max suggested in his answer will work but leaves you using internal code (resulting in a 'Discouraged Access' warning).
Another approach is to build the menu through your applications action bar advisor. Although, this approach will leave you to having to write code (oppose to use providing menu contributions in the plugin XML definition). Consider the following example:
public class ApplicationActionBarAdvisor extends ActionBarAdvisor
{
private IContributionItem contributionOpenPerspective;
private IContributionItem contributionShowView;
...
protected void makeActions(IWorkbenchWindow window)
{
...
contributionOpenPerspective = ContributionItemFactory.
PERSPECTIVES_SHORTLIST.create(window);
contributionShowView = ContributionItemFactory.
VIEWS_SHORTLIST.create(window);
...
}
protected void fillMenuBar(IMenuManager menuBar)
{
...
MenuManager windowMenu = new MenuManager("&Window",
IWorkbenchActionConstants.M_WINDOW);
menuBar.add(windowMenu);
MenuManager openPerspectiveMenu = new MenuManager("&Open Perspective");
openPerspectiveMenu.add(perspectivesContribution);
windowMenu.add(openPerspectiveMenu);
MenuManager showViewMenu = new MenuManager("Show &View");
showViewMenu.add(viewsContribution);
windowMenu.add(showViewMenu);
...
}
}
A possible downside to this approach is with the interaction between menus created in the advisor and menus created by menu contributions. Since advisor menu items are created before menu contributions, you are left to deal with adding more sorting logic in your menu contributions. This might be fine for most people, however, you lose the 'feel' of a centralized menu structure from org.eclipse.ui.menus (even if the feeling is an illusion when other plugins come into play with their own menu contributions).
I've also included the building of a perspective menu as well; completely option, but I added it if anyone was attempting to perform the same menu building with perspectives.