In Bug 514458, I added the “Theme” dynamic menu to the Eclipse IDE. This post explains how I did this.

Menu Eclipse 3.x style

First edit the plugin.xml, and add a menu contribution. With the locationURI menu:org.eclipse.ui.appearance?after=org.eclipse.ui.window.appearance.separator1, you’ll contribute a submenu to the Window > Appearance menu, just after the separator.

appearance-menu-structure

Add a Theme menu under the menuContribution, and then add a child dynamic element.

<menuContribution
      locationURI="menu:org.eclipse.ui.appearance?after=org.eclipse.ui.window.appearance.separator1">
   <menu
         id="org.eclipse.ui.appearance.theme"
         label="Theme">
      <dynamic
            class="org.eclipse.ui.internal.actions.ThemeDynamicMenu"
            id="org.eclipse.ui.ide.dynamic1">
      </dynamic>
   </menu>
</menuContribution>

Next, create the java class implementing the dynamic menu, and add mock code to verify the menu works.

public class ThemeDynamicMenu extends ContributionItem {

	@Override
	public void fill(Menu menu, int index) {
		MenuItem menuItem = new MenuItem(menu, SWT.CHECK, index);
		menuItem.setText("Theme 1"); //$NON-NLS-1$
		menuItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				// executed on menu select
				System.out.println("Selected"); //$NON-NLS-1$
			}
		});
	}

}

Verify the menu is displayed where you expect, and the submenu dynamic entries are working.

new-theme-dynamic-menu

Now remove the line which adds the “Theme 1” item, and rewrite the body of the widgetSelected.

The menu should have one menu item for each available theme, and each widgetSelected(){…} should activate the corresponding theme.

The theme selection code is inspired tothe ViewsPreferencePage one.

/**
 * Implements the Dynamic Menu to choose the Theme.
 */
public class ThemeDynamicMenu extends ContributionItem {

	private static String THEME_ID = "THEME_ID"; //$NON-NLS-1$

	private IThemeEngine engine;
	private boolean highContrastMode;

	public ThemeDynamicMenu() {
		IWorkbench workbench = PlatformUI.getWorkbench();
		MApplication application = workbench.getService(MApplication.class);
		IEclipseContext context = application.getContext();
		engine = context.get(IThemeEngine.class);
		highContrastMode = workbench.getDisplay().getHighContrast();
	}

	@Override
	public void fill(Menu menu, int index) {
		for (ITheme theme : engine.getThemes()) {
			if (!highContrastMode && !Util.isGtk() && theme.getId().equals(E4Application.HIGH_CONTRAST_THEME_ID)) {
				continue;
			}
			MenuItem menuItem = new MenuItem(menu, SWT.CHECK, index);
			menuItem.setText(theme.getLabel());
			menuItem.setData(THEME_ID, theme.getId());
			menuItem.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					engine.setTheme(theme, !highContrastMode);
				}
			});
		}

		menu.addMenuListener(new MenuAdapter() {
			@Override
			public void menuShown(MenuEvent e) {
				for (MenuItem item : menu.getItems()) {
					boolean isActive = item.getData(THEME_ID).equals(engine.getActiveTheme().getId());
					item.setEnabled(!isActive);
					item.setSelection(isActive);
				}
			}
		});

	}

}

Finally, launch the Eclipse IDE to check the menu works as expected.

theming-menu
Categories: eclipseJava

7 Comments

Tom Schindl · April 11, 2017 at 20:22

Should you call setSelection instead of set enabled?

    psuzzi · May 7, 2017 at 16:15

    The user should not select a theme that is already active. So, the setEnabled(!active) disables the menuItem, for the next time the menu is shown, the user can not select it.
    The setSelected, on the other hand, is responsible for showing the “v” mark next to the menuItem.

Dennis · April 12, 2017 at 08:46

Improvement suggestion: sort the themes by name, before adding them as entries to the menu.

Max · April 12, 2017 at 16:41

Your link points to the wrong bug. Here is the correct link:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=514458

Michael Keppler · April 13, 2017 at 07:51

Link behind the bug number is wrong.

Andreas Sewe · April 13, 2017 at 11:39

Thank you for the interesting blog post, Patrik. One thing I am curious about, however, is why you chose this curious mixture of Eclipse 3.x and 4.x APIs. While you use an 3.x-style menu contribution, you later on use the 4.x IEclipseContext and IThemeEngine. Why not Eclipse 4.x all the way through?

(One more thing: The link to Bug 514458 above actually takes you to a different, unrelated bug.)

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *