How to manage key conflict handler of different commands in multipage editor - eclipse

I have multipage editor and i'm using different commands in two pages with same key sequence 'M3+O'. I am getting key conflicting handlers.
Error:
!MESSAGE A conflict occurred for ALT+O:
Binding(ALT+O,
ParameterizedCommand(Command(adt.tools.wda_com.sap.adt.wda.controller.ui.addmethcommand,Add Method,
,
Category(org.eclipse.core.commands.categories.autogenerated,Uncategorized,Commands that were either auto-generated or have no category,true),
org.eclipse.ui.internal.MakeHandlersGo#2f2e3d,
,,true),null),
org.eclipse.ui.defaultAcceleratorConfiguration,
com.sap.adt.wda.controller.ui.contextTabScope,,,system)
Binding(ALT+O,
ParameterizedCommand(Command(adt.tools.wda_com.sap.adt.wda.controller.ui.addnodecommand,Add Node,
,
Category(org.eclipse.core.commands.categories.autogenerated,Uncategorized,Commands that were either auto-generated or have no category,true),
org.eclipse.ui.internal.MakeHandlersGo#184af18,
,,true),null),
org.eclipse.ui.defaultAcceleratorConfiguration,
com.sap.adt.wda.controller.ui.contextTabScope,,,system)
Extensions:
<extension
point="org.eclipse.ui.bindings">
<key
commandId="adt.tools.wda_com.sap.adt.wda.controller.ui.addmethcommand"
contextId="com.sap.adt.wda.controller.ui.contextScope"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="M3+O">
</key>
<key
commandId="adt.tools.wda_com.sap.adt.wda.controller.ui.addnodecommand"
contextId="com.sap.adt.wda.controller.ui.contextScope"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="M3+O">
</key>
</extension>
My own Context:
<extension
point="org.eclipse.ui.contexts">
<context
description="context scope"
id="com.sap.adt.wda.controller.ui.contextScope"
name="context scope"
parentId="org.eclipse.ui.contexts.window">
</context>
</extension>
Activation and deactivation: It is done through activation and deactivation of context. Below is the code snippet on page change.
Activation in 1st Page:
private void activateHandlers() {
IContextService contextService = (IContextService) (PlatformUI.getWorkbench().getService(IContextService.class));
if (contextService != null) {
activation = contextService.activateContext(IControllerConstants.CONTEXT_TAB_ECLIPSE_CONTEXT_ID);
}
IEditorSite site = getEditor().getEditorSite();
IHandlerService service = (IHandlerService) site.getService(IHandlerService.class);
IHandlerActivation nodeActivation = service.activateHandler(AddNodeHandler.COMMAND_ID, new AddNodeHandler());
activatedHandlers = new ArrayList<IHandlerActivation>();
activatedHandlers.add(nodeActivation );
}
Activation in 2nd Page:
private void activateHandlers() {
IContextService contextService = (IContextService) (PlatformUI.getWorkbench().getService(IContextService.class));
if (contextService != null) {
activation = contextService.activateContext(IControllerConstants.CONTEXT_TAB_ECLIPSE_CONTEXT_ID);
}
IEditorSite site = getEditor().getEditorSite();
IHandlerService service = (IHandlerService) site.getService(IHandlerService.class);
IHandlerActivation methodActivation = service.activateHandler(AddMethodHandler.COMMAND_ID, new AddMethodHandler());
activatedHandlers = new ArrayList<IHandlerActivation>();
activatedHandlers.add(methodActivation );
}
Deactivation similar in respective page:
public void deactivateHandlers() {
IContextService contextService = (IContextService) (PlatformUI.getWorkbench().getService(IContextService.class));
contextService.deactivateContext(activation);
IHandlerService service = (IHandlerService) getEditor().getEditorSite().getService(IHandlerService.class);
if (activatedHandlers != null) {
service.deactivateHandlers(activatedHandlers);
activatedHandlers = null;
}
}
Even after deactivation / activation on page change, the conflict appears.
Please let me know if there is a better approach.
Thanks.

Use a different context id for each page. You could make your main com.sap.adt.wda.controller.ui.contextScope the parent of each page context.

