Eclipse RCP application key bindings conflicts with typing in textbox - java

I've assign W,A,S,D as hotkeys for zooming/scrolling through the key bindings extension point, and those are global hotkeys. This causes an issue that I can't type WASD in textbox. How should I fix this? I was thinking to disable the hotkey or do something in the textbox OnFocus event handler.

If you really think that W A S D are good key bindings and if you still think they make for good global key bindings (both I doubt), you can use key binding contexts to make the binding only available when outside editing controls.
Once you have defined an org.eclipse.ui.contexts extension, assign this context to the respective key bindings thought the contextId attribute.
Now these key bindings are only available if the specified context is active. The IContextService can be used to activate and deactivate the context.
Use a display filter to deactivate the context when entering an editing control like Text, Spinner, StyledText, etc. and to activate it when leaving such a control.
For example:
Listener filter = new Listener() {
IContextActivation activation;
#Override
public void handleEvent( Event event ) {
if( isEditingWidget( event.widget ) ) {
if( event.type = SWT.FocusIn ) {
contextService.deactivateContext( activation );
} else {
activation = contextService.activateContext( "context id" );
}
}
}
};
display.addFilter( SWT.FocusIn, filter );
display.addFilter( SWT.FocusOut, filter );

You have to change your Hotkeys. WASD are already mapped as single single pressed and as pressed in combination with shift. Use the normal arrow keys. It is not worth modifying every textbox just so you can use an unwisely chosen set of hotkeys

Related

How enable or disable correctly an Action

