Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 246165
Collapse All | Expand All

(-)Eclipse UI/org/eclipse/ui/internal/keys/WorkbenchKeyboard.java (+48 lines)
Lines 23-31 Link Here
23
import org.eclipse.core.commands.common.CommandException;
23
import org.eclipse.core.commands.common.CommandException;
24
import org.eclipse.core.commands.common.NotDefinedException;
24
import org.eclipse.core.commands.common.NotDefinedException;
25
import org.eclipse.core.commands.util.Tracing;
25
import org.eclipse.core.commands.util.Tracing;
26
import org.eclipse.core.expressions.IEvaluationContext;
27
import org.eclipse.core.runtime.AssertionFailedException;
26
import org.eclipse.core.runtime.IStatus;
28
import org.eclipse.core.runtime.IStatus;
27
import org.eclipse.core.runtime.Status;
29
import org.eclipse.core.runtime.Status;
28
import org.eclipse.jface.bindings.Binding;
30
import org.eclipse.jface.bindings.Binding;
31
import org.eclipse.jface.bindings.TriggerSequence;
29
import org.eclipse.jface.bindings.keys.KeySequence;
32
import org.eclipse.jface.bindings.keys.KeySequence;
30
import org.eclipse.jface.bindings.keys.KeyStroke;
33
import org.eclipse.jface.bindings.keys.KeyStroke;
31
import org.eclipse.jface.bindings.keys.ParseException;
34
import org.eclipse.jface.bindings.keys.ParseException;
Lines 53-58 Link Here
53
import org.eclipse.ui.internal.handlers.HandlerService;
56
import org.eclipse.ui.internal.handlers.HandlerService;
54
import org.eclipse.ui.internal.misc.Policy;
57
import org.eclipse.ui.internal.misc.Policy;
55
import org.eclipse.ui.internal.misc.StatusUtil;
58
import org.eclipse.ui.internal.misc.StatusUtil;
59
import org.eclipse.ui.internal.tweaklets.Tweaklets;
60
import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
56
import org.eclipse.ui.internal.util.Util;
61
import org.eclipse.ui.internal.util.Util;
57
import org.eclipse.ui.keys.IBindingService;
62
import org.eclipse.ui.keys.IBindingService;
58
import org.eclipse.ui.statushandlers.StatusManager;
63
import org.eclipse.ui.statushandlers.StatusManager;
Lines 78-83 Link Here
78
public final class WorkbenchKeyboard {
83
public final class WorkbenchKeyboard {
79
84
80
	/**
85
	/**
86
	 * Tweaklet key for menu flashing.
87
	 *
88
	 * @since 3.5
89
	 */
90
	public static TweakKey KEY = new Tweaklets.TweakKey(MenuFlasher.class);
91
	
92
	/**
93
	 * Tweaklet class for flashing the menu.
94
	 *  
95
	 * @since 3.5
96
	 */
97
	public abstract static class MenuFlasher {
98
		
99
		/**
100
		 * Flash a menu item that matches the provided key sequence
101
		 * 
102
		 * @param currentState
103
		 *            the current context
104
		 * @param triggerSequence
105
		 *            the trigger sequence to flash
106
		 */
107
		public abstract void flash(IEvaluationContext currentState,
108
				TriggerSequence triggerSequence);
109
	}
110
	
111
	/**
81
	 * A display filter for handling key bindings. This filter can either be
112
	 * A display filter for handling key bindings. This filter can either be
82
	 * enabled or disabled. If disabled, the filter does not process incoming
113
	 * enabled or disabled. If disabled, the filter does not process incoming
83
	 * events. The filter starts enabled.
114
	 * events. The filter starts enabled.
Lines 372-377 Link Here
372
	private final IWorkbench workbench;
403
	private final IWorkbench workbench;
373
404
374
	/**
405
	/**
406
	 * Flasher tweaklet.  May be <code>null</code>
407
     *
408
     * @since 3.5
409
     */
410
	private MenuFlasher flasher;
411
412
	/**
375
	 * Constructs a new instance of <code>WorkbenchKeyboard</code> associated
413
	 * Constructs a new instance of <code>WorkbenchKeyboard</code> associated
376
	 * with a particular workbench.
414
	 * with a particular workbench.
377
	 * 
415
	 * 
Lines 384-389 Link Here
384
		workbench = associatedWorkbench;
422
		workbench = associatedWorkbench;
385
		state = new KeyBindingState(associatedWorkbench);
423
		state = new KeyBindingState(associatedWorkbench);
386
		workbench.addWindowListener(windowListener);
424
		workbench.addWindowListener(windowListener);
425
		try {
426
			flasher = (MenuFlasher)Tweaklets.get(KEY);
427
		}
428
		catch (AssertionFailedException e) {
429
			// no-op. No flasher, no problem. Any exceptions in creating a
430
			// flasher class would have been logged by the Tweaklets code so we
431
			// shouldn't do anything.
432
		}
387
	}
433
	}
388
434
389
	/**
435
	/**
Lines 469-474 Link Here
469
		}
515
		}
470
516
471
		try {
517
		try {
518
			if (flasher != null)
519
				flasher.flash(handlerService.getCurrentState(), binding.getTriggerSequence());	
472
			handlerService.executeCommand(parameterizedCommand, trigger);
520
			handlerService.executeCommand(parameterizedCommand, trigger);
473
		} catch (final NotDefinedException e) {
521
		} catch (final NotDefinedException e) {
474
			// The command is not defined. Forwarded to the IExecutionListener.
522
			// The command is not defined. Forwarded to the IExecutionListener.
(-)META-INF/MANIFEST.MF (-1 / +1 lines)
Lines 2-8 Link Here
2
Bundle-ManifestVersion: 2
2
Bundle-ManifestVersion: 2
3
Bundle-Name: %fragmentName
3
Bundle-Name: %fragmentName
4
Bundle-SymbolicName: org.eclipse.ui.carbon; singleton:=true
4
Bundle-SymbolicName: org.eclipse.ui.carbon; singleton:=true
5
Bundle-Version: 4.0.0.qualifier
5
Bundle-Version: 4.0.1.qualifier
6
Bundle-Vendor: %providerName
6
Bundle-Vendor: %providerName
7
Fragment-Host: org.eclipse.ui;bundle-version="[3.2.0,4.0.0)"
7
Fragment-Host: org.eclipse.ui;bundle-version="[3.2.0,4.0.0)"
8
Bundle-Localization: fragment-carbon
8
Bundle-Localization: fragment-carbon
(-)fragment.xml (+10 lines)
Lines 8-12 Link Here
8
            class="org.eclipse.ui.internal.carbon.CarbonUIEnhancer">
8
            class="org.eclipse.ui.internal.carbon.CarbonUIEnhancer">
9
      </startup>
9
      </startup>
10
   </extension>
10
   </extension>
11
   <extension
12
         point="org.eclipse.ui.internalTweaklets">
13
      <tweaklet
14
            definition="org.eclipse.ui.internal.keys.WorkbenchKeyboard$MenuFlasher"
15
            description="%menu.tweaklet.description."
16
            id="org.eclipse.ui.carbon.menuFlasher"
17
            implementation="org.eclipse.ui.internal.carbon.CarbonMenuFlasher"
18
            name="%menu.tweaklet.name.">
19
      </tweaklet>
20
   </extension>
11
   
21
   
12
</fragment>
22
</fragment>
(-)fragment-carbon.properties (+3 lines)
Lines 11-13 Link Here
11
11
12
providerName=Eclipse.org
12
providerName=Eclipse.org
13
fragmentName=Eclipse UI MacOS X Enhancements
13
fragmentName=Eclipse UI MacOS X Enhancements
14
15
menu.tweaklet.description. = Flashes the appropriate main menu entry on keybinding activation
16
menu.tweaklet.name. = Carbon Menu Flasher
(-)src/org/eclipse/ui/internal/carbon/CarbonMenuFlasher.java (+109 lines)
Added Link Here
1
package org.eclipse.ui.internal.carbon;
2
3
import java.lang.reflect.Field;
4
5
import org.eclipse.core.expressions.IEvaluationContext;
6
import org.eclipse.jface.bindings.TriggerSequence;
7
import org.eclipse.swt.internal.carbon.OS;
8
import org.eclipse.swt.widgets.Menu;
9
import org.eclipse.swt.widgets.MenuItem;
10
import org.eclipse.swt.widgets.Shell;
11
import org.eclipse.ui.ISources;
12
import org.eclipse.ui.internal.keys.WorkbenchKeyboard.MenuFlasher;
13
14
/**
15
 * @since 4.0.1
16
 * 
17
 */
18
public class CarbonMenuFlasher extends MenuFlasher {
19
20
	private static Field handleField;
21
	static {
22
		try {
23
			Field handleField = Menu.class.getDeclaredField("handle"); //$NON-NLS-1$
24
			handleField.setAccessible(true);
25
			// only set it after we've successfully set the accessibility
26
			CarbonMenuFlasher.handleField = handleField;
27
		} catch (SecurityException e) {
28
			throw new ExceptionInInitializerError("Could not change accessibility of required 'handle' field for CarbonMenuFlasher"); //$NON-NLS-1$
29
		} catch (NoSuchFieldException e) {
30
			throw new ExceptionInInitializerError("Could not find required 'handle' field for CarbonMenuFlasher"); //$NON-NLS-1$
31
		}
32
	}
33
34
	/*
35
	 * (non-Javadoc)
36
	 * 
37
	 * @see
38
	 * org.eclipse.ui.internal.keys.WorkbenchKeyboard.MenuFlasher#flash(org.
39
	 * eclipse.core.expressions.IEvaluationContext,
40
	 * org.eclipse.jface.bindings.TriggerSequence)
41
	 */
42
	public void flash(IEvaluationContext currentState,
43
			TriggerSequence triggerSequence) {
44
		Shell currentShell = (Shell) currentState
45
				.getVariable(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME);
46
		if (currentShell != null) {
47
			Menu menuBar = currentShell.getMenuBar();
48
			flashItemWithTrigger(menuBar, triggerSequence);
49
		}
50
	}
51
52
	/**
53
	 * @param menuBar
54
	 * @param triggerSequence
55
	 */
56
	private boolean flashItemWithTrigger(Menu menuBar,
57
			TriggerSequence triggerSequence) {
58
		MenuItem[] items = menuBar.getItems();
59
		for (int i = 0; i < items.length; i++) {
60
			MenuItem menuItem = items[i];
61
			String menuItemText = menuItem.getText();
62
			if (menuItemText.endsWith(triggerSequence.format())) {
63
				try {
64
					flash(menuItem);
65
				} catch (IllegalArgumentException e) {
66
					e.printStackTrace();
67
				} catch (IllegalAccessException e) {
68
					e.printStackTrace();
69
				}
70
				return true;
71
			}
72
			Menu childMenu = menuItem.getMenu();
73
			if (childMenu != null) {
74
				boolean childResult = flashItemWithTrigger(childMenu,
75
						triggerSequence);
76
				if (childResult)
77
					return true;
78
			}
79
		}
80
		return false;
81
	}
82
83
	/**
84
	 * Flash the provided menu item.
85
	 * @param menuItem the item to flash
86
	 * @throws IllegalAccessException thrown if the handle field of the Menu class could not be invoked.
87
	 * @throws IllegalArgumentException not thrown
88
	 */
89
	private void flash(MenuItem menuItem) throws IllegalArgumentException,
90
			IllegalAccessException {
91
92
		Menu menu = menuItem.getParent();
93
		while (menu.getParentMenu() != null
94
				&& menu.getParentMenu().getParentMenu() != null) {
95
			menu = menu.getParentMenu();
96
		}
97
98
		if (menu == null)
99
			return;
100
101
		final short menuId = OS.GetMenuID(handleField.getInt(menu));
102
		OS.HiliteMenu(menuId);
103
		try {
104
			Thread.sleep(125);
105
		} catch (InterruptedException e) {
106
		}
107
		OS.HiliteMenu((short) 0);
108
	}
109
}

Return to bug 246165