Related

How to set the light theme as the default theme?

Eclipse RCP 2022-06
After exporting the product, I found that if the current theme of win10 is dark, RCP also uses the dark theme
In other words, eclipse will now decide which theme to choose at startup based on the theme of the operating system
How do disable this feature?? I don't want to use it until the dark theme is complete
Updated as recommended by greg-449
Possibly set system property org.eclipse.swt.internal.win32.useDarkModeExplorerTheme to false. Look at the source of Display to see all the properties that can be set on Windows
This is my exported product profile
-startup
plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.2.500.v20220509-0833
-clearPersistedState
--launcher.appendVmargs
--launcher.defaultAction
openFile
-vmargs
-Dosgi.requiredJavaVersion=17
-Dorg.eclipse.swt.internal.win32.useDarkModeExplorerTheme=false
-Xms1024m
-Xmx2048m
-XX:+UseG1GC
--add-modules=ALL-SYSTEM
Still unsolvable
Reply to howlger
The exported product is the most basic product
This is a particularly simple test for the new version of RCP export products
Other settings are based on platform feature
plugin.xml
<plugin>
<extension
id="product"
point="org.eclipse.core.runtime.products">
<product
application="org.eclipse.ui.ide.workbench"
name="BitFan">
<property
name="appName"
value="BitFan">
</property>
<property
name="windowImages"
value="logo16.png,logo32.png,logo48.png,logo64.png,logo128.png,logo256.png">
</property>
<property
name="startupForegroundColor"
value="FFFFFF">
</property>
<property
name="startupMessageRect"
value="30,272,445,20">
</property>
<property
name="startupProgressRect"
value="28,295,445,15">
</property>
<property
name="applicationCSSResources"
value="platform:/plugin/org.eclipse.ui.themes/images/">
</property>
<property
name="applicationXMI"
value="org.eclipse.platform/LegacyIDE.e4xmi">
</property>
<property
name="cssTheme"
value="org.eclipse.e4.ui.css.theme.e4_default">
</property>
<property
name="buildIdLocation"
value="0,220">
</property>
<property
name="buildIdSize"
value="293,40">
</property>
<property
name="preferenceCustomization"
value="plugin_customization.ini">
</property>
</product>
</extension>
</plugin>
Reply to howlger again
boolean hasDarkTheme = getThemes().stream().anyMatch(t -> t.getId().startsWith(E4_DARK_THEME_ID));
String themeToRestore = Display.isSystemDarkTheme() && hasDarkTheme ? E4_DARK_THEME_ID : alternateTheme;
if (themeToRestore != null && flag) {
setTheme(themeToRestore, false);
}
I tracked that "Display.isSystemDarkTheme()" is true, so the dark theme is set
Then I set
-Dorg.eclipse.swt.internal.win32.useDarkModeExplorerTheme=false in the Run Configurations VM Arguments
clear run, still the dark theme
This parameter has no effect
It judges by reading the registry
public static boolean isSystemDarkTheme () {
boolean isDarkTheme = false;
/*
* The registry settings, and Dark Theme itself, is present since Win10 1809
*/
if (OS.WIN32_BUILD >= OS.WIN32_BUILD_WIN10_1809) {
int[] result = OS.readRegistryDwords(OS.HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme");
if (result!=null) {
isDarkTheme = (result[0] == 0);
}
}
return isDarkTheme;
}
I think this problem can only be solved by deleting the dark theme , But how to delete it? It seems that the "org.eclipse.ui.activities" extension point cannot disable themes
Maybe I can remove it through removeExtension, but this needs to be done before the workbench starts. At present, I only know that the splashHandlers extension point can be implemented. Should I do this?
Under normal circumstances, there is no way to solve this problem, because the restore method of ThemeEngine determines whether to use dark theme according to the Display
#Override
public void restore(String alternateTheme) {
String prefThemeId = getPreferenceThemeId();
// Bug 562794, 563601: Eclipse once contained two identical themes named
// "Classic" and "Windows Classic" and the second was removed with bug 562794.
// An old workspace using the removed "Windows Classic" theme would be reseted
// to the default theme on update. Since both themes are identical we silently
// change the theme to the remaining "Classic" theme and don't disturb the user.
if ("org.eclipse.e4.ui.css.theme.e4_classic6.0,6.1,6.2,6.3".equals(prefThemeId)) { //$NON-NLS-1$
prefThemeId = "org.eclipse.e4.ui.css.theme.e4_classic"; //$NON-NLS-1$
}
boolean flag = true;
if (prefThemeId != null) {
for (ITheme t : getThemes()) {
if (prefThemeId.equals(t.getId())) {
setTheme(t, false);
flag = false;
break;
}
}
}
/*
* Any Platform: if the system has Dark appearance set and Eclipse is using the
* default settings, then start Eclipse in Dark theme. Check that there is a
* dark theme present.
*/
boolean hasDarkTheme = getThemes().stream().anyMatch(t -> t.getId().startsWith(E4_DARK_THEME_ID));
String themeToRestore = Display.isSystemDarkTheme() && hasDarkTheme ? E4_DARK_THEME_ID : alternateTheme;
if (themeToRestore != null && flag) {
setTheme(themeToRestore, false);
}
}
But "Display.isSystemDarkTheme" is determined based on the operating system registry
public static boolean isSystemDarkTheme () {
boolean isDarkTheme = false;
/*
* The registry settings, and Dark Theme itself, is present since Win10 1809
*/
if (OS.WIN32_BUILD >= OS.WIN32_BUILD_WIN10_1809) {
int[] result = OS.readRegistryDwords(OS.HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme");
if (result!=null) {
isDarkTheme = (result[0] == 0);
}
}
return isDarkTheme;
}
Solution
Remove all themes first
private void removeThemes()throws Exception {
ExtensionRegistry registry = (ExtensionRegistry)Platform.getExtensionRegistry() ;
Field field = ExtensionRegistry.class.getDeclaredField("masterToken") ; //$NON-NLS-1$
field.setAccessible( true ) ;
Object masterToken = field.get(registry) ;
IExtensionPoint extPoint = registry.getExtensionPoint(ThemeEngine.THEME_PLUGIN_ID);
IExtension extensions[] = extPoint.getExtensions() ;
for (IExtension e : extensions ) {
if( "org.eclipse.ui.themes".equals( e.getContributor().getName() ) ) { //$NON-NLS-1$
registry.removeExtension( e , masterToken ) ;
return ;
}
}
}
Then add extension points in the appropriate plug-ins (I defined in the product plug-ins)
<extension
point="org.eclipse.e4.ui.css.swt.theme">
<theme
basestylesheeturi="platform:/plugin/org.eclipse.ui.themes/css/e4_default_win.css"
id="org.eclipse.e4.ui.css.theme.e4_default"
label="Light"
os="win32">
</theme>
</extension>
Finally, modify the start method of the application
#Override
public Object start(IApplicationContext appContext) throws Exception {
removeThemes();
...
...
}

Eclipse RCP Content Assist not working with auto activated characters

I define my own editor and have completion proposals like this
public IContentAssistant getContentAssistant(ISourceViewer sv) {
ContentAssistant ca = new ContentAssistant();
IContentAssistProcessor pr = new TagCompletionProcessor();
ca.setContentAssistProcessor(pr, IDocument.DEFAULT_CONTENT_TYPE);
return ca;
}
#Override
public char[] getCompletionProposalAutoActivationCharacters() {
String str = "._abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
return str.toCharArray();
}
So when I am pressing ctrl-space enter it will work, but I want it should always trigger computeCompletionProposals when any of the above characters are entered.
<extension
point="org.eclipse.ui.editors">
<editor
id="testingpluginproject.editors.XMLEditor"
name="Sample XML Editor"
icon="icons/sample.png"
extensions="xxml"
class="testingpluginproject.editors.XMLEditor"
contributorClass="org.eclipse.ui.texteditor.BasicTextEditorActionContributor">
</editor>
</extension>
So what I am missing?
You must call the ContentAssistant enableAutoActivation method to enable auto activation:
ca.enableAutoActivation(true);
You might also want to look at implementing IContentAssistProcessorExtension rather than just IContentAssistProcessor as it provides a better isCompletionProposalAutoActivation method.

How to ensure that my key bindings have priority over other definitions

I am developing an RCP app. The app has an execution mode where I want to enable various key bindings to control Start, Stop, Continue, Repeat etc. The bindings will be enabled using an 'ExecutionContext' which is set when any of the relevant views are activated.
The context switching is done in each of the 'Execution' views.
#Override
public final void createPartControl(Composite parent)
{
addPartListener();
...
}
private void addPartListener()
{
this.getViewSite().getPage().addPartListener(new IPartListener2()
{
IContextActivation token = null;
#Override
public void partDeactivated(IWorkbenchPartReference partRef)
{
if (token != null)
{
System.out.println("End exec context");
IContextService contextService = (IContextService) PlatformUI.getWorkbench().getService(
IContextService.class);
contextService.deactivateContext(token);
token = null;
}
}
#Override
public void partActivated(IWorkbenchPartReference partRef)
{
System.out.println("Set exec context");
IContextService contextService = (IContextService) PlatformUI.getWorkbench().getService(
IContextService.class);
token = contextService.activateContext("AtfExecutionContext");
}
});
}
I can see via Console messages that my context is being set and some of the key bindings are working as expected.
However, if a key binding has already been assigned from another plugin, that binding has priority. E.g. I want to use Ctrl+F8 to stop but when that is pressed I get the 'Next perspective' action which is the workbench default.
The binding definition is
<extension
point="org.eclipse.ui.bindings">
<scheme
id="atfscheme"
name="atfscheme"
parentId="org.eclipse.ui.defaultAcceleratorConfiguration">
</scheme>
<key
commandId="com.xxx.atf.model.ui.commands.ExecKey.Start"
contextId="AtfExecutionContext"
schemeId="atfscheme"
sequence="M1+M2+F5">
<!-- F5 does not work but Ctrl-Shift-F5 does -->
</key>
</extension>
<extension
point="org.eclipse.ui.contexts">
<context
id="AtfExecutionContext"
name="AtfExecutionContext"
parentId="org.eclipse.debug.ui.debugging">
<!-- have tried various parentid values... -->
</context>
</extension>
It seems that only previously undefined accelerators work. What do I have to do to override existing definitions and activate mine when my context has been set?
There is a separate context service for each part, you must use the correct context service.
It isn't necessary to activate / deactivate the context on part activation / deactivation. The separate context services will deal with that automatically.
So activate in createPartControl with:
IContextService contextService = getSite().getService(IContextService.class);
token = contextService.activateContext("AtfExecutionContext");
and deactivate when the part closes.
You are also defining a new key binding scheme - that has to be activated separately and isn't what you want here. Just remove that and just use org.eclipse.ui.defaultAcceleratorConfiguration as the schemeId

Eclipse: Disable property tab contributed from navigator plugin

I need to hide propery tab called "Resources" contributed by plugin org.eclipse.ui.navigator.resources
This tab looks like this:
The description of this tab from plugin:
<extension
point="org.eclipse.ui.views.properties.tabbed.propertyContributor">
<propertyContributor
contributorId="org.eclipse.ui.navigator.ProjectExplorer"
labelProvider="org.eclipse.ui.internal.navigator.resources.workbench.TabbedPropertySheetTitleProvider">
<propertyCategory category="general"/>
<propertyCategory category="core"/>
<propertyCategory category="appearance"/>
<propertyCategory category="resource"/>
<propertyCategory category="advanced"/>
</propertyContributor>
</extension>
<extension
point="org.eclipse.ui.views.properties.tabbed.propertyTabs">
<propertyTabs contributorId="org.eclipse.ui.navigator.ProjectExplorer">
<propertyTab
label="%Resource"
category="resource"
id="CommonNavigator.tab.Resource"/>
</propertyTabs>
</extension>
I want to hide this tab, so there will be visible only tab contributed by my plugin.
Update.
I have tried activities like this, but is doesnt helps:
<activityPatternBinding
activityId="com.company.activities.hide"
isEqualityPattern="true"
pattern="org.eclipse.ui.navigator.resources/CommonNavigator.tab.Resource">
</activityPatternBinding>
On possibility is to remove unwanted contribution:
final ActionSetRegistry reg = WorkbenchPlugin.getDefault().getActionSetRegistry();
final IActionSetDescriptor[] actionSets = reg.getActionSets();
final String[] removeActionSets =
new String[] { "org.eclipse.search.searchActionSet", "org.eclipse.ui.cheatsheets.actionSet",
"org.eclipse.ui.actionSet.keyBindings", "org.eclipse.ui.edit.text.actionSet.navigation",
"org.eclipse.ui.edit.text.actionSet.annotationNavigation",
"org.eclipse.ui.edit.text.actionSet.convertLineDelimitersTo",
"org.eclipse.ui.edit.text.actionSet.openExternalFile",
"org.eclipse.ui.externaltools.ExternalToolsSet", "org.eclipse.ui.WorkingSetActionSet",
"org.eclipse.update.ui.softwareUpdates", "org.eclipse.ui.actionSet.openFiles",
"org.eclipse.mylyn.tasks.ui.navigation", };
for (IActionSetDescriptor actionSet : actionSets) {
boolean found = false;
for (String removeActionSet : removeActionSets) {
if (removeActionSet.equals(actionSet.getId())) {
found = true;
}
}
if (!found) {
continue;
}
final IExtension ext = actionSet.getConfigurationElement().getDeclaringExtension();
reg.removeExtension(ext, new Object[] { actionSet });
}

Any example of changing menus and supporting closing for an 'AllActive' tabbed application?

I'm a CM newbie and trying to get my head around CM. I am building an application where each tab allows the user different functionality for accessing a server where the active work in all tabs (if any is active) could be running async to each other so the shell is an "Conductor.Collection.AllActive" which I hope was the correct choice. I am looking for suggestions or an sample in two areas -
I would like to have the main shell own the application menu and the tab control, and to change the application menuitems depending on the tab selected and then have the menuitem clicks routed to the respective VM for the tab.
Since all tabs could potentially be doing active work simultaneously, I am hoping for an example of how the VM on each tab can participate in helping to decide (via dialogs to the user) if the application can be closed if the close menuitem or the application X icon is clicked. Or if the close should be cancelled per the user response (e.g. they say 'no' since there are unsaved files).
Any examples and suggestions much appreciated.
I created a sample of a possible way to do this. Using a SharedViewModel that contains a collection of MenuItems. The SharedViewModel is injected into the ShellViewModel and each TabViewModel. The Menu control binds to the collection of MenuItems.
When a tab's OnActivate fires the Menu items can be updated by the TabViewModel.
<HierarchicalDataTemplate DataType="{x:Type viewModels:MenuItemViewModel}"
ItemsSource="{Binding Path=MenuItems}">
<ContentControl cal:View.Model="{Binding}" />
</HierarchicalDataTemplate>
<Menu IsMainMenu="True"
ItemsSource="{Binding SharedViewModel.MenuItems}" />
SharedViewModel:
public class SharedViewModel : PropertyChangedBase
{
private List<MenuItemViewModel> _menuItems;
public List<MenuItemViewModel> MenuItems
{
get { return _menuItems; }
set
{
_menuItems = value;
NotifyOfPropertyChange(() => MenuItems);
}
}
}
Example of a TabViewModel updating the Menu:
protected override void OnActivate()
{
base.OnActivate();
SharedViewModel.MenuItems = new List<MenuItemViewModel>
{
new MenuItemViewModel
{
Header = "MainMenuItem1",
MenuItems =
new List<MenuItemViewModel>
{
new MenuItemViewModel {Header = "SubMenuItem1"},
new MenuItemViewModel {Header = "SubMenuItem2"},
}
},
new MenuItemViewModel
{
Header = "MainMenuItem2",
MenuItems =
new List<MenuItemViewModel>
{
new MenuItemViewModel {Header = "SubMenuItem1"},
new MenuItemViewModel {Header = "SubMenuItem2"},
}
}
};
}