i have a little problem when i try to disable an Action of my Netbeans platform project. When the app starts, some Actions must be disabled, and i do that with this method:
CallableSystemAction.get(BuildProjectAction.class).setEnabled(FLAG);
It works, because the BuildProjectAction is disabled, but the corresponding items of the MenuBar and the Toolbar remains enabled until i click on one of it.
Only later that i have clicked on it, the comportament start to work correctly.
First question: Why?
If i want disable an Action, it's obvious that i want disable also the relative Icon in the Menu and in the Toolbar, so it must be automatic when i call Action.setEnabled(false).
It doesn't have sense that the Icons are not refreshed if i don't click on they.
Same problem if i try to use .getToolbarPresenter().setEnabled(false); and .getMenuPresenter().setEnabled(false);
For start the application with the icons disabled, I have tried to set the lazy attribute to FALSE and declare the image programmatically with the method setIcon(new ImageIcon(image)); that sets the same image for Menu and Toolbar.
And it works; there is only another problem: Menu and Toolbar have icons of different size (16x16 and 24x24).
It doesn't have sense that the if i set the icon with the #ActionRegistration(iconBase = "image.png") the correct icon is automatically selected, but if i use the method .setIcon(), it doesn't.
I have read some articles about Action, CookieAction, Lookup, but the only thing that i want is disable the graphic elements in the same moment when i disable the Action.
Second question: How i can do that?
This is an example of my Action.
#ActionID(
category = "Run",
id = "BuildProjectAction")
#ActionRegistration(
lazy = true,
iconBase = "images/icons/compile.png",
displayName = "#CTL_BuildProjectAction")
#ActionReferences({
#ActionReference(
path = "Menu/Run",
position = 3),
#ActionReference(path = "Toolbars/Run",
position = 3),
#ActionReference(
path = "Shortcuts",
name = "D-B")
})
#Messages("CTL_BuildProjectAction=Build Project")
public final class BuildProjectAction extends CallableSystemAction {
#Override
public void actionPerformed(ActionEvent e) {...}
#Override
public void performAction() {}
#Override
public String getName() {
return Bundle.CTL_BuildProjectAction();
}
#Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
Thanks
The easiest way to create an action that is disabled at startup is to use the platform’s New Action Wizard to create your action, and to create one that depends on a "context" -- this is, on finding a specific object in the global lookup. If no object is available in the lookup, as at startup, then the action will be disabled.
The menu and toolbar graphic elements are bundled together with your action via the annotations. This means that enabled/disabled state of your context-aware action will automatically affect the icons in the menu and toolbar as well.
This article by Geertjan Wielenga has a walkthrough on creating a context-aware action:
http://netbeans.dzone.com/how-to-make-context-sensitive-actions
When you want to enable your action, you will add the object on which the action depends into the global lookup, which will cause the action (and its graphic elements) to be enabled.
This entry in the platform’s Developer FAQ has some examples of how to add an object to the global context:
http://wiki.netbeans.org/DevFaqAddGlobalContext
If you need to create an action that depends on a more complex set of conditions there is some discussion, as well as a code sample illustrating how to do this, in this platform developer list thread:
http://forums.netbeans.org/ptopic55295.html
The grayed-out versions of the icons that are shown when your action is disabled are created automatically by the platform. You only have to provide the "normal" non-grayed-out images.
As for the icons of different sizes, it’s a matter of filename convention. If your annotation declares the icon with #ActionRegistration(iconBase = "image.png”), then you will provide a 16x16 image called “image.png” and a 24x24 version called “image24.png”. The platform will find and use the appropriate size in the menu and toolbar.

Eclipse 4 RCP Editor using SourceViewer Undo and Redo operations are not working

I'm creating an editor using 'SourceViewer'. Given below is the code snippet from my '#PostConstruct' method.
// viewer is my SourceViewer instance
viewer = new SourceViewer(parent,verticalRuler, styles);
IUndoManager undoManager = new TextViewerUndoManager(25);
undoManager.connect(viewer);
viewer.setUndoManager(undoManager);
Even though a default 'TextViewerUndoManager' associated with 'SourceViewer'. Ctrl+Z and Ctrl+Y is not working.
Another alternative that I tried is to override the 'IUndoManager getUndoManager(ISourceViewer sourceViewer)' of 'SourceViewerConfiguration' subclass and return a 'TextViewerUndoManager'. This approach also doesn't give the desired result.
Kindly let me know what I'm missing in the above approaches.
It is normally the SourceViewerConfiguration that provides the Undo manager, the SourceViewer expects this and will set up the manager from that. The defaults already set up TextViewerUndoManager.
In an e4 application you do not get any default key bindings, commands or handlers so you will have to set up all these to make use of the undo manager.
In your application model declare Commands for undo and redo.
Declare key bindings for Ctrl+Z and Ctrl+Y specifying your commands. You might want to put the key bindings in a Binding Table that is specific to text editors.
Declare Handlers for the undo and redo commands, the code for undo might look like:
public class UndoHandler
{
#Inject
private Adapter _adapter;
#Execute
public void execute(#Named(IServiceConstants.ACTIVE_PART) final MPart part)
{
final ITextOperationTarget opTarget = _adapter.adapt(part.getObject(), ITextOperationTarget.class);
opTarget.doOperation(ITextOperationTarget.UNDO);
}
#CanExecute
public boolean canExecute(#Named(IServiceConstants.ACTIVE_PART) final MPart part)
{
final ITextOperationTarget opTarget = _adapter.adapt(part.getObject(), ITextOperationTarget.class);
if (opTarget == null)
return false;
return opTarget.canDoOperation(ITextOperationTarget.UNDO);
}
}
Redo would be similar but using ITextOperationTarget.REDO.
The order of doing/registering things is important. Be sure to connect the undo manager AFTER setting the document to the SourceViewer instance because on connect() the document will be retrieved from the viewer by the undo manager and if it doesn't find a document it will not register anything and undoable() will always return false.

How can i disable a button when the model is not updated?

In my UI i have 2 text field and and 2 buttons .I am using jface data binding to bind the text field and i am doing the validation and depending on the validation success the model is updated other wise it will not.I want my button to respond accordingly .Like if my model is not updated than i want to disable my button.One more thing that i do anot want to do hard coding .so is there any way to that without hard coding.
In other way I want to bind a button to text field so that when the text field has some unwanted value than the button should be disabled .In the other way i am doing data binding on text field which will take care when the text field does not have proper value than it will not update its model.Then i want to disable the button when the value is not proper can i do that.Any pointer on this helps me a lot.
You can make use of below listener. Add listener to your Observable
org.eclipse.core.databinding.observable.value.IValueChangeListener
After some research, I found that I have to observe the enable/disable property of the button and bind it with the current emf databinding context. Detail of the function which I have used is given below:
void bindEnablementButtonToValidationStatus(Button button, EMFDataBindingContext ctx) {
IObservableValue buttonEnable = SWTObservables.observeEnabled(button);
IObservableValue validationStatus = new AggregateValidationStatus(
ctx.getValidationRealm(),
ctx.getBindings(),
AggregateValidationStatus.MAX_SEVERITY);
ctx.bindValue(buttonEnable, validationStatus,
new EMFUpdateValueStrategy(
UpdateValueStrategy.POLICY_NEVER),
new EMFUpdateValueStrategy().setConverter(
new Converter(IStatus.class, Boolean.TYPE) {
public Object convert(Object fromObject) {
return new Boolean(((IStatus)fromObject).isOK());
}
}));
}

Is it possible to use Enter as Tab without inheriting JTextField or mass-adding key listeners?

I've found several pages and SO answers about the enter-as-tab problem in Java, but all propose either overriding methods of JTextField or adding a key listener to every component.
But isn't there any other way? Can't I override something of the LookAndFeel or install some global policy?
After some documentation crawling I found a solution: It is possible to set the focus traversal keys on KeyboardFocusManager instead of a JComponent instance.
// 1. Get default keys
Set<AWTKeyStroke> ftk = new HashSet<AWTKeyStroke>(
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getDefaultFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
// 2. Add our key
ftk.add(KeyStroke.getKeyStroke("ENTER"));
// 3. Set new keys
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.setDefaultFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, ftk);
This adds the enter key to the list of keys which are used for forward traversal. (Backward traversal similar)
you can probably use http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html
to change the keyBinding for the enter key
or you can add focustravesal keys
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, your keys here);
The hammer - of setting the enter as focus traversal key for all component except those which register their own - is just fine if it's really required. The obvious drawback is that default bindings to the enter stop working, in particular
action/Listeners on textFields
default buttons
any other component type with a custom binding to enter
If those side-effects are problematic, there's the less intrusive alternative of tweaking the binding in the shared ancestor actionMap of the textFields.
// "early" in the app instantiate a textField
JTextField text = new JTextField();
ActionMap map = text.getActionMap();
// get a reference to the default binding
final Action notify = map.get(JTextField.notifyAction);
while (map.getParent() != null) {
// walk up the parent chain to reach the top-most shared ancestor
map = map.getParent();
}
// custom notify action
TextAction tab = new TextAction(JTextField.notifyAction) {
#Override
public void actionPerformed(ActionEvent e) {
// delegate to default if enabled
if (notify.isEnabled()) {
notify.actionPerformed(e);
}
// trigger a focus transfer
getTextComponent(e).transferFocus();
}
};
// replace default with augmented custom action
map.put(JTextField.notifyAction, tab);
After replacing the default, all textFields will use the custom action. The one beware is that the replacement has to be repeated whenever the LAF is changed.

SWT, Maintain default tab ordering when adding Key Listner

I've been creating a custom TabFolder extension that adds a key listener to allow quick tab switching using an ALT + # hotkey.
By adding the KeyAdapter to my TabFolder, the event handler works properly only when you have a tab header selected (in which case the ALT + ARROW_LEFT/ARROW_RIGHT also work.). I need this hot key to be active when any Widget with-in the TabFolder is active; however, it shouldn't be active if the selection is in a different tab folder or widget outside of a tab folder.
In an attempt to solve this, I wrote a simple recursive function to apply the key listener to all of the children of the tab folder:
public void applyQuickSwitchKeyBindings() {
removeKeyListener(ka);
addKeyListener(ka);
for(Control c: getChildren())
applyQuickSwitchKeyBindingsToChildren(c);
}
private void applyQuickSwitchKeyBindingsToChildren(Control c) {
if(c==null) return;
if(c instanceof Composite) {
Control[] controls = ((Composite)c).getChildren();
for(Control c2: controls)
applyQuickSwitchKeyBindingsToChildren(c2);
if(controls.length < 1) {
c.removeKeyListener(ka);
c.addKeyListener(ka);
}
}
}
Then i call the applyQuickSwitchKeyBindings() after I add the controls to each TabItem in the tab group.
The good news was that the quick switch hot key (ALT + #) worked great!
The bad news was that the original TAB ordering based on z-index is now gone. When you hit the SWT.TAB key you lose focus on your current text box and don't gain focus on anything else...
Questions:
1.) Can each control only have one KeyListener?
2.) Why is the original TAB traversal not working anymore?
Thanks in advance!
to 1) I'm pretty sure that more than one KeyListener is allowed.
to 2) I'm not sure, that depends on what you're doing in your KeyAdapter. Maybe you can post that too?
I just the tab order is broken somehow, you can reset ( or change ) it with a call to setTabList( Control[] ).
setTablList( new Control[] {
control1,
control2,
control3,
....
} );
So after more time learning and developing with SWT i've discovered my problem. When you add a listener it is applied to the widget/control you call the addXXXListener function on. So if that control is not active the listeners will not be fired.
The solution seems to be SWT's global Filter mechanism which allows you to add global application(Display) scope listeners.
Display.getCurrent().addFilter(SWT.keyPress, new KeyPressListener());
Pardon the incorrectness of this line, but if you google it you'll see what i mean.
I have also read to use this sparingly.

Categories